fix(otel): preserve all exemplars per data point (#1662)#1720
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughOTEL metrics now support configurable exemplar storage: nested arrays preserve all exemplars by default, while ChangesOTEL exemplar handling
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant OTELClient
participant flatten_otel_metrics
participant process_resource_metrics
participant flatten_metrics_record
participant insert_exemplars
OTELClient->>flatten_otel_metrics: OTEL metrics payload
flatten_otel_metrics->>process_resource_metrics: configured exemplar mode
process_resource_metrics->>flatten_metrics_record: metric record and mode
flatten_metrics_record->>insert_exemplars: exemplar list and mode
insert_exemplars-->>flatten_metrics_record: nested array or flattened columns
flatten_metrics_record-->>process_resource_metrics: flattened records
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Note on the failing |
|
@prabhaks thank you for raising the lint PR, i have verified and merged it, you can rebase this PR now |
42b3bde to
1e9eb32
Compare
Done, thank you for reviewing and merging my other PR! |
1e9eb32 to
bf49759
Compare
|
@nikhilsinhaparseable @parmesant please take a look at this PR whenever you get a chance! |
bf49759 to
0134035
Compare
|
@parmesant @nikhilsinhaparseable Any thoughts on this fix? |
|
Hey @prabhaks |
0134035 to
9685f44
Compare
insert_exemplars wrote every exemplar of a data point to the same static columns (exemplar_time_unix_nano, exemplar_span_id, exemplar_trace_id, exemplar_value), so each exemplar overwrote the previous one and only the last survived. This affected Sum, Histogram, ExponentialHistogram (and Gauge) metric types. Serialize all exemplars into a single nested `exemplars` array column (array of objects), the OTel-faithful representation recommended in the issue. Each element carries exemplar_time_unix_nano, exemplar_span_id, exemplar_trace_id, exemplar_value, and any filtered attributes. Add the P_OTEL_FLATTEN_EXEMPLARS flag (default false) to opt back into the legacy flat columns for backward compatibility. Also stops exemplar attributes from leaking into the physical-series hash: `exemplars` is added to OTEL_METRICS_KNOWN_FIELD_LIST so exemplar contents no longer fragment series identity.
9685f44 to
a8bbdbc
Compare
|
@prabhaks the PR looks good but there is a doubt that we have-
|
Hi @parmesant - I am on vacation till July 22nd. Will get back to you after that! |
|
Have a great vacation! |
Exemplar values were emitted as JSON integers for AsInt exemplars and floats for AsDouble. After the exemplars array is flattened into parallel List columns during ingest, exemplars_exemplar_value then infers as List<Int64> in some batches and List<Float64> in others. Parseable's schema-conflict handling routes the mismatched batch to a separate exemplars_exemplar_value_list column and leaves the original empty. Normalize both int and double exemplar values to f64 so the column is always List<Float64>: one clean column, no empty sibling. Addresses review feedback on parseablehq#1720.
|
Good catch, and no, that empty column is not intended. Root cause: exemplar values come through as an integer for I reproduced it with a small test: an int-typed exemplar batch followed by a double-typed one yields exactly Fix (just pushed): normalize both int and double exemplar values to One heads up for re-testing: the earlier run already created the empty For context on the overall shape: the exemplars array flattens into parallel per-field list columns ( |
|
@parmesant Can you please test against a fresh stream! |
|
Sure |
What
Fixes #1662.
insert_exemplarsinsrc/otel/metrics.rswrote every exemplar of a data point to the same static columns (exemplar_time_unix_nano,exemplar_span_id,exemplar_trace_id,exemplar_value). Since the keys were shared, each exemplar overwrote the previous one and only the last survived. This affected Sum, Histogram and ExponentialHistogram (and Gauge, which shares the sameNumberDataPointpath).Approach
Following the recommended option 1 in the issue, all exemplars for a data point are now serialized into a single nested
exemplarsarray column. Each element is an object withexemplar_time_unix_nano,exemplar_span_id,exemplar_trace_id,exemplar_valueand any filtered attributes. This matches the OTel data model (exemplars are a repeated field per data point) and keeps the schema stable regardless of exemplar count.Backward compatibility
Added a
P_OTEL_FLATTEN_EXEMPLARSflag (defaultfalse). When set totruethe previous flatexemplar_*columns are emitted (last exemplar wins, same as before) for anyone already querying those columns. Per the discussion on the issue, the default is the new array behavior.Bonus fix
Previously exemplar attributes were written straight into the data point map, so they leaked into
compute_series_hashand fragmented physical-series identity.exemplarsis now part ofOTEL_METRICS_KNOWN_FIELD_LIST, so exemplar contents no longer affect the series hash.Query validation (PoC)
Before settling on the schema I ran a PoC against the same library versions used here (datafusion 53, arrow/arrow-json 58) to confirm the query layer handles the array-of-objects column. arrow-json infers it as
List<Struct<...>>, and DataFusion handles reading the column,array_length,unnest, struct field access, and filtering on nested fields. Details are in the issue thread.Testing
cargo test: 311 passed, 0 failed.Flag reference
P_OTEL_FLATTEN_EXEMPLARSenv var /--otel-flatten-exemplarsflag, defaultfalse(new nestedexemplarsarray). Set totruefor the legacy flatexemplar_*columns.Summary by CodeRabbit
--otel-flatten-exemplars/P_OTEL_FLATTEN_EXEMPLARSto control how OTEL metric exemplars are represented when flattening.exemplarsstructure; enabling uses legacy flatexemplar_*fields (“last wins”).