apollo-opentelemetry 0.8.0

OpenTelemetry configuration types for Apollo platform
Documentation
//! RAII guards for recording metrics that span asynchronous operations.
//!
//! In async Rust, a future can be cancelled at any `.await` point — for example, when a request
//! times out or a client disconnects. Metrics recorded only on the success path are silently
//! dropped, leaving gaps in observability. These guards ensure metrics are always recorded when
//! a scope exits, regardless of how it exits.
//!
//! # Guards
//!
//! Four guards are available, each accessed via an extension trait on the corresponding
//! OpenTelemetry instrument type. Import the traits you need:
//!
//! ```
//! use apollo_opentelemetry::metrics::{CounterExt, FutureExt, HistogramExt, UpDownCounterExt};
//! ```
//!
//! - [`track`](UpDownCounterExt::track) — increments an `UpDownCounter` on entry and
//!   decrements it on drop. Use this to track concurrent operations such as active connections
//!   or in-flight requests.
//!
//! - [`record_duration_on_drop`](HistogramExt::record_duration_on_drop) — starts a timer on
//!   entry and records elapsed seconds to a `Histogram<f64>` on drop. Use this for operation
//!   latency.
//!
//! - [`record_on_drop`](HistogramExt::record_on_drop) — records a value to a `Histogram` on
//!   drop. Use this for metrics whose value is only known at the end of an operation, such as
//!   response body size.
//!
//! - [`add_on_drop`](CounterExt::add_on_drop) — adds a value to a `Counter` on drop. Use this
//!   to count completed operations or bytes transferred.
//!
//! In addition, [`with_guard`](FutureExt::with_guard) is available on any `Future` and ties a
//! guard's lifetime to that future — the guard drops when the future resolves or is cancelled.
//!
//! # Example
//!
//! ```
//! use opentelemetry::KeyValue;
//! use opentelemetry::metrics::{Counter, Histogram, UpDownCounter};
//! use apollo_opentelemetry::metrics::{CounterExt, HistogramExt, UpDownCounterExt};
//! # async fn read_body() -> usize { 1024 }
//!
//! async fn handle_request(
//!     active_requests: UpDownCounter<i64>,
//!     request_duration: Histogram<f64>,
//!     response_size: Histogram<f64>,
//!     bytes_sent: Counter<u64>,
//! ) {
//!     // Increments immediately; decrements when this guard is dropped.
//!     let _active = active_requests.track([KeyValue::new("service", "api")]);
//!
//!     // Timer starts now; elapsed time is recorded when this guard is dropped.
//!     let mut timer = request_duration.record_duration_on_drop([KeyValue::new("http.method", "GET")]);
//!
//!     // Value recorded on drop — body size is not yet known.
//!     let mut size = response_size.record_on_drop(0.0, []);
//!
//!     // Counter incremented on drop.
//!     let bytes = bytes_sent.add_on_drop(0, []);
//!
//!     let body_bytes = read_body().await; // future may be cancelled here — all guards still record on drop
//!
//!     // Outcome attributes and final values set after the await.
//!     timer.set(KeyValue::new("http.status", 200_i64));
//!     size.value(body_bytes as f64);
//!     drop(bytes); // already holds the right value
//! }
//! # fn main() {}
//! ```
//!
//! # Setting attributes
//!
//! Attributes known upfront — such as HTTP method or service name — are passed at construction.
//! Attributes that depend on the outcome — such as a status code or error type — are set
//! afterwards via [`set`](RecordDurationGuard::set). This ensures the metric is always recorded
//! with the correct attributes even if the future is cancelled before reaching the `set` call,
//! in which case the metric is recorded with only the attributes provided at construction.
//!
//! ```
//! # use opentelemetry::metrics::Histogram;
//! # use opentelemetry::KeyValue;
//! # use apollo_opentelemetry::metrics::HistogramExt;
//! # async fn process() -> Result<(), ()> { Ok(()) }
//! async fn handle(histogram: Histogram<f64>) {
//!     let mut timer = histogram.record_duration_on_drop([KeyValue::new("http.method", "POST")]);
//!
//!     let result = process().await; // may be cancelled here
//!
//!     let status = if result.is_ok() { 200_i64 } else { 500_i64 };
//!     timer.set(KeyValue::new("http.status", status));
//! }
//! # fn main() {}
//! ```
//!
//! # Cancellation
//!
//! Call [`cancel`](RecordDurationGuard::cancel) to suppress recording entirely. This is useful
//! when an error or early-exit path should not contribute to a metric, or when a more specific
//! guard takes over on the success path.
//!
//! ```
//! # use opentelemetry::metrics::Histogram;
//! # use apollo_opentelemetry::metrics::HistogramExt;
//! # async fn process() -> bool { true }
//! async fn handle(histogram: Histogram<f64>) {
//!     let mut timer = histogram.record_duration_on_drop([]);
//!
//!     let success = process().await; // may be cancelled here
//!
//!     if !success {
//!         timer.cancel(); // don't record failed attempts
//!     }
//! }
//! # fn main() {}
//! ```

mod counter;
mod duration_histogram;
mod ext;
mod future;
mod histogram;
mod up_down_counter;

pub use counter::AddValueGuard;
pub use duration_histogram::RecordDurationGuard;
pub use ext::{CounterExt, HistogramExt, UpDownCounterExt};
pub use future::{FutureExt, WithGuard};
pub use histogram::RecordValueGuard;
/// Clock used to measure elapsed time in [`RecordDurationGuard`].
///
/// In tests, use [`Clock::mock`] to control time:
///
/// ```
/// # use std::time::Duration;
/// # use opentelemetry::global;
/// # use apollo_opentelemetry::metrics::{Clock, HistogramExt};
/// # let histogram = global::meter_provider().meter("example").f64_histogram("request.duration").build();
/// let (clock, mock) = Clock::mock();
/// let _guard = histogram.record_duration_on_drop_with_clock(clock, []);
/// mock.increment(Duration::from_millis(500));
/// // guard records 0.5s on drop
/// ```
pub use quanta::Clock;
pub use up_down_counter::TrackGuard;