Skip to content

feat(opentelemetry sink): add native metric to OTLP conversion#24897

Open
szibis wants to merge 17 commits intovectordotdev:masterfrom
szibis:feat/otlp-native-metrics-conversion
Open

feat(opentelemetry sink): add native metric to OTLP conversion#24897
szibis wants to merge 17 commits intovectordotdev:masterfrom
szibis:feat/otlp-native-metrics-conversion

Conversation

@szibis
Copy link
Contributor

@szibis szibis commented Mar 11, 2026

Summary

Adds encoding support for converting native Vector metrics to OTLP protobuf format (ExportMetricsServiceRequest), enabling Vector metrics from any source to be sent through OTLP sinks without pre-formatted OTLP structure.

This is the metrics counterpart to log/trace native conversion in #24621.

Related Issues

User Impact

Before this PR, sending native Vector metrics to an OTLP collector required either:

  1. use_otlp_decoding: true on the source (passthrough only, no transforms possible)
  2. Complex 50+ line VRL transforms to manually build OTLP protobuf structure (error-prone, caused Metrics Opentelemetry sink is failing to push metrics with Bad Request error #23365)

After this PR:

sources:
  host_metrics:
    type: host_metrics
sinks:
  otel_out:
    type: opentelemetry
    inputs: ["host_metrics"]
    encoding:
      codec: otlp  # Native metrics auto-converted

Conversion Architecture

graph LR
    subgraph "Vector Native Metrics"
        C[Counter]
        G[Gauge]
        H[AggregatedHistogram]
        S[AggregatedSummary]
        D[Distribution]
        Set[Set]
    end
    subgraph "OTLP Protobuf"
        Sum[Sum<br/>monotonic]
        OG[Gauge]
        OH[Histogram]
        OS[Summary]
    end
    C -->|"Incremental→Delta<br/>Absolute→Cumulative"| Sum
    G --> OG
    H -->|"Incremental→Delta<br/>Absolute→Cumulative"| OH
    S --> OS
    D -->|"samples→buckets"| OH
    Set -->|"cardinality count"| OG
Loading

Type Mapping

Vector MetricValue OTLP Data Type Temporality Logic
Counter Sum (monotonic) Incremental → Delta, Absolute → Cumulative
Gauge Gauge
AggregatedHistogram Histogram Incremental → Delta, Absolute → Cumulative
AggregatedSummary Summary
Distribution Histogram samples converted to bucket boundaries
Set Gauge emits unique value count
Sketch (dropped with warning) not directly representable in OTLP

Tag Decomposition

Reverses the decode-path flattening from build_metric_tags:

Tag Pattern OTLP Destination
resource.* Resource.attributes[] (prefix stripped)
scope.name InstrumentationScope.name
scope.version InstrumentationScope.version
scope.* (other) InstrumentationScope.attributes[] (prefix stripped)
everything else DataPoint.attributes[]

Safety

  • Zero panics, zero unsafe blocks in encode path
  • All numeric casts use From/TryFrom (no bare as casts for narrowing)
  • Non-finite (NaN/Infinity) distribution samples are filtered before accumulation
  • Sketch metrics produce empty data (no silent corruption with zero gauges)
  • internal_log_rate_limit used for rate-limited warnings (Vector convention)

Test Plan

  • 47 unit tests covering all metric type conversions
  • Roundtrip tests (encode → decode → verify fidelity) for Counter, Gauge, Histogram, Summary
  • Tag decomposition: resource, scope, data point attributes, mixed, prefix collision
  • Edge cases: zero values, negative values, empty buckets/quantiles, large values, special chars
  • NaN/Infinity handling: distribution samples skipped, gauge/counter passthrough, all-NaN distribution
  • Sketch metric dropped (no data), zero-rate samples, scope custom attributes
  • Non-finite histogram/summary sum passthrough verification
  • cargo clippy clean, cargo fmt clean
  • CI passes

Add encoding support for converting native Vector metrics to OTLP
protobuf format (ExportMetricsServiceRequest). This enables Vector
metrics from any source to be sent through OTLP sinks without
requiring pre-formatted OTLP structure.

Metric type mapping:
- Counter → Sum (monotonic, Delta/Cumulative per MetricKind)
- Gauge → Gauge
- AggregatedHistogram → Histogram
- AggregatedSummary → Summary
- Distribution → Histogram (samples → buckets)
- Set → Gauge (cardinality count)
- Sketch → Gauge with warning (unsupported)

Tag decomposition reverses the decode-path flattening:
- resource.* tags → resource attributes
- scope.name/version → InstrumentationScope
- scope.* tags → scope attributes
- All other tags → data point attributes

Includes 36 tests covering type conversions, tag decomposition,
roundtrip fidelity, and edge cases.
@szibis szibis requested a review from a team as a code owner March 11, 2026 16:24
@szibis szibis changed the title feat(opentelemetry): native metric → OTLP conversion feat(codecs): native metric to OTLP conversion Mar 11, 2026
@szibis szibis changed the title feat(codecs): native metric to OTLP conversion feat(opentelemetry sink): add native metric to OTLP conversion Mar 11, 2026
Update opentelemetry sink CUE requirements to reflect native metric
auto-conversion support. Add comprehensive otlp-native-conversion
docs with metric type mapping, tag decomposition reference, and
use case examples. Add kvlist to spelling expect list.
@szibis szibis requested a review from a team as a code owner March 11, 2026 16:44
@github-actions github-actions bot added domain: ci Anything related to Vector's CI environment domain: external docs Anything related to Vector's external, public documentation labels Mar 11, 2026
This feature targets the 0.55.0 release, not 0.54.0.
@buraizu
Copy link
Contributor

buraizu commented Mar 11, 2026

Created DOCS-13660 for documentation team review

@buraizu buraizu removed their assignment Mar 11, 2026
szibis added 8 commits March 11, 2026 23:24
… encode

Apply review feedback patterns from PR vectordotdev#24621:
- Replace `as u64` with `u64::try_from().ok()` for timestamp conversion
- Replace `as u64`/`as f64` with `u64::from()`/`f64::from()` for sample.rate
- Remove unwrap() in Distribution bucket overflow guard, use
  saturating index clamping instead
…ogram conversion

NaN and Infinity sample values were not excluded from the accumulation
loop in Distribution-to-Histogram conversion, even though they were
already filtered from the boundary list. This caused NaN to poison
the total_sum and misroute samples via binary_search_by. Non-finite
samples are now skipped in the accumulation loop, matching the
boundary filter.
Sketch metrics were converted to an empty gauge (value 0.0), causing
silent data corruption downstream. Now Sketch metrics produce a Metric
with no data field, which OTLP receivers will ignore. Also fixes the
rate-limit key to use internal_log_rate_limit (Vector convention).
Add clippy::cast_precision_loss annotation on values.len() as f64 in
Set conversion (usize→f64 is lossy for very large sets but acceptable).
Fix test to use u64::try_from instead of bare 'as u64' cast, matching
the production code pattern.
Add tests covering NaN/Infinity distribution samples, non-finite gauge
and counter values, zero-rate samples, Sketch metric dropping, tag
prefix collision routing, scope custom attributes, and non-finite
histogram/summary sums.
Sketch metrics are now dropped with a warning instead of emitting
an empty gauge, matching the code change.
@szibis
Copy link
Contributor Author

szibis commented Mar 12, 2026

Companion decode-side fix: #24905 adds decode for missing scope, schema_url, and resource.dropped_attributes_count fields across logs, traces, and metrics. This ensures the fields that this PR's encode path handles are actually populated by the decode side.

… tags

Update decompose_metric_tags to handle 4 special tags as proto-level
structural fields rather than generic attributes:
- resource.dropped_attributes_count → Resource.dropped_attributes_count
- resource.schema_url → ResourceMetrics.schema_url
- scope.dropped_attributes_count → InstrumentationScope.dropped_attributes_count
- scope.schema_url → ScopeMetrics.schema_url

This ensures round-trip fidelity with fix/otlp-decode-missing-fields
(vectordotdev#24905) once merged, while remaining backward-compatible (graceful
defaults of 0 / empty string) before that PR merges.
szibis and others added 4 commits March 12, 2026 18:01
Co-authored-by: Pavlos Rontidis <pavlos.rontidis@gmail.com>
…nversion

- Use DataType::all_bits() instead of manual OR (reviewer nit)
- Split OtlpSerializer doc into "Pre-formatted OTLP events" and
  "Native Vector events" sections for clarity
- Sketch metrics now truly dropped (return None from
  native_metric_to_otlp_request instead of including empty metric)
- Document resource.*/scope.* tag prefix reservation for OTLP mapping
- Add sample config to changelog fragment
- Remove orphaned docs/examples/otlp-native-conversion.md (content
  folded into encoder docstring)
Add explicit user-facing documentation about resource.*/scope.* tag
prefix reservation in OTLP encoding:

- CUE sink docs: new "Metric tag prefix conventions" section
- Changelog: explicitly notes prefix reservation and behavior for
  non-OTLP sources using these prefixes coincidentally

Addresses review feedback requesting explicit documentation for the
implicit prefix reservation behavior.
@szibis szibis requested a review from pront March 12, 2026 17:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain: ci Anything related to Vector's CI environment domain: external docs Anything related to Vector's external, public documentation editorial review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Source Host Metrics in OTEL format Support sending OpenTelemetry metrics

3 participants