1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
//! # OpenTelemetry Metrics API //! //! The user-facing metrics API supports producing diagnostic measurements //! using three basic kinds of instrument. "Metrics" are the thing being //! produced--mathematical, statistical summaries of certain observable //! behavior in the program. `Instrument`s are the devices used by the //! program to record observations about their behavior. Therefore, we use //! "metric instrument" to refer to a program object, allocated through the //! API, used for recording metrics. There are three distinct instruments //! in the Metrics API, commonly known as `Counter`s, `Gauge`s, and //! `Measure`s. //! //! Monitoring and alerting are the common use-case for the data provided //! through metric instruments, after various collection and aggregation //! strategies are applied to the data. We find there are many other uses //! for the metric events that stream into these instruments. We imagine //! metric data being aggregated and recorded as events in tracing and //! logging systems too, and for this reason OpenTelemetry requires a //! separation of the API from the SDK. //! //! To capture measurements using an `Instrument`, you need an SDK that //! implements the `Meter` API. //! //! ## Metric kinds and inputs //! //! The API distinguishes metric instruments by semantic meaning, not by //! the type of value produced in an exporter. This is a departure from //! convention, compared with a number of common metric libraries, and //! stems from the separation of the API and the SDK. The SDK ultimately //! determines how to handle metric events and could potentially implement //! non-standard behavior. //! //! This explains why the metric API does not have metric instrument kinds //! for exporting "Histogram" and "Summary" distribution explicitly, for //! example. These are both semantically `Measure` instruments and an SDK //! can be configured to produce histograms or distribution summaries from //! Measure events. It is out of scope for the Metrics API to specify how //! these alternatives are configured in a particular SDK. //! //! We believe the three metric kinds `Counter`, `Gauge`, and `Measure` //! form a sufficient basis for expression of a wide variety of metric data. //! Programmers write and read these as `add()`, `set()`, and `record()` //! method calls, signifying the semantics and standard interpretation, //! and we believe these three methods are all that are needed. //! //! Nevertheless, it is common to apply restrictions on metric values, the //! inputs to `add()`, `set()`, and `record()`, in order to refine their //! standard interpretation. Generally, there is a question of whether //! the instrument can be used to compute a rate, because that is usually //! a desirable analysis. Each metric instrument offers an optional //! declaration, specifying restrictions on values input to the metric. //! For example, Measures are declared as non-negative by default, //! appropriate for reporting sizes and durations; a Measure option is //! provided to record positive or negative values, but it does not change //! the kind of instrument or the method name used, as the semantics are //! unchanged. use crate::api; use std::sync::Arc; pub mod counter; pub mod gauge; pub mod measure; pub mod noop; pub mod value; use counter::Counter; use gauge::Gauge; use measure::Measure; use value::MeasurementValue; /// The implementation-level interface to Set/Add/Record individual /// metrics without precomputed labels. pub trait Instrument<LS> { /// Allows the SDK to observe a single metric event for a given set of labels. fn record_one(&self, value: MeasurementValue, label_set: &LS); } /// The implementation-level interface to Set/Add/Record individual /// metrics with precomputed labels. pub trait InstrumentHandle { /// Allows the SDK to observe a single metric event. fn record_one(&self, value: MeasurementValue); } /// `LabelSet` is an implementation-level interface that represents a /// set of `KeyValue` for use as pre-defined labels in the metrics API. pub trait LabelSet {} /// `MetricOptions` contains some options for metrics of any kind. #[derive(Default, Debug)] pub struct MetricOptions { /// Description is an optional field describing the metric instrument. pub description: String, /// Unit is an optional field describing the metric instrument. /// Valid values are specified according to the /// [UCUM](http://unitsofmeasure.org/ucum.html). pub unit: api::Unit, /// Keys are dimension names for the given metric. pub keys: Vec<api::Key>, /// Alternate defines the property of metric value dependent on /// a metric type. /// /// - for `Counter`, `true` implies that the metric is an up-down /// `Counter` /// /// - for `Gauge`, `true` implies that the metric is a /// non-descending `Gauge` /// /// - for `Measure`, `true` implies that the metric supports /// positive and negative values pub alternate: bool, } impl MetricOptions { /// Set a description for the current set of options. pub fn with_description<S: Into<String>>(self, description: S) -> Self { MetricOptions { description: description.into(), ..self } } /// Set a `Unit` for the current set of metric options. pub fn with_unit(self, unit: api::Unit) -> Self { MetricOptions { unit, ..self } } /// Set a list of `Key`s for the current set metric of options. pub fn with_keys(self, keys: Vec<api::Key>) -> Self { MetricOptions { keys, ..self } } /// Set monotonic for the given set of metric options. pub fn with_monotonic(self, _monotonic: bool) -> Self { // TODO figure out counter vs gauge issue here. unimplemented!() } /// Set absolute for the given set of metric options. pub fn with_absolute(self, absolute: bool) -> Self { MetricOptions { alternate: !absolute, ..self } } } /// Used to record `MeasurementValue`s for a given `Instrument` for use in /// batch recording by a `Meter`. #[allow(missing_debug_implementations)] pub struct Measurement<LS> { instrument: Arc<dyn Instrument<LS>>, value: MeasurementValue, } impl<LS: LabelSet> Measurement<LS> { /// Create a new measurement pub fn new(instrument: Arc<dyn Instrument<LS>>, value: MeasurementValue) -> Self { Measurement { instrument, value } } /// Returns an instrument that created this measurement. pub fn instrument(&self) -> Arc<dyn Instrument<LS>> { self.instrument.clone() } /// Returns a value recorded in this measurement. pub fn into_value(self) -> MeasurementValue { self.value } } /// Meter is an interface to the metrics portion of the OpenTelemetry SDK. /// /// The Meter interface allows creating of a registered metric instrument using methods specific to /// each kind of metric. There are six constructors representing the three kinds of instrument /// taking either floating point or integer inputs, see the detailed design below. /// /// Binding instruments to a single Meter instance has two benefits: /// /// 1. Instruments can be exported from the zero state, prior to first use, with no explicit /// Register call /// 2. The component name provided by the named Meter satisfies a namespace requirement /// /// The recommended practice is to define structures to contain the instruments in use and keep /// references only to the instruments that are specifically needed. /// /// We recognize that many existing metric systems support allocating metric instruments statically /// and providing the Meter interface at the time of use. In this example, typical of statsd /// clients, existing code may not be structured with a convenient place to store new metric /// instruments. Where this becomes a burden, it is recommended to use the global meter factory to /// construct a static named Meter, to construct metric instruments. /// /// The situation is similar for users of Prometheus clients, where instruments are allocated /// statically and there is an implicit global. Such code may not have access to the appropriate /// Meter where instruments are defined. Where this becomes a burden, it is recommended to use the /// global meter factory to construct a static named Meter, to construct metric instruments. /// /// Applications are expected to construct long-lived instruments. Instruments are considered /// permanent for the lifetime of a SDK, there is no method to delete them. pub trait Meter { /// The `LabelSet` data type for this meter. type LabelSet: LabelSet; /// The `I64Counter` data type for this meter. type I64Counter: Counter<i64, Self::LabelSet>; /// The `F64Counter` data type for this meter. type F64Counter: Counter<f64, Self::LabelSet>; /// The `I64Gauge` data type for this meter. type I64Gauge: Gauge<i64, Self::LabelSet>; /// The `F64Gauge` data type for this meter. type F64Gauge: Gauge<f64, Self::LabelSet>; /// The `I64Measure` data type for this meter. type I64Measure: Measure<i64, Self::LabelSet>; /// The `F64Measure` data type for this meter. type F64Measure: Measure<f64, Self::LabelSet>; /// Returns a reference to a set of labels that cannot be read by the application. fn labels(&self, key_values: Vec<api::KeyValue>) -> Self::LabelSet; /// Creates a new `i64` counter with a given name and customized with passed options. fn new_i64_counter<S: Into<String>>(&self, name: S, opts: MetricOptions) -> Self::I64Counter; /// Creates a new `f64` counter with a given name and customized with passed options. fn new_f64_counter<S: Into<String>>(&self, name: S, opts: MetricOptions) -> Self::F64Counter; /// Creates a new `i64` gauge with a given name and customized with passed options. fn new_i64_gauge<S: Into<String>>(&self, name: S, opts: MetricOptions) -> Self::I64Gauge; /// Creates a new `f64` gauge with a given name and customized with passed options. fn new_f64_gauge<S: Into<String>>(&self, name: S, opts: MetricOptions) -> Self::F64Gauge; /// Creates a new `i64` measure with a given name and customized with passed options. fn new_i64_measure<S: Into<String>>(&self, name: S, opts: MetricOptions) -> Self::I64Measure; /// Creates a new `f64` measure with a given name and customized with passed options. fn new_f64_measure<S: Into<String>>(&self, name: S, opts: MetricOptions) -> Self::F64Measure; /// Atomically records a batch of measurements. fn record_batch<M: IntoIterator<Item = Measurement<Self::LabelSet>>>( &self, label_set: &Self::LabelSet, measurements: M, ); }