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 10, 2022
1 parent d818d9b commit 3cacf46
Show file tree
Hide file tree
Showing 16 changed files with 226 additions and 59 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
24 changes: 18 additions & 6 deletions examples/basic-otlp/src/main.rs
Expand Up @@ -77,16 +77,28 @@ 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();
another_recorder.record(5.5, COMMON_ATTRIBUTES.as_ref());
// 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();
Expand All @@ -100,7 +112,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 +121,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
2 changes: 1 addition & 1 deletion opentelemetry-dynatrace/tests/http_test.rs
Expand Up @@ -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);
Expand Down
18 changes: 9 additions & 9 deletions opentelemetry-prometheus/src/lib.rs
Expand Up @@ -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();
//!
Expand All @@ -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,
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(),
))
}
}

0 comments on commit 3cacf46

Please sign in to comment.