You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by xu...@apache.org on 2025/03/28 05:05:49 UTC
(opendal) branch main updated: refactor(layer/otelmetrics): Migrate OtelMetricsLayer to support IO metrics (#5901)
This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git
The following commit(s) were added to refs/heads/main by this push:
new 9731a7a3b refactor(layer/otelmetrics): Migrate OtelMetricsLayer to support IO metrics (#5901)
9731a7a3b is described below
commit 9731a7a3b8ce981f752905f36c628d22fecd125a
Author: Qinxuan Chen <ko...@gmail.com>
AuthorDate: Fri Mar 28 13:05:44 2025 +0800
refactor(layer/otelmetrics): Migrate OtelMetricsLayer to support IO metrics (#5901)
* refactor(layer/otelmetrics): Migrate OtelMetricsLayer to support IO metrics
* return Vec<f64> instead of iterator
* cleanup
* specify name explictly
* remove exponential_boundaries
---
core/src/layers/observe/metrics.rs | 50 ----
core/src/layers/observe/mod.rs | 41 ---
core/src/layers/otelmetrics.rs | 589 ++++++++++++++++++++-----------------
core/src/layers/prometheus.rs | 6 -
4 files changed, 326 insertions(+), 360 deletions(-)
diff --git a/core/src/layers/observe/metrics.rs b/core/src/layers/observe/metrics.rs
index e8d165713..d908ce61e 100644
--- a/core/src/layers/observe/metrics.rs
+++ b/core/src/layers/observe/metrics.rs
@@ -133,8 +133,6 @@ pub static LABEL_ROOT: &str = "root";
pub static LABEL_OPERATION: &str = "operation";
/// The metric label for the error.
pub static LABEL_ERROR: &str = "error";
-/// The metrics label for the path. (will be removed)
-pub static LABEL_PATH: &str = "path";
/// The metric label for the http code.
pub static LABEL_STATUS_CODE: &str = "status_code";
@@ -395,54 +393,6 @@ pub trait MetricsIntercept: Debug + Clone + Send + Sync + Unpin + 'static {
fn observe(&self, labels: MetricLabels, value: MetricValue) {
let _ = (labels, value);
}
-
- /// Observe the operation duration in seconds.
- fn observe_operation_duration_seconds(
- &self,
- info: Arc<AccessorInfo>,
- path: &str,
- op: Operation,
- duration: Duration,
- ) {
- let _ = (info, path, op, duration);
- }
-
- /// Observe the operation bytes happened in IO like read and write.
- fn observe_operation_bytes(
- &self,
- info: Arc<AccessorInfo>,
- path: &str,
- op: Operation,
- bytes: usize,
- ) {
- let _ = (info, path, op, bytes);
- }
-
- /// Observe the operation errors total.
- fn observe_operation_errors_total(
- &self,
- info: Arc<AccessorInfo>,
- path: &str,
- op: Operation,
- error: ErrorKind,
- ) {
- let _ = (info, path, op, error);
- }
-
- /// Observe the http request duration in seconds.
- fn observe_http_request_duration_seconds(
- &self,
- info: Arc<AccessorInfo>,
- op: Operation,
- duration: Duration,
- ) {
- let _ = (info, op, duration);
- }
-
- /// Observe the operation bytes happened in http request like read and write.
- fn observe_http_request_bytes(&self, info: Arc<AccessorInfo>, op: Operation, bytes: usize) {
- let _ = (info, op, bytes);
- }
}
/// The metrics layer for opendal.
diff --git a/core/src/layers/observe/mod.rs b/core/src/layers/observe/mod.rs
index dd8185ef6..86959b3ca 100644
--- a/core/src/layers/observe/mod.rs
+++ b/core/src/layers/observe/mod.rs
@@ -89,7 +89,6 @@ pub use metrics::DEFAULT_TTFB_BUCKETS;
pub use metrics::LABEL_ERROR;
pub use metrics::LABEL_NAMESPACE;
pub use metrics::LABEL_OPERATION;
-pub use metrics::LABEL_PATH;
pub use metrics::LABEL_ROOT;
pub use metrics::LABEL_SCHEME;
pub use metrics::LABEL_STATUS_CODE;
@@ -98,43 +97,3 @@ pub use metrics::METRIC_HTTP_REQUEST_DURATION_SECONDS;
pub use metrics::METRIC_OPERATION_BYTES;
pub use metrics::METRIC_OPERATION_DURATION_SECONDS;
pub use metrics::METRIC_OPERATION_ERRORS_TOTAL;
-
-/// Return the path label value according to the given `path` and `level`.
-///
-/// - level = 0: return `None`, which means we ignore the path label.
-/// - level > 0: the path label will be the path split by "/" and get the last n level,
-/// if n=1 and input path is "abc/def/ghi", and then we'll use "abc/" as the path label.
-pub fn path_label_value(path: &str, level: usize) -> Option<&str> {
- if level > 0 {
- if path.is_empty() {
- return Some("");
- }
-
- let label_value = path
- .char_indices()
- .filter(|&(_, c)| c == '/')
- .nth(level - 1)
- .map_or(path, |(i, _)| &path[..i]);
- Some(label_value)
- } else {
- None
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_path_label_value() {
- let path = "abc/def/ghi";
- assert_eq!(path_label_value(path, 0), None);
- assert_eq!(path_label_value(path, 1), Some("abc"));
- assert_eq!(path_label_value(path, 2), Some("abc/def"));
- assert_eq!(path_label_value(path, 3), Some("abc/def/ghi"));
- assert_eq!(path_label_value(path, usize::MAX), Some("abc/def/ghi"));
-
- assert_eq!(path_label_value("", 0), None);
- assert_eq!(path_label_value("", 1), Some(""));
- }
-}
diff --git a/core/src/layers/otelmetrics.rs b/core/src/layers/otelmetrics.rs
index ffac5fc1c..3f3ca4121 100644
--- a/core/src/layers/otelmetrics.rs
+++ b/core/src/layers/otelmetrics.rs
@@ -15,17 +15,16 @@
// specific language governing permissions and limitations
// under the License.
-use std::sync::Arc;
use std::time::Duration;
use opentelemetry::metrics::Counter;
use opentelemetry::metrics::Histogram;
use opentelemetry::metrics::Meter;
+use opentelemetry::metrics::UpDownCounter;
use opentelemetry::KeyValue;
use crate::layers::observe;
use crate::raw::*;
-use crate::*;
/// Add [opentelemetry::metrics](https://docs.rs/opentelemetry/latest/opentelemetry/metrics/index.html) for every operation.
///
@@ -53,10 +52,6 @@ pub struct OtelMetricsLayer {
impl OtelMetricsLayer {
/// Create a [`OtelMetricsLayerBuilder`] to set the configuration of metrics.
///
- /// # Default Configuration
- ///
- /// - `path_label`: `0`
- ///
/// # Examples
///
/// ```no_run
@@ -69,196 +64,85 @@ impl OtelMetricsLayer {
/// # async fn main() -> Result<()> {
/// let meter = opentelemetry::global::meter("opendal");
/// let op = Operator::new(services::Memory::default())?
- /// .layer(OtelMetricsLayer::builder().path_label(1).register(&meter))
+ /// .layer(OtelMetricsLayer::builder().register(&meter))
/// .finish();
///
/// Ok(())
/// # }
/// ```
pub fn builder() -> OtelMetricsLayerBuilder {
- OtelMetricsLayerBuilder::new()
+ OtelMetricsLayerBuilder::default()
}
}
/// [`OtelMetricsLayerBuilder`] is a config builder to build a [`OtelMetricsLayer`].
pub struct OtelMetricsLayerBuilder {
- operation_duration_seconds_boundaries: Vec<f64>,
- operation_bytes_boundaries: Vec<f64>,
- http_request_duration_seconds_boundaries: Vec<f64>,
- http_request_bytes_boundaries: Vec<f64>,
- path_label_level: usize,
+ bytes_boundaries: Vec<f64>,
+ bytes_rate_boundaries: Vec<f64>,
+ entries_boundaries: Vec<f64>,
+ entries_rate_boundaries: Vec<f64>,
+ duration_seconds_boundaries: Vec<f64>,
+ ttfb_boundaries: Vec<f64>,
}
-impl OtelMetricsLayerBuilder {
- fn new() -> Self {
+impl Default for OtelMetricsLayerBuilder {
+ fn default() -> Self {
Self {
- operation_duration_seconds_boundaries: exponential_boundary(0.01, 2.0, 16),
- operation_bytes_boundaries: exponential_boundary(1.0, 2.0, 16),
- http_request_duration_seconds_boundaries: exponential_boundary(0.01, 2.0, 16),
- http_request_bytes_boundaries: exponential_boundary(1.0, 2.0, 16),
- path_label_level: 0,
+ bytes_boundaries: observe::DEFAULT_BYTES_BUCKETS.to_vec(),
+ bytes_rate_boundaries: observe::DEFAULT_BYTES_RATE_BUCKETS.to_vec(),
+ entries_boundaries: observe::DEFAULT_ENTRIES_BUCKETS.to_vec(),
+ entries_rate_boundaries: observe::DEFAULT_ENTRIES_RATE_BUCKETS.to_vec(),
+ duration_seconds_boundaries: observe::DEFAULT_DURATION_SECONDS_BUCKETS.to_vec(),
+ ttfb_boundaries: observe::DEFAULT_TTFB_BUCKETS.to_vec(),
}
}
+}
- /// Set the level of path label.
- ///
- /// - level = 0: we will ignore the path label.
- /// - level > 0: the path label will be the path split by "/" and get the last n level,
- /// if n=1 and input path is "abc/def/ghi", and then we will get "abc/" as the path label.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// # use log::debug;
- /// # use opendal::layers::OtelMetricsLayer;
- /// # use opendal::services;
- /// # use opendal::Operator;
- /// # use opendal::Result;
- ///
- /// # #[tokio::main]
- /// # async fn main() -> Result<()> {
- /// let meter = opentelemetry::global::meter("opendal");
- /// let op = Operator::new(services::Memory::default())?
- /// .layer(OtelMetricsLayer::builder().path_label(1).register(&meter))
- /// .finish();
- /// debug!("operator: {op:?}");
- ///
- /// Ok(())
- /// # }
- /// ```
- pub fn path_label(mut self, level: usize) -> Self {
- self.path_label_level = level;
+impl OtelMetricsLayerBuilder {
+ /// Set boundaries for bytes related histogram like `operation_bytes`.
+ pub fn bytes_boundaries(mut self, boundaries: Vec<f64>) -> Self {
+ if !boundaries.is_empty() {
+ self.bytes_boundaries = boundaries;
+ }
self
}
- /// Set boundaries for `operation_duration_seconds` histogram.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// # use log::debug;
- /// # use opendal::layers::OtelMetricsLayer;
- /// # use opendal::services;
- /// # use opendal::Operator;
- /// # use opendal::Result;
- ///
- /// # #[tokio::main]
- /// # async fn main() -> Result<()> {
- /// let meter = opentelemetry::global::meter("opendal");
- /// let op = Operator::new(services::Memory::default())?
- /// .layer(
- /// OtelMetricsLayer::builder()
- /// .operation_duration_seconds_boundaries(vec![0.01, 0.02, 0.05, 0.1, 0.2, 0.5])
- /// .register(&meter)
- /// )
- /// .finish();
- /// debug!("operator: {op:?}");
- ///
- /// Ok(())
- /// # }
- /// ```
- pub fn operation_duration_seconds_boundaries(mut self, boundaries: Vec<f64>) -> Self {
+ /// Set boundaries for bytes rate related histogram like `operation_bytes_rate`.
+ pub fn bytes_rate_boundaries(mut self, boundaries: Vec<f64>) -> Self {
if !boundaries.is_empty() {
- self.operation_duration_seconds_boundaries = boundaries;
+ self.bytes_rate_boundaries = boundaries;
}
self
}
- /// Set boundaries for `operation_bytes` histogram.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// # use log::debug;
- /// # use opendal::layers::OtelMetricsLayer;
- /// # use opendal::services;
- /// # use opendal::Operator;
- /// # use opendal::Result;
- ///
- /// # #[tokio::main]
- /// # async fn main() -> Result<()> {
- /// let meter = opentelemetry::global::meter("opendal");
- /// let op = Operator::new(services::Memory::default())?
- /// .layer(
- /// OtelMetricsLayer::builder()
- /// .operation_bytes_boundaries(vec![1.0, 2.0, 5.0, 10.0, 20.0, 50.0])
- /// .register(&meter)
- /// )
- /// .finish();
- /// debug!("operator: {op:?}");
- ///
- /// Ok(())
- /// # }
- /// ```
- pub fn operation_bytes_boundaries(mut self, boundaries: Vec<f64>) -> Self {
+ /// Set boundaries for entries related histogram like `operation_entries`.
+ pub fn entries_boundaries(mut self, boundaries: Vec<f64>) -> Self {
if !boundaries.is_empty() {
- self.operation_bytes_boundaries = boundaries;
+ self.entries_boundaries = boundaries;
}
self
}
- /// Set boundaries for `http_request_duration_seconds` histogram.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// # use log::debug;
- /// # use opendal::layers::OtelMetricsLayer;
- /// # use opendal::services;
- /// # use opendal::Operator;
- /// # use opendal::Result;
- ///
- /// # #[tokio::main]
- /// # async fn main() -> Result<()> {
- /// let meter = opentelemetry::global::meter("opendal");
- /// let op = Operator::new(services::Memory::default())?
- /// .layer(
- /// OtelMetricsLayer::builder()
- /// .http_request_duration_seconds_boundaries(vec![0.01, 0.02, 0.05, 0.1, 0.2, 0.5])
- /// .register(&meter)
- /// )
- /// .finish();
- /// debug!("operator: {op:?}");
- ///
- /// Ok(())
- /// # }
- /// ```
- pub fn http_request_duration_seconds_boundaries(mut self, boundaries: Vec<f64>) -> Self {
+ /// Set boundaries for entries rate related histogram like `operation_entries_rate`.
+ pub fn entries_rate_boundaries(mut self, boundaries: Vec<f64>) -> Self {
if !boundaries.is_empty() {
- self.http_request_duration_seconds_boundaries = boundaries;
+ self.entries_rate_boundaries = boundaries;
}
self
}
- /// Set boundaries for `http_request_bytes` histogram.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// # use log::debug;
- /// # use opendal::layers::OtelMetricsLayer;
- /// # use opendal::services;
- /// # use opendal::Operator;
- /// # use opendal::Result;
- ///
- /// # #[tokio::main]
- /// # async fn main() -> Result<()> {
- /// let meter = opentelemetry::global::meter("opendal");
- /// let op = Operator::new(services::Memory::default())?
- /// .layer(
- /// OtelMetricsLayer::builder()
- /// .http_request_bytes_boundaries(vec![1.0, 2.0, 5.0, 10.0, 20.0, 50.0])
- /// .register(&meter)
- /// )
- /// .finish();
- /// debug!("operator: {op:?}");
- ///
- /// Ok(())
- /// # }
- /// ```
- pub fn http_request_bytes_boundaries(mut self, boundaries: Vec<f64>) -> Self {
+ /// Set boundaries for duration seconds related histogram like `operation_duration_seconds`.
+ pub fn duration_seconds_boundaries(mut self, boundaries: Vec<f64>) -> Self {
if !boundaries.is_empty() {
- self.http_request_bytes_boundaries = boundaries;
+ self.duration_seconds_boundaries = boundaries;
+ }
+ self
+ }
+
+ /// Set boundaries for ttfb related histogram like `operation_ttfb_seconds`.
+ pub fn ttfb_boundaries(mut self, boundaries: Vec<f64>) -> Self {
+ if !boundaries.is_empty() {
+ self.ttfb_boundaries = boundaries;
}
self
}
@@ -277,48 +161,179 @@ impl OtelMetricsLayerBuilder {
/// # async fn main() -> Result<()> {
/// let meter = opentelemetry::global::meter("opendal");
/// let op = Operator::new(services::Memory::default())?
- /// .layer(OtelMetricsLayer::builder().register(&meter))
+ /// .layer(OtelMetricsLayer::builder()
+ /// .register(&meter))
/// .finish();
///
/// Ok(())
/// # }
/// ```
pub fn register(self, meter: &Meter) -> OtelMetricsLayer {
- let operation_duration_seconds = meter
- .f64_histogram("opendal.operation.duration")
- .with_description("Duration of operations")
- .with_unit("second")
- .with_boundaries(self.operation_duration_seconds_boundaries)
- .build();
- let operation_bytes = meter
- .u64_histogram("opendal.operation.size")
- .with_description("Size of operations")
- .with_unit("byte")
- .with_boundaries(self.operation_bytes_boundaries)
- .build();
- let http_request_duration_seconds = meter
- .f64_histogram("opendal.http.request.duration")
- .with_description("Duration of http requests")
- .with_unit("second")
- .build();
- let http_request_bytes = meter
- .u64_histogram("opendal.http.request.size")
- .with_description("Size of http requests")
- .with_unit("byte")
- .build();
- let errors = meter
- .u64_counter("opendal.operation.errors")
- .with_description("Number of operation errors")
- .build();
+ let operation_bytes = {
+ let metric = observe::MetricValue::OperationBytes(0);
+ register_u64_histogram_meter(
+ meter,
+ "opendal.operation.bytes",
+ metric,
+ self.bytes_boundaries.clone(),
+ )
+ };
+ let operation_bytes_rate = {
+ let metric = observe::MetricValue::OperationBytesRate(0.0);
+ register_f64_histogram_meter(
+ meter,
+ "opendal.operation.bytes_rate",
+ metric,
+ self.bytes_rate_boundaries.clone(),
+ )
+ };
+ let operation_entries = {
+ let metric = observe::MetricValue::OperationEntries(0);
+ register_u64_histogram_meter(
+ meter,
+ "opendal.operation.entries",
+ metric,
+ self.entries_boundaries.clone(),
+ )
+ };
+ let operation_entries_rate = {
+ let metric = observe::MetricValue::OperationEntriesRate(0.0);
+ register_f64_histogram_meter(
+ meter,
+ "opendal.operation.entries_rate",
+ metric,
+ self.entries_rate_boundaries.clone(),
+ )
+ };
+ let operation_duration_seconds = {
+ let metric = observe::MetricValue::OperationDurationSeconds(Duration::default());
+ register_f64_histogram_meter(
+ meter,
+ "opendal.operation.duration",
+ metric,
+ self.duration_seconds_boundaries.clone(),
+ )
+ };
+ let operation_errors_total = {
+ let metric = observe::MetricValue::OperationErrorsTotal;
+ meter
+ .u64_counter("opendal.operation.errors")
+ .with_description(metric.help())
+ .build()
+ };
+ let operation_executing = {
+ let metric = observe::MetricValue::OperationExecuting(0);
+ meter
+ .i64_up_down_counter("opendal.operation.executing")
+ .with_description(metric.help())
+ .build()
+ };
+ let operation_ttfb_seconds = {
+ let metric = observe::MetricValue::OperationTtfbSeconds(Duration::default());
+ register_f64_histogram_meter(
+ meter,
+ "opendal.operation.ttfb",
+ metric,
+ self.duration_seconds_boundaries.clone(),
+ )
+ };
+
+ let http_executing = {
+ let metric = observe::MetricValue::HttpExecuting(0);
+ meter
+ .i64_up_down_counter("opendal.http.executing")
+ .with_description(metric.help())
+ .build()
+ };
+ let http_request_bytes = {
+ let metric = observe::MetricValue::HttpRequestBytes(0);
+ register_u64_histogram_meter(
+ meter,
+ "opendal.http.request.bytes",
+ metric,
+ self.bytes_boundaries.clone(),
+ )
+ };
+ let http_request_bytes_rate = {
+ let metric = observe::MetricValue::HttpRequestBytesRate(0.0);
+ register_f64_histogram_meter(
+ meter,
+ "opendal.http.request.bytes_rate",
+ metric,
+ self.bytes_rate_boundaries.clone(),
+ )
+ };
+ let http_request_duration_seconds = {
+ let metric = observe::MetricValue::HttpRequestDurationSeconds(Duration::default());
+ register_f64_histogram_meter(
+ meter,
+ "opendal.http.request.duration",
+ metric,
+ self.duration_seconds_boundaries.clone(),
+ )
+ };
+ let http_response_bytes = {
+ let metric = observe::MetricValue::HttpResponseBytes(0);
+ register_u64_histogram_meter(
+ meter,
+ "opendal.http.response.bytes",
+ metric,
+ self.bytes_boundaries.clone(),
+ )
+ };
+ let http_response_bytes_rate = {
+ let metric = observe::MetricValue::HttpResponseBytesRate(0.0);
+ register_f64_histogram_meter(
+ meter,
+ "opendal.http.response.bytes_rate",
+ metric,
+ self.bytes_rate_boundaries.clone(),
+ )
+ };
+ let http_response_duration_seconds = {
+ let metric = observe::MetricValue::HttpResponseDurationSeconds(Duration::default());
+ register_f64_histogram_meter(
+ meter,
+ "opendal.http.response.duration",
+ metric,
+ self.duration_seconds_boundaries.clone(),
+ )
+ };
+ let http_connection_errors_total = {
+ let metric = observe::MetricValue::HttpConnectionErrorsTotal;
+ meter
+ .u64_counter("opendal.http.connection_errors")
+ .with_description(metric.help())
+ .build()
+ };
+ let http_status_errors_total = {
+ let metric = observe::MetricValue::HttpStatusErrorsTotal;
+ meter
+ .u64_counter("opendal.http.status_errors")
+ .with_description(metric.help())
+ .build()
+ };
OtelMetricsLayer {
interceptor: OtelMetricsInterceptor {
- operation_duration_seconds,
operation_bytes,
- http_request_duration_seconds,
+ operation_bytes_rate,
+ operation_entries,
+ operation_entries_rate,
+ operation_duration_seconds,
+ operation_errors_total,
+ operation_executing,
+ operation_ttfb_seconds,
+
+ http_executing,
http_request_bytes,
- errors,
- path_label_level: self.path_label_level,
+ http_request_bytes_rate,
+ http_request_duration_seconds,
+ http_response_bytes,
+ http_response_bytes_rate,
+ http_response_duration_seconds,
+ http_connection_errors_total,
+ http_status_errors_total,
},
}
}
@@ -334,101 +349,149 @@ impl<A: Access> Layer<A> for OtelMetricsLayer {
#[derive(Clone, Debug)]
pub struct OtelMetricsInterceptor {
- operation_duration_seconds: Histogram<f64>,
operation_bytes: Histogram<u64>,
- http_request_duration_seconds: Histogram<f64>,
+ operation_bytes_rate: Histogram<f64>,
+ operation_entries: Histogram<u64>,
+ operation_entries_rate: Histogram<f64>,
+ operation_duration_seconds: Histogram<f64>,
+ operation_errors_total: Counter<u64>,
+ operation_executing: UpDownCounter<i64>,
+ operation_ttfb_seconds: Histogram<f64>,
+
+ http_executing: UpDownCounter<i64>,
http_request_bytes: Histogram<u64>,
- errors: Counter<u64>,
- path_label_level: usize,
+ http_request_bytes_rate: Histogram<f64>,
+ http_request_duration_seconds: Histogram<f64>,
+ http_response_bytes: Histogram<u64>,
+ http_response_bytes_rate: Histogram<f64>,
+ http_response_duration_seconds: Histogram<f64>,
+ http_connection_errors_total: Counter<u64>,
+ http_status_errors_total: Counter<u64>,
}
impl observe::MetricsIntercept for OtelMetricsInterceptor {
- fn observe_operation_duration_seconds(
- &self,
- info: Arc<AccessorInfo>,
- path: &str,
- op: Operation,
- duration: Duration,
- ) {
- let attributes = self.create_attributes(info, path, op, None);
- self.operation_duration_seconds
- .record(duration.as_secs_f64(), &attributes);
- }
-
- fn observe_operation_bytes(
- &self,
- info: Arc<AccessorInfo>,
- path: &str,
- op: Operation,
- bytes: usize,
- ) {
- let attributes = self.create_attributes(info, path, op, None);
- self.operation_bytes.record(bytes as u64, &attributes);
- }
-
- fn observe_operation_errors_total(
- &self,
- info: Arc<AccessorInfo>,
- path: &str,
- op: Operation,
- error: ErrorKind,
- ) {
- let attributes = self.create_attributes(info, path, op, Some(error));
- self.errors.add(1, &attributes);
- }
+ fn observe(&self, labels: observe::MetricLabels, value: observe::MetricValue) {
+ let attributes = self.create_attributes(labels);
- fn observe_http_request_duration_seconds(
- &self,
- info: Arc<AccessorInfo>,
- op: Operation,
- duration: Duration,
- ) {
- let attributes = self.create_attributes(info, "", op, None);
- self.http_request_duration_seconds
- .record(duration.as_secs_f64(), &attributes);
- }
+ match value {
+ observe::MetricValue::OperationBytes(v) => self.operation_bytes.record(v, &attributes),
+ observe::MetricValue::OperationBytesRate(v) => {
+ self.operation_bytes_rate.record(v, &attributes)
+ }
+ observe::MetricValue::OperationEntries(v) => {
+ self.operation_entries.record(v, &attributes)
+ }
+ observe::MetricValue::OperationEntriesRate(v) => {
+ self.operation_entries_rate.record(v, &attributes)
+ }
+ observe::MetricValue::OperationDurationSeconds(v) => self
+ .operation_duration_seconds
+ .record(v.as_secs_f64(), &attributes),
+ observe::MetricValue::OperationErrorsTotal => {
+ self.operation_errors_total.add(1, &attributes)
+ }
+ observe::MetricValue::OperationExecuting(v) => {
+ self.operation_executing.add(v as i64, &attributes)
+ }
+ observe::MetricValue::OperationTtfbSeconds(v) => self
+ .operation_ttfb_seconds
+ .record(v.as_secs_f64(), &attributes),
- fn observe_http_request_bytes(&self, info: Arc<AccessorInfo>, op: Operation, bytes: usize) {
- let attributes = self.create_attributes(info, "", op, None);
- self.http_request_bytes.record(bytes as u64, &attributes);
+ observe::MetricValue::HttpExecuting(v) => {
+ self.http_executing.add(v as i64, &attributes)
+ }
+ observe::MetricValue::HttpRequestBytes(v) => {
+ self.http_request_bytes.record(v, &attributes)
+ }
+ observe::MetricValue::HttpRequestBytesRate(v) => {
+ self.http_request_bytes_rate.record(v, &attributes)
+ }
+ observe::MetricValue::HttpRequestDurationSeconds(v) => self
+ .http_request_duration_seconds
+ .record(v.as_secs_f64(), &attributes),
+ observe::MetricValue::HttpResponseBytes(v) => {
+ self.http_response_bytes.record(v, &attributes)
+ }
+ observe::MetricValue::HttpResponseBytesRate(v) => {
+ self.http_response_bytes_rate.record(v, &attributes)
+ }
+ observe::MetricValue::HttpResponseDurationSeconds(v) => self
+ .http_response_duration_seconds
+ .record(v.as_secs_f64(), &attributes),
+ observe::MetricValue::HttpConnectionErrorsTotal => {
+ self.http_connection_errors_total.add(1, &attributes)
+ }
+ observe::MetricValue::HttpStatusErrorsTotal => {
+ self.http_status_errors_total.add(1, &attributes)
+ }
+ }
}
}
impl OtelMetricsInterceptor {
- fn create_attributes(
- &self,
- info: Arc<AccessorInfo>,
- path: &str,
- operation: Operation,
- error: Option<ErrorKind>,
- ) -> Vec<KeyValue> {
+ fn create_attributes(&self, attrs: observe::MetricLabels) -> Vec<KeyValue> {
let mut attributes = Vec::with_capacity(6);
attributes.extend([
- KeyValue::new(observe::LABEL_SCHEME, info.scheme().into_static()),
- KeyValue::new(observe::LABEL_NAMESPACE, info.name().clone()),
- KeyValue::new(observe::LABEL_ROOT, info.root().clone()),
- KeyValue::new(observe::LABEL_OPERATION, operation.into_static()),
+ KeyValue::new(observe::LABEL_SCHEME, attrs.scheme.into_static()),
+ KeyValue::new(observe::LABEL_NAMESPACE, attrs.namespace),
+ KeyValue::new(observe::LABEL_ROOT, attrs.root),
+ KeyValue::new(observe::LABEL_OPERATION, attrs.operation),
]);
- if let Some(path) = observe::path_label_value(path, self.path_label_level) {
- attributes.push(KeyValue::new(observe::LABEL_PATH, path.to_owned()));
+ if let Some(error) = attrs.error {
+ attributes.push(KeyValue::new(observe::LABEL_ERROR, error.into_static()));
}
- if let Some(error) = error {
- attributes.push(KeyValue::new(observe::LABEL_ERROR, error.into_static()));
+ if let Some(status_code) = attrs.status_code {
+ attributes.push(KeyValue::new(
+ observe::LABEL_STATUS_CODE,
+ status_code.as_u16() as i64,
+ ));
}
attributes
}
}
-fn exponential_boundary(start: f64, factor: f64, count: usize) -> Vec<f64> {
- let mut boundaries = Vec::with_capacity(count);
- let mut current = start;
- for _ in 0..count {
- boundaries.push(current);
- current *= factor;
+fn register_u64_histogram_meter(
+ meter: &Meter,
+ name: &'static str,
+ metric: observe::MetricValue,
+ boundaries: Vec<f64>,
+) -> Histogram<u64> {
+ let (_name, unit) = metric.name_with_unit();
+ let description = metric.help();
+
+ let builder = meter
+ .u64_histogram(name)
+ .with_description(description)
+ .with_boundaries(boundaries);
+
+ if let Some(unit) = unit {
+ builder.with_unit(unit).build()
+ } else {
+ builder.build()
+ }
+}
+
+fn register_f64_histogram_meter(
+ meter: &Meter,
+ name: &'static str,
+ metric: observe::MetricValue,
+ boundaries: Vec<f64>,
+) -> Histogram<f64> {
+ let (_name, unit) = metric.name_with_unit();
+ let description = metric.help();
+
+ let builder = meter
+ .f64_histogram(name)
+ .with_description(description)
+ .with_boundaries(boundaries);
+
+ if let Some(unit) = unit {
+ builder.with_unit(unit).build()
+ } else {
+ builder.build()
}
- boundaries
}
diff --git a/core/src/layers/prometheus.rs b/core/src/layers/prometheus.rs
index 726759102..95b9d9e2f 100644
--- a/core/src/layers/prometheus.rs
+++ b/core/src/layers/prometheus.rs
@@ -91,12 +91,6 @@ pub struct PrometheusLayer {
impl PrometheusLayer {
/// Create a [`PrometheusLayerBuilder`] to set the configuration of metrics.
///
- /// # Default Configuration
- ///
- /// - `operation_duration_seconds_buckets`: `exponential_buckets(0.01, 2.0, 16)`
- /// - `operation_bytes_buckets`: `exponential_buckets(1.0, 2.0, 16)`
- /// - `path_label`: `0`
- ///
/// # Example
///
/// ```no_run