diff --git a/examples/basic-otlp-with-selector/src/main.rs b/examples/basic-otlp-with-selector/src/main.rs index 512ea1ae67..4ec79cde2d 100644 --- a/examples/basic-otlp-with-selector/src/main.rs +++ b/examples/basic-otlp-with-selector/src/main.rs @@ -113,16 +113,16 @@ async fn main() -> Result<(), Box> { .with_description("A ValueObserver set to 1.0") .init(); - let value_recorder_two = meter.f64_value_recorder("ex.com.two").init(); + let histogram_two = meter.f64_histogram("ex.com.two").init(); - let another_recorder = meter.f64_value_recorder("ex.com.two").init(); + let another_recorder = meter.f64_histogram("ex.com.two").init(); another_recorder.record(5.5, COMMON_ATTRIBUTES.as_ref()); let _baggage = Context::current_with_baggage(vec![FOO_KEY.string("foo1"), BAR_KEY.string("bar1")]) .attach(); - let value_recorder = value_recorder_two.bind(COMMON_ATTRIBUTES.as_ref()); + let histogram = histogram_two.bind(COMMON_ATTRIBUTES.as_ref()); tracer.in_span("operation", |cx| { let span = cx.span(); span.add_event( @@ -135,7 +135,7 @@ async fn main() -> Result<(), Box> { // Note: call-site variables added as context Entries: &Context::current_with_baggage(vec![ANOTHER_KEY.string("xyz")]), COMMON_ATTRIBUTES.as_ref(), - vec![value_recorder_two.measurement(2.0)], + vec![histogram_two.measurement(2.0)], ); tracer.in_span("Sub operation...", |cx| { @@ -144,7 +144,7 @@ async fn main() -> Result<(), Box> { span.add_event("Sub span event".to_string(), vec![]); - value_recorder.record(1.3); + histogram.record(1.3); }); }); diff --git a/examples/basic-otlp/src/main.rs b/examples/basic-otlp/src/main.rs index ae2e5c0c3d..7cb894bf23 100644 --- a/examples/basic-otlp/src/main.rs +++ b/examples/basic-otlp/src/main.rs @@ -77,16 +77,27 @@ async fn main() -> Result<(), Box> { .with_description("A ValueObserver set to 1.0") .init(); - let value_recorder_two = meter.f64_value_recorder("ex.com.two").init(); - - let another_recorder = meter.f64_value_recorder("ex.com.two").init(); - another_recorder.record(5.5, COMMON_ATTRIBUTES.as_ref()); + let histogram_two = meter.f64_histogram("ex.com.two").init(); + + // Needed for code coverage reasons. + #[allow(deprecated)] + let a_recorder = meter.f64_value_recorder("ex.recorder.a").init(); + a_recorder.record(5.5, COMMON_ATTRIBUTES.as_ref()); + #[allow(deprecated)] + let b_recorder = meter.u64_value_recorder("ex.recorder.b").init(); + b_recorder.record(5, COMMON_ATTRIBUTES.as_ref()); + #[allow(deprecated)] + let c_recorder = meter.i64_value_recorder("ex.recorder.c").init(); + c_recorder.record(5, COMMON_ATTRIBUTES.as_ref()); + + let another_histogram = meter.f64_histogram("ex.com.two").init(); + another_histogram.record(5.5, COMMON_ATTRIBUTES.as_ref()); let _baggage = Context::current_with_baggage(vec![FOO_KEY.string("foo1"), BAR_KEY.string("bar1")]) .attach(); - let value_recorder = value_recorder_two.bind(COMMON_ATTRIBUTES.as_ref()); + let histogram = histogram_two.bind(COMMON_ATTRIBUTES.as_ref()); tracer.in_span("operation", |cx| { let span = cx.span(); @@ -100,7 +111,7 @@ async fn main() -> Result<(), Box> { // Note: call-site variables added as context Entries: &Context::current_with_baggage(vec![ANOTHER_KEY.string("xyz")]), COMMON_ATTRIBUTES.as_ref(), - vec![value_recorder_two.measurement(2.0)], + vec![histogram_two.measurement(2.0)], ); tracer.in_span("Sub operation...", |cx| { @@ -109,7 +120,7 @@ async fn main() -> Result<(), Box> { span.add_event("Sub span event".to_string(), vec![]); - value_recorder.record(1.3); + histogram.record(1.3); }); }); diff --git a/examples/basic/src/main.rs b/examples/basic/src/main.rs index 5c4a317f25..da3337225d 100644 --- a/examples/basic/src/main.rs +++ b/examples/basic/src/main.rs @@ -70,13 +70,13 @@ async fn main() -> Result<(), Box> { .with_description("A ValueObserver set to 1.0") .init(); - let value_recorder_two = meter.f64_value_recorder("ex.com.two").init(); + let histogram_two = meter.f64_histogram("ex.com.two").init(); let _baggage = Context::current_with_baggage(vec![FOO_KEY.string("foo1"), BAR_KEY.string("bar1")]) .attach(); - let value_recorder = value_recorder_two.bind(COMMON_ATTRIBUTES.as_ref()); + let histogram = histogram_two.bind(COMMON_ATTRIBUTES.as_ref()); tracer.in_span("operation", |cx| { let span = cx.span(); @@ -90,7 +90,7 @@ async fn main() -> Result<(), Box> { // Note: call-site variables added as context Entries: &Context::current_with_baggage(vec![ANOTHER_KEY.string("xyz")]), COMMON_ATTRIBUTES.as_ref(), - vec![value_recorder_two.measurement(2.0)], + vec![histogram_two.measurement(2.0)], ); tracer.in_span("Sub operation...", |cx| { @@ -99,7 +99,7 @@ async fn main() -> Result<(), Box> { span.add_event("Sub span event".to_string(), vec![]); - value_recorder.record(1.3); + histogram.record(1.3); }); }); diff --git a/examples/dynatrace/src/main.rs b/examples/dynatrace/src/main.rs index f9251e31f1..679b5c055b 100644 --- a/examples/dynatrace/src/main.rs +++ b/examples/dynatrace/src/main.rs @@ -140,16 +140,16 @@ async fn main() -> Result<(), Box> { .with_description("A ValueObserver set to 1.0") .init(); - let value_recorder_two = meter.f64_value_recorder("ex.com.two").init(); + let histogram_two = meter.f64_histogram("ex.com.two").init(); - let another_recorder = meter.f64_value_recorder("ex.com.two").init(); + let another_recorder = meter.f64_histogram("ex.com.two").init(); another_recorder.record(5.5, COMMON_ATTRIBUTES.as_ref()); let _baggage = Context::current_with_baggage(vec![FOO_KEY.string("foo1"), BAR_KEY.string("bar1")]) .attach(); - let value_recorder = value_recorder_two.bind(COMMON_ATTRIBUTES.as_ref()); + let histogram = histogram_two.bind(COMMON_ATTRIBUTES.as_ref()); tracer.in_span("operation", |cx| { let span = cx.span(); @@ -163,7 +163,7 @@ async fn main() -> Result<(), Box> { // Note: call-site variables added as context Entries: &Context::current_with_baggage(vec![ANOTHER_KEY.string("xyz")]), COMMON_ATTRIBUTES.as_ref(), - vec![value_recorder_two.measurement(2.0)], + vec![histogram_two.measurement(2.0)], ); tracer.in_span("Sub operation...", |cx| { @@ -172,7 +172,7 @@ async fn main() -> Result<(), Box> { span.add_event("Sub span event".to_string(), vec![]); - value_recorder.record(1.3); + histogram.record(1.3); }); }); diff --git a/examples/hyper-prometheus/src/main.rs b/examples/hyper-prometheus/src/main.rs index ee31149011..7d27675c1a 100644 --- a/examples/hyper-prometheus/src/main.rs +++ b/examples/hyper-prometheus/src/main.rs @@ -8,7 +8,7 @@ use hyper::{ }; use opentelemetry::{ global, - metrics::{BoundCounter, BoundValueRecorder}, + metrics::{BoundCounter, BoundHistogram}, KeyValue, }; use opentelemetry_prometheus::PrometheusExporter; @@ -63,8 +63,8 @@ async fn serve_req( struct AppState { exporter: PrometheusExporter, http_counter: BoundCounter, - http_body_gauge: BoundValueRecorder, - http_req_histogram: BoundValueRecorder, + http_body_gauge: BoundHistogram, + http_req_histogram: BoundHistogram, } #[tokio::main] @@ -80,12 +80,12 @@ pub async fn main() -> Result<(), Box> { .init() .bind(HANDLER_ALL.as_ref()), http_body_gauge: meter - .u64_value_recorder("example.http_response_size_bytes") + .u64_histogram("example.http_response_size_bytes") .with_description("The metrics HTTP response sizes in bytes.") .init() .bind(HANDLER_ALL.as_ref()), http_req_histogram: meter - .f64_value_recorder("example.http_request_duration_seconds") + .f64_histogram("example.http_request_duration_seconds") .with_description("The HTTP request latencies in seconds.") .init() .bind(HANDLER_ALL.as_ref()), diff --git a/opentelemetry-dynatrace/src/transform/metrics.rs b/opentelemetry-dynatrace/src/transform/metrics.rs index 9f302f977f..1dc4b1fa28 100644 --- a/opentelemetry-dynatrace/src/transform/metrics.rs +++ b/opentelemetry-dynatrace/src/transform/metrics.rs @@ -1112,7 +1112,7 @@ mod tests { "test_histogram".to_string(), "test", None, - InstrumentKind::ValueRecorder, + InstrumentKind::Histogram, NumberKind::I64, ); let bound = [0.1, 0.2, 0.3]; diff --git a/opentelemetry-dynatrace/tests/http_test.rs b/opentelemetry-dynatrace/tests/http_test.rs index c038a5bd77..fc14f08e15 100644 --- a/opentelemetry-dynatrace/tests/http_test.rs +++ b/opentelemetry-dynatrace/tests/http_test.rs @@ -98,7 +98,7 @@ mod test { let recorder = meter.f64_counter("test2").init(); recorder.add(1e10 + 0.123, &[KeyValue::new("foo", "bar")]); - let recorder = meter.i64_value_recorder("test3").init(); + let recorder = meter.i64_histogram("test3").init(); recorder.record(-999, &[Key::new("foo").i64(-123)]); let _ = tick_tx.send(1); diff --git a/opentelemetry-otlp/src/transform/metrics.rs b/opentelemetry-otlp/src/transform/metrics.rs index d6f673000b..b6bef09c4a 100644 --- a/opentelemetry-otlp/src/transform/metrics.rs +++ b/opentelemetry-otlp/src/transform/metrics.rs @@ -626,7 +626,7 @@ mod tests { "test".to_string(), "test", None, - InstrumentKind::ValueRecorder, + InstrumentKind::Histogram, NumberKind::I64, ); let bound = [0.1, 0.2, 0.3]; diff --git a/opentelemetry-prometheus/src/lib.rs b/opentelemetry-prometheus/src/lib.rs index 4ebbb20cc4..1929850fe1 100644 --- a/opentelemetry-prometheus/src/lib.rs +++ b/opentelemetry-prometheus/src/lib.rs @@ -22,7 +22,7 @@ //! .with_description("Counts things") //! .init(); //! let recorder = meter -//! .i64_value_recorder("a.value_recorder") +//! .i64_histogram("a.histogram") //! .with_description("Records values") //! .init(); //! @@ -40,14 +40,14 @@ //! // # HELP a_counter Counts things //! // # TYPE a_counter counter //! // a_counter{R="V",key="value"} 100 -//! // # HELP a_value_recorder Records values -//! // # TYPE a_value_recorder histogram -//! // a_value_recorder_bucket{R="V",key="value",le="0.5"} 0 -//! // a_value_recorder_bucket{R="V",key="value",le="0.9"} 0 -//! // a_value_recorder_bucket{R="V",key="value",le="0.99"} 0 -//! // a_value_recorder_bucket{R="V",key="value",le="+Inf"} 1 -//! // a_value_recorder_sum{R="V",key="value"} 100 -//! // a_value_recorder_count{R="V",key="value"} 1 +//! // # HELP a_histogram Records values +//! // # TYPE a_histogram histogram +//! // a_histogram_bucket{R="V",key="value",le="0.5"} 0 +//! // a_histogram_bucket{R="V",key="value",le="0.9"} 0 +//! // a_histogram_bucket{R="V",key="value",le="0.99"} 0 +//! // a_histogram_bucket{R="V",key="value",le="+Inf"} 1 +//! // a_histogram_sum{R="V",key="value"} 100 +//! // a_histogram_count{R="V",key="value"} 1 //! ``` #![warn( future_incompatible, diff --git a/opentelemetry-prometheus/tests/integration_test.rs b/opentelemetry-prometheus/tests/integration_test.rs index da56513041..1cfb25bfb0 100644 --- a/opentelemetry-prometheus/tests/integration_test.rs +++ b/opentelemetry-prometheus/tests/integration_test.rs @@ -72,7 +72,7 @@ fn test_add() { let up_down_counter = meter.f64_up_down_counter("updowncounter").init(); let counter = meter.f64_counter("counter").init(); - let value_recorder = meter.f64_value_recorder("value_recorder").init(); + let histogram = meter.f64_histogram("my.histogram").init(); let attributes = vec![KeyValue::new("A", "B"), KeyValue::new("C", "D")]; @@ -92,16 +92,16 @@ fn test_add() { expected.push(r#"intobserver{A="B",C="D",R="V"} 1"#); - value_recorder.record(-0.6, &attributes); - value_recorder.record(-0.4, &attributes); - value_recorder.record(0.6, &attributes); - value_recorder.record(20.0, &attributes); + histogram.record(-0.6, &attributes); + histogram.record(-0.4, &attributes); + histogram.record(0.6, &attributes); + histogram.record(20.0, &attributes); - expected.push(r#"value_recorder_bucket{A="B",C="D",R="V",le="+Inf"} 4"#); - expected.push(r#"value_recorder_bucket{A="B",C="D",R="V",le="-0.5"} 1"#); - expected.push(r#"value_recorder_bucket{A="B",C="D",R="V",le="1"} 3"#); - expected.push(r#"value_recorder_count{A="B",C="D",R="V"} 4"#); - expected.push(r#"value_recorder_sum{A="B",C="D",R="V"} 19.6"#); + expected.push(r#"my_histogram_bucket{A="B",C="D",R="V",le="+Inf"} 4"#); + expected.push(r#"my_histogram_bucket{A="B",C="D",R="V",le="-0.5"} 1"#); + expected.push(r#"my_histogram_bucket{A="B",C="D",R="V",le="1"} 3"#); + expected.push(r#"my_histogram_count{A="B",C="D",R="V"} 4"#); + expected.push(r#"my_histogram_sum{A="B",C="D",R="V"} 19.6"#); up_down_counter.add(10.0, &attributes); up_down_counter.add(-3.2, &attributes); @@ -122,15 +122,15 @@ fn test_sanitization() { .init(); let meter = exporter.provider().unwrap().meter("test", None); - let value_recorder = meter.f64_value_recorder("http.server.duration").init(); + let histogram = meter.f64_histogram("http.server.duration").init(); let attributes = vec![ KeyValue::new("http.method", "GET"), KeyValue::new("http.host", "server"), ]; - value_recorder.record(-0.6, &attributes); - value_recorder.record(-0.4, &attributes); - value_recorder.record(0.6, &attributes); - value_recorder.record(20.0, &attributes); + histogram.record(-0.6, &attributes); + histogram.record(-0.4, &attributes); + histogram.record(0.6, &attributes); + histogram.record(20.0, &attributes); let expected = vec![ r#"http_server_duration_bucket{http_host="server",http_method="GET",service_name="Test Service",le="+Inf"} 4"#, diff --git a/opentelemetry/benches/ddsketch.rs b/opentelemetry/benches/ddsketch.rs index 7234468711..c6bff00eee 100644 --- a/opentelemetry/benches/ddsketch.rs +++ b/opentelemetry/benches/ddsketch.rs @@ -23,7 +23,7 @@ fn ddsketch(data: Vec) { "test".to_string(), "test", None, - InstrumentKind::ValueRecorder, + InstrumentKind::Histogram, NumberKind::F64, ); for f in data { @@ -44,7 +44,7 @@ fn array(data: Vec) { "test".to_string(), "test", None, - InstrumentKind::ValueRecorder, + InstrumentKind::Histogram, NumberKind::F64, ); for f in data { diff --git a/opentelemetry/src/metrics/histogram.rs b/opentelemetry/src/metrics/histogram.rs new file mode 100644 index 0000000000..2be6603a80 --- /dev/null +++ b/opentelemetry/src/metrics/histogram.rs @@ -0,0 +1,106 @@ +use crate::metrics::{ + sync_instrument::{SyncBoundInstrument, SyncInstrument}, + Descriptor, InstrumentKind, Measurement, Meter, Number, NumberKind, Result, Unit, +}; +use crate::KeyValue; +use std::marker; + +/// Histogram is a metric that records per-request non-additive values. +#[derive(Clone, Debug)] +pub struct Histogram(SyncInstrument); + +impl Histogram +where + T: Into, +{ + /// Creates a bound instrument for this Histogram. The attributes are + /// associated with values recorded via subsequent calls to record. + pub fn bind(&self, attributes: &[KeyValue]) -> BoundHistogram { + let bound_instrument = self.0.bind(attributes); + BoundHistogram { bound_instrument } + } + + /// Record a new metric value + pub fn record(&self, value: T, attributes: &[KeyValue]) { + self.0.direct_record(value.into(), attributes) + } + + /// Creates a `Measurement` object to use with batch recording. + pub fn measurement(&self, value: T) -> Measurement { + Measurement::new(value.into(), self.0.instrument().clone()) + } +} + +/// BoundHistogram is a bound instrument for recording per-request +/// non-additive values. +/// +/// It inherits the Unbind function from syncBoundInstrument. +#[derive(Clone, Debug)] +pub struct BoundHistogram { + bound_instrument: SyncBoundInstrument, +} + +impl BoundHistogram +where + T: Into, +{ + /// Adds a new value to the list of Histogram's records. The attributes + /// should contain the keys and values to be associated with this value. + pub fn record(&self, value: T) { + self.bound_instrument.direct_record(value.into()) + } +} + +/// Initialization configuration for a given `Histogram`. +#[derive(Debug)] +pub struct HistogramBuilder<'a, T> { + meter: &'a Meter, + descriptor: Descriptor, + _marker: marker::PhantomData, +} + +impl<'a, T> HistogramBuilder<'a, T> { + pub(crate) fn new(meter: &'a Meter, name: String, number_kind: NumberKind) -> Self { + HistogramBuilder { + meter, + descriptor: Descriptor::new( + name, + meter.instrumentation_library().name, + meter.instrumentation_library().version, + InstrumentKind::Histogram, + number_kind, + ), + _marker: marker::PhantomData, + } + } + + /// Set the description for this `Histogram` + pub fn with_description>(mut self, description: S) -> Self { + self.descriptor.set_description(description.into()); + self + } + + /// Set the unit for this `Histogram`. + pub fn with_unit(mut self, unit: Unit) -> Self { + self.descriptor.config.unit = Some(unit); + self + } + + /// Tries to create a new `Histogram`. + pub fn try_init(self) -> Result> { + let instrument = self.meter.new_sync_instrument(self.descriptor)?; + Ok(Histogram(SyncInstrument::new(instrument))) + } + + /// Creates a new `Histogram`. + /// + /// # Panics + /// + /// This function panics if the instrument cannot be created. Use try_init if you want to + /// handle errors. + pub fn init(self) -> Histogram { + Histogram(SyncInstrument::new( + self.meter.new_sync_instrument(self.descriptor).unwrap(), + )) + } +} diff --git a/opentelemetry/src/metrics/kind.rs b/opentelemetry/src/metrics/kind.rs index 8ba383e46c..f27316496e 100644 --- a/opentelemetry/src/metrics/kind.rs +++ b/opentelemetry/src/metrics/kind.rs @@ -2,7 +2,8 @@ /// /// | **Name** | Instrument kind | Function(argument) | Default aggregation | Notes | /// | ----------------------- | ----- | --------- | ------------- | --- | -/// | **ValueRecorder** | Synchronous | Record(value) | MinMaxSumCount | Per-request, any non-additive measurement | +/// | **Histogram** | Synchronous | Record(value) | MinMaxSumCount | Per-request, any non-additive measurement | +/// | **ValueRecorder** | Synchronous | Record(value) | MinMaxSumCount | Depreated. Use Histogram. | /// | **ValueObserver** | Asynchronous | Observe(value) | MinMaxSumCount | Per-interval, any non-additive measurement | /// | **Counter** | Synchronous additive monotonic | Add(increment) | Sum | Per-request, part of a monotonic sum | /// | **UpDownCounter** | Synchronous additive | Add(increment) | Sum | Per-request, part of a non-monotonic sum | @@ -11,7 +12,7 @@ #[derive(Clone, Debug, PartialEq, Hash)] pub enum InstrumentKind { /// A synchronous per-request recorder of non-additive measurements. - ValueRecorder, + Histogram, /// An asynchronous per-interval recorder of non-additive measurements. ValueObserver, /// A synchronous per-request part of a monotonic sum. @@ -29,7 +30,7 @@ impl InstrumentKind { pub fn synchronous(&self) -> bool { matches!( self, - InstrumentKind::Counter | InstrumentKind::UpDownCounter | InstrumentKind::ValueRecorder + InstrumentKind::Counter | InstrumentKind::UpDownCounter | InstrumentKind::Histogram ) } diff --git a/opentelemetry/src/metrics/meter.rs b/opentelemetry/src/metrics/meter.rs index 1103f22054..3394fd04f6 100644 --- a/opentelemetry/src/metrics/meter.rs +++ b/opentelemetry/src/metrics/meter.rs @@ -5,8 +5,8 @@ use crate::sdk::InstrumentationLibrary; use crate::{ metrics::{ sdk_api, AsyncRunner, BatchObserver, BatchObserverResult, CounterBuilder, Descriptor, - Measurement, NumberKind, ObserverResult, Result, SumObserverBuilder, UpDownCounterBuilder, - UpDownSumObserverBuilder, ValueObserverBuilder, ValueRecorderBuilder, + HistogramBuilder, Measurement, NumberKind, ObserverResult, Result, SumObserverBuilder, + UpDownCounterBuilder, UpDownSumObserverBuilder, ValueObserverBuilder, ValueRecorderBuilder, }, Context, KeyValue, }; @@ -35,6 +35,7 @@ pub trait MeterProvider: fmt::Debug { /// | ----------------------- | ----- | --------- | ------------- | --- | /// | **Counter** | Synchronous adding monotonic | Add(increment) | Sum | Per-request, part of a monotonic sum | /// | **UpDownCounter** | Synchronous adding | Add(increment) | Sum | Per-request, part of a non-monotonic sum | +/// | **Histogram** | Synchronous | Record(value) | Histogram Aggregation | Per-request, any grouping measurement | /// | **ValueRecorder** | Synchronous | Record(value) | [TBD issue 636](https://github.com/open-telemetry/opentelemetry-specification/issues/636) | Per-request, any grouping measurement | /// | **SumObserver** | Asynchronous adding monotonic | Observe(sum) | Sum | Per-interval, reporting a monotonic sum | /// | **UpDownSumObserver** | Asynchronous adding | Observe(sum) | Sum | Per-interval, reporting a non-monotonic sum | @@ -98,6 +99,7 @@ impl Meter { } /// Creates a new `ValueRecorderBuilder` for `i64` values with the given name. + #[deprecated(since = "0.18.0", note = "Please use i64_histogram instead.")] pub fn i64_value_recorder(&self, name: T) -> ValueRecorderBuilder<'_, i64> where T: Into, @@ -106,6 +108,7 @@ impl Meter { } /// Creates a new `ValueRecorderBuilder` for `u64` values with the given name. + #[deprecated(since = "0.18.0", note = "Please use u64_histogram instead.")] pub fn u64_value_recorder(&self, name: T) -> ValueRecorderBuilder<'_, u64> where T: Into, @@ -114,6 +117,7 @@ impl Meter { } /// Creates a new `ValueRecorderBuilder` for `f64` values with the given name. + #[deprecated(since = "0.18.0", note = "Please use f64_histogram instead.")] pub fn f64_value_recorder(&self, name: T) -> ValueRecorderBuilder<'_, f64> where T: Into, @@ -121,6 +125,30 @@ impl Meter { ValueRecorderBuilder::new(self, name.into(), NumberKind::F64) } + /// Creates a new `HistogramBuilder` for `i64` values with the given name. + pub fn i64_histogram(&self, name: T) -> HistogramBuilder<'_, i64> + where + T: Into, + { + HistogramBuilder::new(self, name.into(), NumberKind::I64) + } + + /// Creates a new `HistogramBuilder` for `u64` values with the given name. + pub fn u64_histogram(&self, name: T) -> HistogramBuilder<'_, u64> + where + T: Into, + { + HistogramBuilder::new(self, name.into(), NumberKind::U64) + } + + /// Creates a new `HistogramBuilder` for `f64` values with the given name. + pub fn f64_histogram(&self, name: T) -> HistogramBuilder<'_, f64> + where + T: Into, + { + HistogramBuilder::new(self, name.into(), NumberKind::F64) + } + /// Creates a new integer `SumObserverBuilder` for `u64` values with the given /// name and callback pub fn u64_sum_observer(&self, name: T, callback: F) -> SumObserverBuilder<'_, u64> diff --git a/opentelemetry/src/metrics/mod.rs b/opentelemetry/src/metrics/mod.rs index fe3c4d859e..b1f9d1ad76 100644 --- a/opentelemetry/src/metrics/mod.rs +++ b/opentelemetry/src/metrics/mod.rs @@ -9,6 +9,7 @@ mod async_instrument; mod config; mod counter; mod descriptor; +mod histogram; mod kind; mod meter; pub mod noop; @@ -25,6 +26,7 @@ pub use async_instrument::{AsyncRunner, BatchObserverResult, Observation, Observ pub use config::InstrumentConfig; pub use counter::{BoundCounter, Counter, CounterBuilder}; pub use descriptor::Descriptor; +pub use histogram::{BoundHistogram, Histogram, HistogramBuilder}; pub use kind::InstrumentKind; pub use meter::{Meter, MeterProvider}; pub use number::{AtomicNumber, Number, NumberKind}; diff --git a/opentelemetry/src/metrics/value_recorder.rs b/opentelemetry/src/metrics/value_recorder.rs index 6c083a793b..c46d78da79 100644 --- a/opentelemetry/src/metrics/value_recorder.rs +++ b/opentelemetry/src/metrics/value_recorder.rs @@ -67,7 +67,7 @@ impl<'a, T> ValueRecorderBuilder<'a, T> { name, meter.instrumentation_library().name, meter.instrumentation_library().version, - InstrumentKind::ValueRecorder, + InstrumentKind::Histogram, number_kind, ), _marker: marker::PhantomData, diff --git a/opentelemetry/src/sdk/export/metrics/mod.rs b/opentelemetry/src/sdk/export/metrics/mod.rs index 34a73d2adb..d78f2f248b 100644 --- a/opentelemetry/src/sdk/export/metrics/mod.rs +++ b/opentelemetry/src/sdk/export/metrics/mod.rs @@ -101,12 +101,12 @@ pub trait Checkpointer: LockedProcessor { /// Aggregator implements a specific aggregation behavior, i.e., a behavior to /// track a sequence of updates to an instrument. Sum-only instruments commonly /// use a simple Sum aggregator, but for the distribution instruments -/// (ValueRecorder, ValueObserver) there are a number of possible aggregators +/// (Histogram, ValueObserver) there are a number of possible aggregators /// with different cost and accuracy tradeoffs. /// /// Note that any Aggregator may be attached to any instrument--this is the /// result of the OpenTelemetry API/SDK separation. It is possible to attach a -/// Sum aggregator to a ValueRecorder instrument or a MinMaxSumCount aggregator +/// Sum aggregator to a Histogram instrument or a MinMaxSumCount aggregator /// to a Counter instrument. pub trait Aggregator: fmt::Debug { /// Update receives a new measured value and incorporates it into the @@ -399,7 +399,7 @@ impl ExportKind { /// Returns whether an exporter of this kind requires memory to export correctly. pub fn memory_required(&self, kind: &InstrumentKind) -> bool { match kind { - InstrumentKind::ValueRecorder + InstrumentKind::Histogram | InstrumentKind::ValueObserver | InstrumentKind::Counter | InstrumentKind::UpDownCounter => { diff --git a/opentelemetry/src/sdk/metrics/aggregators/ddsketch.rs b/opentelemetry/src/sdk/metrics/aggregators/ddsketch.rs index 6636b5a48d..93786c83af 100644 --- a/opentelemetry/src/sdk/metrics/aggregators/ddsketch.rs +++ b/opentelemetry/src/sdk/metrics/aggregators/ddsketch.rs @@ -694,7 +694,7 @@ mod tests { "test".to_string(), "test", None, - InstrumentKind::ValueRecorder, + InstrumentKind::Histogram, kind.clone(), ); @@ -835,7 +835,7 @@ mod tests { "test".to_string(), "test", None, - InstrumentKind::ValueRecorder, + InstrumentKind::Histogram, kind.clone(), ); for i in &dataset.data { diff --git a/opentelemetry/src/sdk/metrics/aggregators/mod.rs b/opentelemetry/src/sdk/metrics/aggregators/mod.rs index 2c328e34d2..f2b181bbdf 100644 --- a/opentelemetry/src/sdk/metrics/aggregators/mod.rs +++ b/opentelemetry/src/sdk/metrics/aggregators/mod.rs @@ -18,7 +18,7 @@ pub use sum::{sum, SumAggregator}; /// RangeTest is a common routine for testing for valid input values. This /// rejects NaN values. This rejects negative values when the metric instrument /// does not support negative values, including monotonic counter metrics and -/// absolute ValueRecorder metrics. +/// absolute Histogram metrics. pub fn range_test(number: &Number, descriptor: &Descriptor) -> Result<()> { if descriptor.number_kind() == &NumberKind::F64 && number.is_nan() { return Err(MetricsError::NaNInput); diff --git a/opentelemetry/src/sdk/metrics/selectors/simple.rs b/opentelemetry/src/sdk/metrics/selectors/simple.rs index 047017bb76..cbf9721a05 100644 --- a/opentelemetry/src/sdk/metrics/selectors/simple.rs +++ b/opentelemetry/src/sdk/metrics/selectors/simple.rs @@ -31,7 +31,7 @@ impl AggregatorSelector for Selector { match self { Selector::Sketch(config) => match descriptor.instrument_kind() { InstrumentKind::ValueObserver => Some(Arc::new(aggregators::last_value())), - InstrumentKind::ValueRecorder => Some(Arc::new(aggregators::ddsketch( + InstrumentKind::Histogram => Some(Arc::new(aggregators::ddsketch( config, descriptor.number_kind().clone(), ))), @@ -39,19 +39,19 @@ impl AggregatorSelector for Selector { }, Selector::Inexpensive => match descriptor.instrument_kind() { InstrumentKind::ValueObserver => Some(Arc::new(aggregators::last_value())), - InstrumentKind::ValueRecorder => { + InstrumentKind::Histogram => { Some(Arc::new(aggregators::min_max_sum_count(descriptor))) } _ => Some(Arc::new(aggregators::sum())), }, Selector::Exact => match descriptor.instrument_kind() { InstrumentKind::ValueObserver => Some(Arc::new(aggregators::last_value())), - InstrumentKind::ValueRecorder => Some(Arc::new(aggregators::array())), + InstrumentKind::Histogram => Some(Arc::new(aggregators::array())), _ => Some(Arc::new(aggregators::sum())), }, Selector::Histogram(boundaries) => match descriptor.instrument_kind() { InstrumentKind::ValueObserver => Some(Arc::new(aggregators::last_value())), - InstrumentKind::ValueRecorder => { + InstrumentKind::Histogram => { Some(Arc::new(aggregators::histogram(descriptor, boundaries))) } _ => Some(Arc::new(aggregators::sum())),