Skip to content

Commit ebbebf5

Browse files
cijothomasutpilla
andauthored
fix: Further trim public API on views (#2989)
Co-authored-by: Utkarsh Umesan Pillai <[email protected]>
1 parent e123996 commit ebbebf5

File tree

6 files changed

+69
-49
lines changed

6 files changed

+69
-49
lines changed

opentelemetry-sdk/CHANGELOG.md

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,24 +44,46 @@ also modified to suppress telemetry before invoking exporters.
4444
behind feature flag "experimental_metrics_custom_reader".
4545
[#2928](https://github.com/open-telemetry/opentelemetry-rust/pull/2928)
4646

47-
- TODO: Placeholder for View related changelog. Polish this after all changs done
47+
- **Views improvements**:
4848
- Core view functionality is now available by default—users can change the
4949
name, unit, description, and cardinality limit of a metric via views without
5050
enabling the `spec_unstable_metrics_views` feature flag. Advanced view
5151
features, such as custom aggregation or attribute filtering, still require
5252
the `spec_unstable_metrics_views` feature.
53-
- Introduced a builder pattern for `Stream` creation to use with "Views".
53+
- Removed `new_view()` method and `View` trait. Views can now be added by passing
54+
a function with signature `Fn(&Instrument) -> Option<Stream>` to the `with_view`
55+
method on `MeterProviderBuilder`.
56+
- Introduced a builder pattern for `Stream` creation to use with views:
5457
- Added `StreamBuilder` struct with methods to configure stream properties
5558
- Added `Stream::builder()` method that returns a new `StreamBuilder`
5659
- `StreamBuilder::build()` returns `Result<Stream, Box<dyn Error>>` enabling
57-
proper validation
58-
- Removed `new_view()` on `View`. Views can be instead added by passing anything
59-
that implements `View` trait to `with_view` method on `MeterProviderBuilder`.
60-
`View` is implemented for `Fn(&Instrument) -> Option<Stream>`, so this can be
61-
used to add views.
60+
proper validation.
61+
62+
Example of using views to rename a metric:
63+
64+
```rust
65+
let view_rename = |i: &Instrument| {
66+
if i.name() == "my_histogram" {
67+
Some(
68+
Stream::builder()
69+
.with_name("my_histogram_renamed")
70+
.build()
71+
.unwrap(),
72+
)
73+
} else {
74+
None
75+
}
76+
};
77+
78+
let provider = SdkMeterProvider::builder()
79+
// add exporters, set resource etc.
80+
.with_view(view_rename)
81+
.build();
82+
```
6283

6384
- *Breaking* `Aggregation` enum moved behind feature flag
64-
"spec_unstable_metrics_views". This was only required when using Views.
85+
"spec_unstable_metrics_views". This was only required when using advanced view
86+
capabilities.
6587
[#2928](https://github.com/open-telemetry/opentelemetry-rust/pull/2928)
6688
- *Breaking* change, affecting custom `PushMetricExporter` authors:
6789
- The `export` method on `PushMetricExporter` now accepts `&ResourceMetrics`

opentelemetry-sdk/benches/metric.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use opentelemetry_sdk::{
77
error::OTelSdkResult,
88
metrics::{
99
data::ResourceMetrics, reader::MetricReader, Aggregation, Instrument, InstrumentKind,
10-
ManualReader, Pipeline, SdkMeterProvider, Stream, Temporality, View,
10+
ManualReader, Pipeline, SdkMeterProvider, Stream, Temporality,
1111
},
1212
};
1313
use rand::Rng;
@@ -107,7 +107,9 @@ impl MetricReader for SharedReader {
107107
// time: [643.75 ns 649.05 ns 655.14 ns]
108108
// Histogram/Record10Attrs1000bounds
109109
// time: [726.87 ns 736.52 ns 747.09 ns]
110-
fn bench_counter(view: Option<Box<dyn View>>, temporality: &str) -> (SharedReader, Counter<u64>) {
110+
type ViewFn = Box<dyn Fn(&Instrument) -> Option<Stream> + Send + Sync + 'static>;
111+
112+
fn bench_counter(view: Option<ViewFn>, temporality: &str) -> (SharedReader, Counter<u64>) {
111113
let rdr = if temporality == "cumulative" {
112114
SharedReader(Arc::new(ManualReader::builder().build()))
113115
} else {
@@ -273,7 +275,7 @@ fn bench_histogram(bound_count: usize) -> (SharedReader, Histogram<u64>) {
273275
let r = SharedReader(Arc::new(ManualReader::default()));
274276
let builder = SdkMeterProvider::builder()
275277
.with_reader(r.clone())
276-
.with_view(Box::new(move |i: &Instrument| {
278+
.with_view(move |i: &Instrument| {
277279
if i.name().starts_with("histogram_") {
278280
Stream::builder()
279281
.with_aggregation(Aggregation::ExplicitBucketHistogram {
@@ -285,7 +287,7 @@ fn bench_histogram(bound_count: usize) -> (SharedReader, Histogram<u64>) {
285287
} else {
286288
None
287289
}
288-
}));
290+
});
289291

290292
let mtr = builder.build().meter("test_meter");
291293
let hist = mtr

opentelemetry-sdk/src/metrics/instrument.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@ impl InstrumentKind {
6464
}
6565
}
6666
}
67-
68-
/// Describes properties an instrument is created with, used for filtering in
69-
/// [View](crate::metrics::View)s.
67+
/// Describes the properties of an instrument at creation, used for filtering in
68+
/// views. This is utilized in the `with_view` methods on `MeterProviderBuilder`
69+
/// to customize metric output.
7070
///
71-
/// A reference to `Instrument` is provided to the `view` to select the
72-
/// instrument(s) for which the [Stream] should be applied.
71+
/// Users can use a reference to `Instrument` to select which instrument(s) a
72+
/// [Stream] should be applied to.
7373
///
7474
/// # Example
7575
///
@@ -78,7 +78,7 @@ impl InstrumentKind {
7878
///
7979
/// let my_view_change_cardinality = |i: &Instrument| {
8080
/// if i.name() == "my_second_histogram" {
81-
/// // Note: If Stream is invalid, build() will return an error. By
81+
/// // Note: If Stream is invalid, `build()` will return an error. By
8282
/// // calling `.ok()`, any such error is ignored and treated as if the
8383
/// // view does not match the instrument. If this is not the desired
8484
/// // behavior, consider handling the error explicitly.
@@ -185,8 +185,8 @@ impl StreamBuilder {
185185
/// Set the stream allowed attribute keys.
186186
///
187187
/// Any attribute recorded for the stream with a key not in this set will be
188-
/// dropped. If the set is empty, all attributes will be dropped, if `None` all
189-
/// attributes will be kept.
188+
/// dropped. If the set is empty, all attributes will be dropped.
189+
/// If this method is not used, all attributes will be kept.
190190
pub fn with_allowed_attribute_keys(
191191
mut self,
192192
attribute_keys: impl IntoIterator<Item = Key>,
@@ -256,15 +256,17 @@ fn validate_bucket_boundaries(boundaries: &[f64]) -> Result<(), String> {
256256
// validate that buckets are sorted and non-duplicate
257257
for i in 1..boundaries.len() {
258258
if boundaries[i] <= boundaries[i - 1] {
259-
return Err("Bucket boundaries must be sorted and non-duplicate".to_string());
259+
return Err(
260+
"Bucket boundaries must be sorted and not contain any duplicates".to_string(),
261+
);
260262
}
261263
}
262264

263265
Ok(())
264266
}
265267

266-
/// Describes the stream of data an instrument produces. Used in
267-
/// [View](crate::metrics::View)s to customize the metric output.
268+
/// Describes the stream of data an instrument produces. Used in `with_view`
269+
/// methods on `MeterProviderBuilder` to customize the metric output.
268270
#[derive(Default, Debug)]
269271
pub struct Stream {
270272
/// The human-readable identifier of the stream.

opentelemetry-sdk/src/metrics/meter_provider.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ use crate::Resource;
1818
use super::{
1919
exporter::PushMetricExporter, meter::SdkMeter, noop::NoopMeter,
2020
periodic_reader::PeriodicReader, pipeline::Pipelines, reader::MetricReader, view::View,
21+
Instrument, Stream,
2122
};
2223

2324
/// Handles the creation and coordination of [Meter]s.
2425
///
2526
/// All `Meter`s created by a `MeterProvider` will be associated with the same
26-
/// [Resource], have the same [View]s applied to them, and have their produced
27+
/// [Resource], have the same views applied to them, and have their produced
2728
/// metric telemetry passed to the configured [MetricReader]s. This is a
2829
/// clonable handle to the MeterProvider implementation itself, and cloning it
2930
/// will create a new reference, not a new instance of a MeterProvider. Dropping
@@ -287,14 +288,14 @@ impl MeterProviderBuilder {
287288
self
288289
}
289290

290-
/// Adds a [View] to the [MeterProvider].
291+
/// Adds a view to the [MeterProvider].
291292
///
292293
/// Views allow you to customize how metrics are aggregated, renamed, or
293294
/// otherwise transformed before export, without modifying instrument
294295
/// definitions in your application or library code.
295296
///
296-
/// You can pass any type implementing the [`View`] trait, including
297-
/// closures matching the pattern `Fn(&Instrument) -> Option<Stream>`. The
297+
/// You can pass any function or closure matching the signature
298+
/// `Fn(&Instrument) -> Option<Stream> + Send + Sync + 'static`. The
298299
/// function receives a reference to the [`Instrument`] and can return an
299300
/// [`Option`] of [`Stream`] to specify how matching instruments should be
300301
/// exported. Returning `None` means the view does not apply to the given
@@ -348,7 +349,7 @@ impl MeterProviderBuilder {
348349
/// // By calling `.ok()`, any such error is ignored and treated as if the view does not match
349350
/// // the instrument.
350351
/// // If this is not the desired behavior, consider handling the error explicitly.
351-
/// Stream::builder().with_cardinality_limit(100).build().ok()
352+
/// Stream::builder().with_cardinality_limit(0).build().ok()
352353
/// } else {
353354
/// None
354355
/// }
@@ -361,10 +362,12 @@ impl MeterProviderBuilder {
361362
/// If no views are added, the [MeterProvider] uses the default view.
362363
///
363364
/// [`Instrument`]: crate::metrics::Instrument
364-
/// [`View`]: crate::metrics::View
365365
/// [`Stream`]: crate::metrics::Stream
366366
/// [`Option`]: core::option::Option
367-
pub fn with_view<T: View>(mut self, view: T) -> Self {
367+
pub fn with_view<T>(mut self, view: T) -> Self
368+
where
369+
T: Fn(&Instrument) -> Option<Stream> + Send + Sync + 'static,
370+
{
368371
self.views.push(Arc::new(view));
369372
self
370373
}

opentelemetry-sdk/src/metrics/mod.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! ## Configuration
44
//!
55
//! The metrics SDK configuration is stored with each [SdkMeterProvider].
6-
//! Configuration for [Resource]s, [View]s, and [ManualReader] or
6+
//! Configuration for [Resource]s, views, and [ManualReader] or
77
//! [PeriodicReader] instances can be specified.
88
//!
99
//! ### Example
@@ -81,7 +81,6 @@ pub use periodic_reader::*;
8181
pub use pipeline::Pipeline;
8282

8383
pub use instrument::{Instrument, InstrumentKind, Stream, StreamBuilder};
84-
pub use view::View;
8584

8685
use std::hash::Hash;
8786

@@ -113,7 +112,6 @@ mod tests {
113112
use self::data::{HistogramDataPoint, ScopeMetrics, SumDataPoint};
114113
use super::data::MetricData;
115114
use super::internal::Number;
116-
use super::view::View;
117115
use super::*;
118116
use crate::metrics::data::ResourceMetrics;
119117
use crate::metrics::internal::AggregatedMetricsAccess;
@@ -940,12 +938,10 @@ mod tests {
940938
// View drops all attributes.
941939
let view = |i: &Instrument| {
942940
if i.name == "my_observable_counter" {
943-
Some(
944-
Stream::builder()
945-
.with_allowed_attribute_keys(vec![])
946-
.build()
947-
.unwrap(),
948-
)
941+
Stream::builder()
942+
.with_allowed_attribute_keys(vec![])
943+
.build()
944+
.ok()
949945
} else {
950946
None
951947
}
@@ -3314,7 +3310,10 @@ mod tests {
33143310
}
33153311
}
33163312

3317-
fn new_with_view<T: View>(temporality: Temporality, view: T) -> Self {
3313+
fn new_with_view<T>(temporality: Temporality, view: T) -> Self
3314+
where
3315+
T: Fn(&Instrument) -> Option<Stream> + Send + Sync + 'static,
3316+
{
33183317
let exporter = InMemoryMetricExporterBuilder::new().with_temporality(temporality);
33193318
let exporter = exporter.build();
33203319
let meter_provider = SdkMeterProvider::builder()

opentelemetry-sdk/src/metrics/view.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ use super::instrument::{Instrument, Stream};
3636
/// let provider = SdkMeterProvider::builder().with_view(my_view).build();
3737
/// # drop(provider)
3838
/// ```
39-
// TODO: This trait need not be public, if we modify MeterProvider to take a
40-
// Fn(&Instrument) -> Option<Stream> instead of View.
41-
pub trait View: Send + Sync + 'static {
39+
pub(crate) trait View: Send + Sync + 'static {
4240
/// Defines how data should be collected for certain instruments.
4341
///
4442
/// Return [Stream] to use for matching [Instrument]s,
@@ -54,9 +52,3 @@ where
5452
self(inst)
5553
}
5654
}
57-
58-
impl View for Box<dyn View> {
59-
fn match_inst(&self, inst: &Instrument) -> Option<Stream> {
60-
(**self).match_inst(inst)
61-
}
62-
}

0 commit comments

Comments
 (0)