Skip to content

Commit ffa7d74

Browse files
committed
* Renamed ResourceMetric->ResourceMetricData and moved to
MetricReader. * Renamed ResourceMetricRef->ResourceMetric and made that iteration would borrow an item, which will allow improving underlying metric collection without any allocations in the future * Updated CHANGELOG.md
1 parent 5a24c63 commit ffa7d74

File tree

18 files changed

+208
-181
lines changed

18 files changed

+208
-181
lines changed

opentelemetry-otlp/src/exporter/http/metrics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use crate::metric::MetricsClient;
44
use http::{header::CONTENT_TYPE, Method};
55
use opentelemetry::otel_debug;
66
use opentelemetry_sdk::error::{OTelSdkError, OTelSdkResult};
7-
use opentelemetry_sdk::metrics::exporter::ResourceMetricsRef;
7+
use opentelemetry_sdk::metrics::exporter::ResourceMetrics;
88

99
use super::OtlpHttpClient;
1010

1111
impl MetricsClient for OtlpHttpClient {
12-
async fn export(&self, metrics: ResourceMetricsRef<'_>) -> OTelSdkResult {
12+
async fn export(&self, metrics: ResourceMetrics<'_>) -> OTelSdkResult {
1313
let client = self
1414
.client
1515
.lock()

opentelemetry-otlp/src/exporter/http/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use std::time::Duration;
2727
mod metrics;
2828

2929
#[cfg(feature = "metrics")]
30-
use opentelemetry_sdk::metrics::exporter::ResourceMetricsRef;
30+
use opentelemetry_sdk::metrics::exporter::ResourceMetrics;
3131

3232
#[cfg(feature = "logs")]
3333
pub(crate) mod logs;
@@ -326,7 +326,7 @@ impl OtlpHttpClient {
326326
#[cfg(feature = "metrics")]
327327
fn build_metrics_export_body(
328328
&self,
329-
metrics: ResourceMetricsRef<'_>,
329+
metrics: ResourceMetrics<'_>,
330330
) -> Option<(Vec<u8>, &'static str)> {
331331
use opentelemetry_proto::tonic::collector::metrics::v1::ExportMetricsServiceRequest;
332332

opentelemetry-otlp/src/exporter/tonic/metrics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use opentelemetry_proto::tonic::collector::metrics::v1::{
66
metrics_service_client::MetricsServiceClient, ExportMetricsServiceRequest,
77
};
88
use opentelemetry_sdk::error::{OTelSdkError, OTelSdkResult};
9-
use opentelemetry_sdk::metrics::exporter::ResourceMetricsRef;
9+
use opentelemetry_sdk::metrics::exporter::ResourceMetrics;
1010
use tonic::{codegen::CompressionEncoding, service::Interceptor, transport::Channel, Request};
1111

1212
use super::BoxInterceptor;
@@ -52,7 +52,7 @@ impl TonicMetricsClient {
5252
}
5353

5454
impl MetricsClient for TonicMetricsClient {
55-
async fn export(&self, metrics: ResourceMetricsRef<'_>) -> OTelSdkResult {
55+
async fn export(&self, metrics: ResourceMetrics<'_>) -> OTelSdkResult {
5656
let (mut client, metadata, extensions) = self
5757
.inner
5858
.lock()

opentelemetry-otlp/src/metric.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::{ExporterBuildError, NoExporterBuilderSet};
1717
use core::fmt;
1818
use opentelemetry_sdk::error::OTelSdkResult;
1919

20-
use opentelemetry_sdk::metrics::exporter::ResourceMetricsRef;
20+
use opentelemetry_sdk::metrics::exporter::ResourceMetrics;
2121
use opentelemetry_sdk::metrics::{exporter::PushMetricExporter, Temporality};
2222
use std::fmt::{Debug, Formatter};
2323
use std::time::Duration;
@@ -122,7 +122,7 @@ impl HasHttpConfig for MetricExporterBuilder<HttpExporterBuilderSet> {
122122
pub(crate) trait MetricsClient: fmt::Debug + Send + Sync + 'static {
123123
fn export(
124124
&self,
125-
metrics: ResourceMetricsRef<'_>,
125+
metrics: ResourceMetrics<'_>,
126126
) -> impl std::future::Future<Output = OTelSdkResult> + Send;
127127
fn shutdown(&self) -> OTelSdkResult;
128128
}
@@ -148,7 +148,7 @@ impl Debug for MetricExporter {
148148
}
149149

150150
impl PushMetricExporter for MetricExporter {
151-
async fn export(&self, metrics: ResourceMetricsRef<'_>) -> OTelSdkResult {
151+
async fn export(&self, metrics: ResourceMetrics<'_>) -> OTelSdkResult {
152152
match &self.client {
153153
#[cfg(feature = "grpc-tonic")]
154154
SupportedTransportClient::Tonic(client) => client.export(metrics).await,

opentelemetry-proto/src/transform/metrics.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub mod tonic {
1313
ExponentialHistogram as SdkExponentialHistogram, Gauge as SdkGauge,
1414
Histogram as SdkHistogram, Metric as SdkMetric, MetricData, Sum as SdkSum,
1515
};
16-
use opentelemetry_sdk::metrics::exporter::{ResourceMetricsRef, ScopeMetricsRef};
16+
use opentelemetry_sdk::metrics::exporter::{ResourceMetrics, ScopeMetrics};
1717
use opentelemetry_sdk::metrics::Temporality;
1818
use opentelemetry_sdk::Resource as SdkResource;
1919

@@ -110,12 +110,16 @@ pub mod tonic {
110110
}
111111
}
112112

113-
impl From<ResourceMetricsRef<'_>> for ExportMetricsServiceRequest {
114-
fn from(rm: ResourceMetricsRef<'_>) -> Self {
113+
impl From<ResourceMetrics<'_>> for ExportMetricsServiceRequest {
114+
fn from(mut rm: ResourceMetrics<'_>) -> Self {
115+
let mut scope_metrics = Vec::new();
116+
while let Some(scope_metric) = rm.scope_metrics.next() {
117+
scope_metrics.push(scope_metric.into());
118+
}
115119
ExportMetricsServiceRequest {
116120
resource_metrics: vec![TonicResourceMetrics {
117121
resource: Some(rm.resource.into()),
118-
scope_metrics: rm.scope_metrics.map(Into::into).collect(),
122+
scope_metrics,
119123
schema_url: rm.resource.schema_url().map(Into::into).unwrap_or_default(),
120124
}],
121125
}
@@ -131,11 +135,15 @@ pub mod tonic {
131135
}
132136
}
133137

134-
impl From<ScopeMetricsRef<'_>> for TonicScopeMetrics {
135-
fn from(sm: ScopeMetricsRef<'_>) -> Self {
138+
impl From<ScopeMetrics<'_>> for TonicScopeMetrics {
139+
fn from(mut sm: ScopeMetrics<'_>) -> Self {
140+
let mut metrics = Vec::new();
141+
while let Some(metric) = sm.metrics.next() {
142+
metrics.push(metric.into());
143+
}
136144
TonicScopeMetrics {
137145
scope: Some((sm.scope, None).into()),
138-
metrics: sm.metrics.map(Into::into).collect(),
146+
metrics,
139147
schema_url: sm
140148
.scope
141149
.schema_url()

opentelemetry-sdk/CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
## vNext
44

5+
- *Breaking* change for `PushMetricExporter::export` from accepting
6+
`metrics: &mut ResourceMetrics`, to accepting `metrics: ResourceMetrics<'_>`.
7+
In addition, `ResourceMetrics` was also changed to allow improving underlying
8+
metric collection without any allocations in the future.
9+
[#2921](https://github.com/open-telemetry/opentelemetry-rust/pull/2921)
10+
- *Breaking* change for `Metric::data` field: From dynamic `Box<dyn Aggregation>`
11+
to new enum `AggregatedMetrics`.
12+
[#2857](https://github.com/open-telemetry/opentelemetry-rust/pull/2857)
13+
514
[#2868](https://github.com/open-telemetry/opentelemetry-rust/pull/2868)
615
`SdkLogger`, `SdkTracer` modified to respect telemetry suppression based on
716
`Context`. In other words, if the current context has telemetry suppression
@@ -40,6 +49,7 @@ also modified to suppress telemetry before invoking exporters.
4049
"spec_unstable_metrics_views". This was only required when using Views.
4150
[2928](https://github.com/open-telemetry/opentelemetry-rust/pull/2928)
4251

52+
4353
## 0.29.0
4454

4555
Released 2025-Mar-21

opentelemetry-sdk/benches/metric.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use opentelemetry::{
66
use opentelemetry_sdk::{
77
error::OTelSdkResult,
88
metrics::{
9-
data::ResourceMetrics, new_view, reader::MetricReader, Aggregation, Instrument,
9+
data::ResourceMetricsData, new_view, reader::MetricReader, Aggregation, Instrument,
1010
InstrumentKind, ManualReader, Pipeline, SdkMeterProvider, Stream, Temporality, View,
1111
},
1212
Resource,
@@ -23,7 +23,7 @@ impl MetricReader for SharedReader {
2323
self.0.register_pipeline(pipeline)
2424
}
2525

26-
fn collect(&self, rm: &mut ResourceMetrics) -> OTelSdkResult {
26+
fn collect(&self, rm: &mut ResourceMetricsData) -> OTelSdkResult {
2727
self.0.collect(rm)
2828
}
2929

@@ -240,7 +240,7 @@ fn counters(c: &mut Criterion) {
240240
});
241241

242242
let (rdr, cntr) = bench_counter(None, "cumulative");
243-
let mut rm = ResourceMetrics {
243+
let mut rm = ResourceMetricsData {
244244
resource: Resource::builder_empty().build(),
245245
scope_metrics: Vec::new(),
246246
};
@@ -337,7 +337,7 @@ fn benchmark_collect_histogram(b: &mut Bencher, n: usize) {
337337
h.record(1, &[]);
338338
}
339339

340-
let mut rm = ResourceMetrics {
340+
let mut rm = ResourceMetricsData {
341341
resource: Resource::builder_empty().build(),
342342
scope_metrics: Vec::new(),
343343
};

opentelemetry-sdk/src/metrics/data/mod.rs

+1-21
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,10 @@
22
33
use std::{borrow::Cow, time::SystemTime};
44

5-
use opentelemetry::{InstrumentationScope, KeyValue};
6-
7-
use crate::Resource;
5+
use opentelemetry::KeyValue;
86

97
use super::Temporality;
108

11-
/// A collection of [ScopeMetrics] and the associated [Resource] that created them.
12-
#[derive(Debug)]
13-
pub struct ResourceMetrics {
14-
/// The entity that collected the metrics.
15-
pub resource: Resource,
16-
/// The collection of metrics with unique [InstrumentationScope]s.
17-
pub scope_metrics: Vec<ScopeMetrics>,
18-
}
19-
20-
/// A collection of metrics produced by a meter.
21-
#[derive(Debug, Default)]
22-
pub struct ScopeMetrics {
23-
/// The [InstrumentationScope] that the meter was created with.
24-
pub scope: InstrumentationScope,
25-
/// The list of aggregations created by the meter.
26-
pub metrics: Vec<Metric>,
27-
}
28-
299
/// A collection of one or more aggregated time series from an [Instrument].
3010
///
3111
/// [Instrument]: crate::metrics::Instrument

opentelemetry-sdk/src/metrics/exporter.rs

+27-26
Original file line numberDiff line numberDiff line change
@@ -6,83 +6,84 @@ use crate::{error::OTelSdkResult, Resource};
66
use std::{fmt::Debug, slice::Iter, time::Duration};
77

88
use super::{
9-
data::{Metric, ResourceMetrics, ScopeMetrics},
9+
data::Metric,
10+
reader::{ResourceMetricsData, ScopeMetricsData},
1011
Temporality,
1112
};
1213

1314
/// A collection of [`BatchScopeMetrics`] and the associated [Resource] that created them.
1415
#[derive(Debug)]
15-
pub struct ResourceMetricsRef<'a> {
16+
pub struct ResourceMetrics<'a> {
1617
/// The entity that collected the metrics.
1718
pub resource: &'a Resource,
1819
/// The collection of metrics with unique [InstrumentationScope]s.
19-
pub scope_metrics: BatchScopeMetrics<'a>,
20+
pub scope_metrics: ScopeMetricsLendingIter<'a>,
2021
}
2122

2223
/// Iterator over libraries instrumentation scopes ([`InstrumentationScope`]) together with metrics.
23-
pub struct BatchScopeMetrics<'a> {
24-
iter: Iter<'a, ScopeMetrics>,
24+
/// Doesn't implement standard [`Iterator`], because it returns borrowed items. AKA "LendingIterator".
25+
pub struct ScopeMetricsLendingIter<'a> {
26+
iter: Iter<'a, ScopeMetricsData>,
2527
}
2628

2729
/// A collection of metrics produced by a [`InstrumentationScope`] meter.
2830
#[derive(Debug)]
29-
pub struct ScopeMetricsRef<'a> {
31+
pub struct ScopeMetrics<'a> {
3032
/// The [InstrumentationScope] that the meter was created with.
3133
pub scope: &'a InstrumentationScope,
3234
/// The list of aggregations created by the meter.
33-
pub metrics: BatchMetrics<'a>,
35+
pub metrics: MetricsLendingIter<'a>,
3436
}
3537

3638
/// Iterator over aggregations created by the meter.
37-
pub struct BatchMetrics<'a> {
39+
/// Doesn't implement standard [`Iterator`], because it returns borrowed items. AKA "LendingIterator".
40+
pub struct MetricsLendingIter<'a> {
3841
iter: Iter<'a, Metric>,
3942
}
4043

41-
impl<'a> ResourceMetricsRef<'a> {
42-
pub(crate) fn new(rm: &'a ResourceMetrics) -> Self {
44+
impl<'a> ResourceMetrics<'a> {
45+
pub(crate) fn new(rm: &'a ResourceMetricsData) -> Self {
4346
Self {
4447
resource: &rm.resource,
45-
scope_metrics: BatchScopeMetrics {
48+
scope_metrics: ScopeMetricsLendingIter {
4649
iter: rm.scope_metrics.iter(),
4750
},
4851
}
4952
}
5053
}
5154

52-
impl<'a> ScopeMetricsRef<'a> {
53-
fn new(sm: &'a ScopeMetrics) -> Self {
55+
impl<'a> ScopeMetrics<'a> {
56+
fn new(sm: &'a ScopeMetricsData) -> Self {
5457
Self {
5558
scope: &sm.scope,
56-
metrics: BatchMetrics {
59+
metrics: MetricsLendingIter {
5760
iter: sm.metrics.iter(),
5861
},
5962
}
6063
}
6164
}
6265

63-
impl Debug for BatchScopeMetrics<'_> {
66+
impl Debug for ScopeMetricsLendingIter<'_> {
6467
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6568
f.debug_struct("BatchScopeMetrics").finish()
6669
}
6770
}
6871

69-
impl<'a> Iterator for BatchScopeMetrics<'a> {
70-
type Item = ScopeMetricsRef<'a>;
71-
72-
fn next(&mut self) -> Option<Self::Item> {
73-
self.iter.next().map(ScopeMetricsRef::new)
72+
impl ScopeMetricsLendingIter<'_> {
73+
/// Advances the iterator and returns the next value.
74+
pub fn next(&mut self) -> Option<ScopeMetrics<'_>> {
75+
self.iter.next().map(ScopeMetrics::new)
7476
}
7577
}
7678

77-
impl<'a> Iterator for BatchMetrics<'a> {
78-
type Item = &'a Metric;
79-
80-
fn next(&mut self) -> Option<Self::Item> {
79+
impl MetricsLendingIter<'_> {
80+
/// Advances the iterator and returns the next value.
81+
pub fn next(&mut self) -> Option<&Metric> {
8182
self.iter.next()
8283
}
8384
}
8485

85-
impl Debug for BatchMetrics<'_> {
86+
impl Debug for MetricsLendingIter<'_> {
8687
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8788
f.debug_struct("BatchMetrics").finish()
8889
}
@@ -99,7 +100,7 @@ pub trait PushMetricExporter: Send + Sync + 'static {
99100
/// considered unrecoverable and will be logged.
100101
fn export(
101102
&self,
102-
metrics: ResourceMetricsRef<'_>,
103+
metrics: ResourceMetrics<'_>,
103104
) -> impl std::future::Future<Output = OTelSdkResult> + Send;
104105

105106
/// Flushes any metric data held by an exporter.

0 commit comments

Comments
 (0)