Skip to content

Commit

Permalink
Deprecate ValueRecorder in favor of Histogram
Browse files Browse the repository at this point in the history
The Metric API Spec is now stable and ValueRecorder was replaced with
Histogram.

* Deprecations - left structs unmarked as clippy threw a fit.
* Update all code examples to use Histograms.

Signed-off-by: Harold Dost <github@hdost.com>
  • Loading branch information
hdost committed Feb 9, 2022
1 parent d818d9b commit aa9fa19
Show file tree
Hide file tree
Showing 14 changed files with 203 additions and 48 deletions.
10 changes: 5 additions & 5 deletions examples/basic-otlp-with-selector/src/main.rs
Expand Up @@ -113,16 +113,16 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
.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(
Expand All @@ -135,7 +135,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
// 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| {
Expand All @@ -144,7 +144,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {

span.add_event("Sub span event".to_string(), vec![]);

value_recorder.record(1.3);
histogram.record(1.3);
});
});

Expand Down
10 changes: 5 additions & 5 deletions examples/basic-otlp/src/main.rs
Expand Up @@ -77,16 +77,16 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
.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();
Expand All @@ -100,7 +100,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
// 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| {
Expand All @@ -109,7 +109,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {

span.add_event("Sub span event".to_string(), vec![]);

value_recorder.record(1.3);
histogram.record(1.3);
});
});

Expand Down
8 changes: 4 additions & 4 deletions examples/basic/src/main.rs
Expand Up @@ -70,13 +70,13 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
.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();
Expand All @@ -90,7 +90,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
// 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| {
Expand All @@ -99,7 +99,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {

span.add_event("Sub span event".to_string(), vec![]);

value_recorder.record(1.3);
histogram.record(1.3);
});
});

Expand Down
10 changes: 5 additions & 5 deletions examples/dynatrace/src/main.rs
Expand Up @@ -140,16 +140,16 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
.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();
Expand All @@ -163,7 +163,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
// 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| {
Expand All @@ -172,7 +172,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {

span.add_event("Sub span event".to_string(), vec![]);

value_recorder.record(1.3);
histogram.record(1.3);
});
});

Expand Down
10 changes: 5 additions & 5 deletions examples/hyper-prometheus/src/main.rs
Expand Up @@ -8,7 +8,7 @@ use hyper::{
};
use opentelemetry::{
global,
metrics::{BoundCounter, BoundValueRecorder},
metrics::{BoundCounter, BoundHistogram},
KeyValue,
};
use opentelemetry_prometheus::PrometheusExporter;
Expand Down Expand Up @@ -63,8 +63,8 @@ async fn serve_req(
struct AppState {
exporter: PrometheusExporter,
http_counter: BoundCounter<u64>,
http_body_gauge: BoundValueRecorder<u64>,
http_req_histogram: BoundValueRecorder<f64>,
http_body_gauge: BoundHistogram<u64>,
http_req_histogram: BoundHistogram<f64>,
}

#[tokio::main]
Expand All @@ -80,12 +80,12 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
.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()),
Expand Down
30 changes: 15 additions & 15 deletions opentelemetry-prometheus/tests/integration_test.rs
Expand Up @@ -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")];

Expand All @@ -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);
Expand All @@ -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"#,
Expand Down
106 changes: 106 additions & 0 deletions 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<T>(SyncInstrument<T>);

impl<T> Histogram<T>
where
T: Into<Number>,
{
/// 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<T> {
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<T> {
bound_instrument: SyncBoundInstrument<T>,
}

impl<T> BoundHistogram<T>
where
T: Into<Number>,
{
/// 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<T>,
}

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<S: Into<String>>(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
}

/// Creates a new value recorder.
pub fn try_init(self) -> Result<Histogram<T>> {
let instrument = self.meter.new_sync_instrument(self.descriptor)?;
Ok(Histogram(SyncInstrument::new(instrument)))
}

/// Creates a new value recorder.
///
/// # Panics
///
/// This function panics if the instrument cannot be created. Use try_init if you want to
/// handle errors.
pub fn init(self) -> Histogram<T> {
Histogram(SyncInstrument::new(
self.meter.new_sync_instrument(self.descriptor).unwrap(),
))
}
}
11 changes: 9 additions & 2 deletions opentelemetry/src/metrics/kind.rs
Expand Up @@ -2,14 +2,18 @@
///
/// | **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 |
/// | **SumObserver** | Asynchronous additive monotonic | Observe(sum) | Sum | Per-interval, reporting a monotonic sum |
/// | **UpDownSumObserver** | Asynchronous additive | Observe(sum) | Sum | Per-interval, reporting a non-monotonic sum |
#[derive(Clone, Debug, PartialEq, Hash)]
pub enum InstrumentKind {
/// A synchronous per-request recorder of non-additive measurements.
Histogram,
/// Deprecated: Replaced by Histogram
/// A synchronous per-request recorder of non-additive measurements.
ValueRecorder,
/// An asynchronous per-interval recorder of non-additive measurements.
Expand All @@ -29,7 +33,10 @@ impl InstrumentKind {
pub fn synchronous(&self) -> bool {
matches!(
self,
InstrumentKind::Counter | InstrumentKind::UpDownCounter | InstrumentKind::ValueRecorder
InstrumentKind::Counter
| InstrumentKind::UpDownCounter
| InstrumentKind::ValueRecorder
| InstrumentKind::Histogram
)
}

Expand Down

0 comments on commit aa9fa19

Please sign in to comment.