Skip to content

Conversation

SomilJain0112
Copy link
Contributor

Which problem is this PR solving?

#7148

Description of the changes

  • Replace ch-go proto.Input with native Go types
  • Write all trace data (attributes, events, links)
  • Update SQL INSERT to include all 36 fields

How was this change tested?

Tested locally

Checklist

@SomilJain0112 SomilJain0112 requested a review from a team as a code owner October 11, 2025 17:42
@SomilJain0112 SomilJain0112 requested a review from jkowall October 11, 2025 17:42
@dosubot dosubot bot added area/storage go Pull requests that update go code v2 labels Oct 11, 2025
Comment on lines 59 to 63
data, err := json.Marshal(convertValueToInterface(v))
if err == nil {
group.StrKeys = append(group.StrKeys, k)
group.StrValues = append(group.StrValues, string(data))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JSON marshaling error is silently ignored, causing the attribute to be dropped when serialization fails. Consider either logging the error or implementing a fallback serialization method to ensure all attribute data is preserved. This is particularly important for observability data where losing attributes could impact troubleshooting capabilities.

Suggested change
data, err := json.Marshal(convertValueToInterface(v))
if err == nil {
group.StrKeys = append(group.StrKeys, k)
group.StrValues = append(group.StrValues, string(data))
}
data, err := json.Marshal(convertValueToInterface(v))
if err != nil {
// Log the error
log.Printf("Failed to marshal attribute %s: %v, using fallback serialization", k, err)
// Fallback: use string representation
fallbackValue := fmt.Sprintf("%v", v)
data, _ = json.Marshal(fallbackValue)
}
group.StrKeys = append(group.StrKeys, k)
group.StrValues = append(group.StrValues, string(data))

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Copy link

codecov bot commented Oct 11, 2025

Codecov Report

❌ Patch coverage is 95.93023% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.44%. Comparing base (5f9ea63) to head (2c4e8d6).

Files with missing lines Patch % Lines
...age/v2/clickhouse/tracestore/dbmodel/to_dbmodel.go 92.30% 6 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7552      +/-   ##
==========================================
- Coverage   96.51%   96.44%   -0.07%     
==========================================
  Files         385      385              
  Lines       23364    23116     -248     
==========================================
- Hits        22549    22294     -255     
- Misses        627      633       +6     
- Partials      188      189       +1     
Flag Coverage Δ
badger_v1 9.02% <ø> (ø)
badger_v2 1.61% <0.00%> (+0.03%) ⬆️
cassandra-4.x-v1-manual 11.67% <ø> (ø)
cassandra-4.x-v2-auto 1.60% <0.00%> (+0.03%) ⬆️
cassandra-4.x-v2-manual 1.60% <0.00%> (+0.03%) ⬆️
cassandra-5.x-v1-manual 11.67% <ø> (ø)
cassandra-5.x-v2-auto 1.60% <0.00%> (+0.03%) ⬆️
cassandra-5.x-v2-manual 1.60% <0.00%> (+0.03%) ⬆️
clickhouse ?
elasticsearch-6.x-v1 16.57% <ø> (ø)
elasticsearch-7.x-v1 16.61% <ø> (ø)
elasticsearch-8.x-v1 16.75% <ø> (ø)
elasticsearch-8.x-v2 1.61% <0.00%> (+0.03%) ⬆️
elasticsearch-9.x-v2 1.61% <0.00%> (+0.03%) ⬆️
grpc_v1 10.22% <ø> (ø)
grpc_v2 1.61% <0.00%> (+0.03%) ⬆️
kafka-3.x-v1 9.66% <ø> (ø)
kafka-3.x-v2 1.61% <0.00%> (+0.03%) ⬆️
memory_v2 1.61% <0.00%> (+0.03%) ⬆️
opensearch-1.x-v1 16.66% <ø> (ø)
opensearch-2.x-v1 16.66% <ø> (ø)
opensearch-2.x-v2 1.61% <0.00%> (+0.03%) ⬆️
opensearch-3.x-v2 1.61% <0.00%> (+0.03%) ⬆️
query 1.61% <0.00%> (+0.03%) ⬆️
tailsampling-processor 0.44% <0.00%> (+<0.01%) ⬆️
unittests 95.43% <95.93%> (-0.08%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

github-actions bot commented Oct 11, 2025

Metrics Comparison Summary

Total changes across all snapshots: 53

Detailed changes per snapshot

summary_metrics_snapshot_cassandra

📊 Metrics Diff Summary

Total Changes: 53

  • 🆕 Added: 53 metrics
  • ❌ Removed: 0 metrics
  • 🔄 Modified: 0 metrics

🆕 Added Metrics

  • http_server_request_body_size_bytes (18 variants)
View diff sample
+http_server_request_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="+Inf",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_request_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="0",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_request_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="10",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_request_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="100",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_request_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="1000",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_request_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="10000",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_request_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="25",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
...
- `http_server_request_duration_seconds` (17 variants)
View diff sample
+http_server_request_duration_seconds{http_request_method="GET",http_response_status_code="503",le="+Inf",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_request_duration_seconds{http_request_method="GET",http_response_status_code="503",le="0.005",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_request_duration_seconds{http_request_method="GET",http_response_status_code="503",le="0.01",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_request_duration_seconds{http_request_method="GET",http_response_status_code="503",le="0.025",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_request_duration_seconds{http_request_method="GET",http_response_status_code="503",le="0.05",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_request_duration_seconds{http_request_method="GET",http_response_status_code="503",le="0.075",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_request_duration_seconds{http_request_method="GET",http_response_status_code="503",le="0.1",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
...
- `http_server_response_body_size_bytes` (18 variants)
View diff sample
+http_server_response_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="+Inf",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_response_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="0",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_response_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="10",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_response_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="100",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_response_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="1000",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_response_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="10000",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
+http_server_response_body_size_bytes{http_request_method="GET",http_response_status_code="503",le="25",network_protocol_name="http",network_protocol_version="1.1",otel_scope_name="go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",otel_scope_schema_url="",otel_scope_version="0.62.0",server_address="localhost",server_port="13133",url_scheme="http"}
...

➡️ View full metrics file

Comment on lines 57 to 65
case ValueTypeSlice, ValueTypeMap:
// For complex types, serialize to JSON string
data, err := json.Marshal(convertValueToInterface(v))
if err != nil {
// Fallback: use string representation if JSON marshaling fails
data, _ = json.Marshal(v.AsString())
}
group.StrKeys = append(group.StrKeys, k)
group.StrValues = append(group.StrValues, string(data))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There appears to be a schema mismatch between how complex types are stored and how they're referenced in the SQL query. The code is serializing ValueTypeSlice and ValueTypeMap to JSON strings and adding them to StrKeys and StrValues, but the SQL query in queries.go expects these values in complex_attributes.key and complex_attributes.value columns. This inconsistency will likely cause data to be inserted into incorrect columns or query failures when the column count doesn't match parameter count.

Consider either:

  1. Adding the serialized complex types to BytesKeys and BytesValues (which appear to be used for complex attributes based on the SQL schema), or
  2. Updating the SQL query to match the current implementation where complex types are stored in string columns
Suggested change
case ValueTypeSlice, ValueTypeMap:
// For complex types, serialize to JSON string
data, err := json.Marshal(convertValueToInterface(v))
if err != nil {
// Fallback: use string representation if JSON marshaling fails
data, _ = json.Marshal(v.AsString())
}
group.StrKeys = append(group.StrKeys, k)
group.StrValues = append(group.StrValues, string(data))
case ValueTypeSlice, ValueTypeMap:
// For complex types, serialize to JSON string
data, err := json.Marshal(convertValueToInterface(v))
if err != nil {
// Fallback: use string representation if JSON marshaling fails
data, _ = json.Marshal(v.AsString())
}
group.BytesKeys = append(group.BytesKeys, k)
group.BytesValues = append(group.BytesValues, data)

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Comment on lines +78 to +83
var linkTraceIDs, linkSpanIDs, linkTraceStates []string
for _, link := range span.Links().All() {
linkTraceIDs = append(linkTraceIDs, link.TraceID().String())
linkSpanIDs = append(linkSpanIDs, link.SpanID().String())
linkTraceStates = append(linkTraceStates, link.TraceState().AsRaw())
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code extracts link metadata (trace IDs, span IDs, trace states) but doesn't capture link attributes, which appears inconsistent with how event attributes are handled. This creates a potential data loss situation where link context is only partially preserved. Consider implementing link attribute extraction using a similar pattern to the event attributes code above:

// Extract link attributes
var linkBoolKeys, linkDoubleKeys, linkIntKeys, linkStrKeys, linkComplexKeys [][]string
var linkBoolVals [][]bool
var linkDoubleVals [][]float64
var linkIntVals [][]int64
var linkStrVals, linkComplexVals [][]string

for _, link := range span.Links().All() {
    // existing code for IDs and states
    
    linkAttrs := dbmodel.ExtractAttributes(link.Attributes())
    // populate attribute arrays similar to events
}

This would ensure complete data preservation across all span components.

Suggested change
var linkTraceIDs, linkSpanIDs, linkTraceStates []string
for _, link := range span.Links().All() {
linkTraceIDs = append(linkTraceIDs, link.TraceID().String())
linkSpanIDs = append(linkSpanIDs, link.SpanID().String())
linkTraceStates = append(linkTraceStates, link.TraceState().AsRaw())
}
var linkTraceIDs, linkSpanIDs, linkTraceStates []string
var linkBoolKeys, linkDoubleKeys, linkIntKeys, linkStrKeys, linkComplexKeys [][]string
var linkBoolVals [][]bool
var linkDoubleVals [][]float64
var linkIntVals [][]int64
var linkStrVals, linkComplexVals [][]string
for _, link := range span.Links().All() {
linkTraceIDs = append(linkTraceIDs, link.TraceID().String())
linkSpanIDs = append(linkSpanIDs, link.SpanID().String())
linkTraceStates = append(linkTraceStates, link.TraceState().AsRaw())
linkAttrs := dbmodel.ExtractAttributes(link.Attributes())
linkBoolKeys = append(linkBoolKeys, linkAttrs.BoolKeys)
linkBoolVals = append(linkBoolVals, linkAttrs.BoolValues)
linkDoubleKeys = append(linkDoubleKeys, linkAttrs.DoubleKeys)
linkDoubleVals = append(linkDoubleVals, linkAttrs.DoubleValues)
linkIntKeys = append(linkIntKeys, linkAttrs.IntKeys)
linkIntVals = append(linkIntVals, linkAttrs.IntValues)
linkStrKeys = append(linkStrKeys, linkAttrs.StringKeys)
linkStrVals = append(linkStrVals, linkAttrs.StringValues)
linkComplexKeys = append(linkComplexKeys, linkAttrs.ComplexKeys)
linkComplexVals = append(linkComplexVals, linkAttrs.ComplexValues)
}

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Signed-off-by: Somil Jain <[email protected]>
@SomilJain0112 SomilJain0112 force-pushed the feat/Migrate-ch-go-library-to-clickhouse branch from fce4725 to 1b85e41 Compare October 11, 2025 19:32
@yurishkuro
Copy link
Member

@mahadzaryab1 do we need this?

E2E tests were failing because batch.Send() wasn't properly committing
data. Adding explicit Flush() before Send() ensures all pending data
is flushed to ClickHouse before the batch is sent.

Changes:
- writer.go: Add batch.Flush() before batch.Send()
- driver_test.go: Add Flush() method to testBatch mock

This should fix the E2E test failures where 0 spans were being
retrieved after writing.

Signed-off-by: Somil Jain <[email protected]>
Resolved merge conflicts in:
- internal/storage/v2/clickhouse/sql/queries.go
  * Removed duplicate attribute fields in INSERT statement
  * Kept 38 placeholders for full schema implementation

- internal/storage/v2/clickhouse/tracestore/writer.go
  * Kept our full implementation with dbmodel.ExtractAttributes
  * Preserved attribute extraction for events and links
  * Added missing jptrace import

- internal/storage/v2/clickhouse/tracestore/writer_test.go
  * Kept 38-field test assertions
  * Service name at index 35, scope at 36, version at 37

All unit tests passing after merge.

Signed-off-by: Somil Jain <[email protected]>
@SomilJain0112 SomilJain0112 force-pushed the feat/Migrate-ch-go-library-to-clickhouse branch from 8a4cae8 to 45c27f8 Compare October 12, 2025 11:44
@SomilJain0112
Copy link
Contributor Author

Hii @mahadzaryab1 , Please let me know if this issue still needs to be resolved as I am working on it.
Thanks!

Signed-off-by: Somil Jain <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/storage go Pull requests that update go code v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants