[SDTEST-3774] Add TelemetryMetricExporter bridging OTel metrics to TelemetryExporter#268
Merged
ypopovych merged 10 commits intoJun 2, 2026
Merged
Conversation
…lemetryExporter Implement MetricExporter that converts OTel MetricData to TelemetryMetric and forwards to TelemetryExporter for batching and upload, following the same pattern as TelemetryLogExporter. - Gauge/Sum types map to gauge or count series - Histogram/ExponentialHistogram/Summary emit .count and .sum sub-series - Attributes are converted to sorted tag arrays - getAggregationTemporality returns cumulative for all instrument types Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Covers message extraction (body, message attribute, eventName, default), severity→level mapping (error/fatal→ERROR, warn→WARN, others→DEBUG), stack trace extraction, attribute→tag conversion, timestamp fallback, multiple records, and forceFlush. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
An empty flush (no pending batches) is a success — there was nothing to upload, so the operation trivially succeeded. Initialising result=true instead of false makes flush() consistent with that expectation and allows forceFlush()/flush() callers to distinguish "nothing to do" from a real upload failure. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Implements the distributions payload type per the telemetry spec: - TelemetryDistribution with its own Namespace (tracers/profilers/rum/appsec) and Series carrying raw sample values ([Double]) rather than [timestamp,value] pairs - Wired into TelemetryRequestType enum, TelemetryMessageBatch decoder, and TelemetryApi - sendDistributions() added to TelemetryApi protocol and TelemetryApiService - TelemetryExporterTests extended to cover distributions round-trip and mixed-type batches Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Histogram types carry sampled data, so they map naturally to the distributions request type rather than the generate-metrics count/sum pair. Conversion strategy: - Histogram (explicit boundaries): reconstruct approximate sample values using bucket midpoints; edge buckets use min/max when available. - ExponentialHistogram: geometric midpoint of each exponential bucket (base^(offset+i+0.5) where base = 2^(2^-scale)). - Summary: kept as generate-metrics count+sum (already pre-aggregated). TelemetryMetricExporter.export(metrics:) now emits a TelemetryMetric payload for scalar types and a separate TelemetryDistribution payload for histogram types when both are present in the same batch. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
When a histogram's underflow (first) bucket has no recorded min, use the first explicit boundary as the representative value instead of 0. A value in the underflow bucket is <= boundaries[0], so the boundary itself is a closer approximation than 0 — especially for histograms whose boundaries don't start near zero. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
The exporter previously declared cumulative temporality for all instruments. Under cumulative, OTel emits running totals since process start on every collection, which is wrong for the DD targets: - DD `count` sums submitted values per interval, so feeding it cumulative snapshots inflates the count. - `distributions` expect the interval's raw samples, so reconstructing from cumulative bucket counts re-emits the entire sample set each cycle. Mirror OTel's deltaPreferred() selector: up/down counters (mapped to DD gauge) stay cumulative so the current running total is reported; counters, histograms, and gauges request delta. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Read the telemetry namespace from each metric's Resource (attribute key "dd.telemetry.namespace") and set it as the per-series namespace override. This lets a meter provider route its metrics to a specific namespace without a dedicated exporter instance. When the attribute is absent or its value isn't valid for the target payload (e.g. a generate-metrics-only namespace on a distribution), the override is omitted and the exporter's configured payload-level namespace applies. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Replace the ad-hoc TelemetryMetricResourceKeys constant and MetricConversion namespace helpers with a typed `Resource.telemetryNamespace` getter/setter in OpenTelemetry+Extensions, matching the existing applicationName/environment/etc. accessors. The converter now reads metric.resource.telemetryNamespace and maps it to the payload-specific Namespace enum via init(rawValue:). Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Split the single string-based telemetryNamespace into two typed accessors, one per payload type with its own resource key: - telemetryMetricNamespace: TelemetryMetric.Namespace? (key "dd.telemetry.metric.namespace") - telemetryDistributionNamespace: TelemetryDistribution.Namespace? (key "dd.telemetry.distribution.namespace") Getters/setters work directly with the enum types (no String at the call site), and the separate keys let metrics and distributions carry independent namespaces — necessary since the two enums accept different value sets. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
anmarchenko
approved these changes
Jun 2, 2026
ypopovych
deleted the
yehor.popovych/sdtest-3774-telemetry-metric-exporter
branch
June 2, 2026 16:07
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Implements SDTEST-3774: a
MetricExporterbridge that converts OTel metrics into our telemetry format and forwards them toTelemetryExporterfor batching/upload — mirroringTelemetryLogExporter.Changes
TelemetryMetricExporter— implements OTel'sMetricExporter. Converts[MetricData]and forwards toTelemetryExporter.gauge; monotonic Sum →count; non-monotonic Sum →gauge; Summary →{name}.count+{name}.sum.distributions: explicit-boundary histograms reconstruct approximate samples from bucket midpoints (edge buckets use min/max, falling back to the boundary edge); exponential histograms use the geometric bucket midpoint.deltaPreferred(): counters/histograms request.delta(DDcount/distributionsare per-interval); up/down counters stay.cumulative(mapped to gauge).TelemetryDistribution— new payload type for thedistributionsrequest type (raw sample points, its own namespace set), wired intoTelemetryRequestType,TelemetryMessageBatch, andTelemetryApi.sendDistributions.Resource— typed accessorsResource.telemetryMetricNamespace/telemetryDistributionNamespace(separate keys, enum-typed get/set) set the per-series namespace override.DataUploadWorker.flush()returnedfalseon an empty queue; an empty flush is a success.Tests
TelemetryMetricExporterTests— gauge/sum/summary/histogram/exponential conversions, sample reconstruction, namespace-from-resource, temporality.TelemetryLogExporterTests— message extraction, severity mapping, stack trace, tags, timestamps, flush.TelemetryExporterTests— extended for thedistributionsround-trip and mixed-type batches.🤖 Generated with Claude Code