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 b26f60100 chore(metrics): add more docs about global instance of 
PrometheusLayer and FastmetricsLayer (#6308)
b26f60100 is described below

commit b26f601002144d91bee3fc4abe274f56b90db44b
Author: Qinxuan Chen <[email protected]>
AuthorDate: Tue Jun 17 17:52:30 2025 +0800

    chore(metrics): add more docs about global instance of PrometheusLayer and 
FastmetricsLayer (#6308)
---
 core/src/layers/fastmetrics.rs       | 156 +++++++++++++++++++++++++----------
 core/src/layers/prometheus.rs        |  88 ++++++++++++++------
 core/src/layers/prometheus_client.rs |  16 ++--
 3 files changed, 181 insertions(+), 79 deletions(-)

diff --git a/core/src/layers/fastmetrics.rs b/core/src/layers/fastmetrics.rs
index 47199320c..2ce066fe3 100644
--- a/core/src/layers/fastmetrics.rs
+++ b/core/src/layers/fastmetrics.rs
@@ -15,7 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use std::{fmt, time::Duration};
+use std::fmt;
+use std::time::Duration;
 
 use fastmetrics::encoder::EncodeLabelSet;
 use fastmetrics::encoder::LabelSetEncoder;
@@ -37,20 +38,93 @@ use crate::*;
 ///
 /// # Examples
 ///
+/// ## Basic Usage
+///
 /// ```no_run
+/// # use fastmetrics::format::text;
+/// # use log::info;
 /// # use opendal::layers::FastmetricsLayer;
 /// # use opendal::services;
 /// # use opendal::Operator;
 /// # use opendal::Result;
 ///
-/// # fn main() -> Result<()> {
+/// # #[tokio::main]
+/// # async fn main() -> Result<()> {
 /// let mut registry = fastmetrics::registry::Registry::default();
-/// let _ = Operator::new(services::Memory::default())?
+/// let op = Operator::new(services::Memory::default())?
 ///     .layer(FastmetricsLayer::builder().register(&mut registry)?)
 ///     .finish();
+///
+/// // Write data into object test.
+/// op.write("test", "Hello, World!").await?;
+///
+/// // Read data from the object.
+/// let bs = op.read("test").await?;
+/// info!("content: {}", String::from_utf8_lossy(&bs.to_bytes()));
+///
+/// // Get object metadata.
+/// let meta = op.stat("test").await?;
+/// info!("meta: {:?}", meta);
+///
+/// // Export prometheus metrics.
+/// let mut output = String::new();
+/// text::encode(&mut output, &registry).unwrap();
+/// println!("{}", output);
 /// # Ok(())
 /// # }
 /// ```
+/// ## Global Instance
+///
+/// `FastmetricsLayer` needs to be registered before instantiation.
+///
+/// If there are multiple operators in an application that need the 
`FastmetricsLayer`, we could
+/// instantiate it once and pass it to multiple operators. But we cannot 
directly call
+/// `.layer(FastmetricsLayer::builder().register(&mut registry)?)` for 
different services, because
+/// registering the same metrics multiple times to the same registry will 
cause register errors.
+/// Therefore, we can provide a global instance for the `FastmetricsLayer`.
+///
+/// ```no_run
+/// # use std::sync::OnceLock;
+/// # use fastmetrics::format::text;
+/// # use fastmetrics::registry::with_global_registry;
+/// # use log::info;
+/// # use opendal::layers::FastmetricsLayer;
+/// # use opendal::services;
+/// # use opendal::Operator;
+/// # use opendal::Result;
+///
+/// fn global_fastmetrics_layer() -> &'static FastmetricsLayer {
+///     static GLOBAL: OnceLock<FastmetricsLayer> = OnceLock::new();
+///     GLOBAL.get_or_init(|| {
+///         FastmetricsLayer::builder()
+///             .register_global()
+///             .expect("Failed to register with the global registry")
+///     })
+/// }
+///
+/// # #[tokio::main]
+/// # async fn main() -> Result<()> {
+/// let op = Operator::new(services::Memory::default())?
+///     .layer(global_fastmetrics_layer().clone())
+///     .finish();
+///
+/// // Write data into object test.
+/// op.write("test", "Hello, World!").await?;
+///
+/// // Read data from the object.
+/// let bs = op.read("test").await?;
+/// info!("content: {}", String::from_utf8_lossy(&bs.to_bytes()));
+///
+/// // Get object metadata.
+/// let meta = op.stat("test").await?;
+/// info!("meta: {:?}", meta);
+///
+/// // Export prometheus metrics.
+/// let mut output = String::new();
+/// with_global_registry(|registry| text::encode(&mut output, 
&registry).unwrap());
+/// println!("{}", output);
+/// # Ok(())
+/// # }
 #[derive(Clone, Debug)]
 pub struct FastmetricsLayer {
     interceptor: FastmetricsInterceptor,
@@ -154,10 +228,9 @@ impl FastmetricsLayerBuilder {
 
     /// Register the metrics into the registry and return a 
[`FastmetricsLayer`].
     ///
-    /// # Examples
+    /// # Example
     ///
     /// ```no_run
-    /// # use log::debug;
     /// # use opendal::layers::FastmetricsLayer;
     /// # use opendal::services;
     /// # use opendal::Operator;
@@ -176,55 +249,48 @@ impl FastmetricsLayerBuilder {
     /// # }
     /// ```
     pub fn register(self, registry: &mut Registry) -> Result<FastmetricsLayer> 
{
-        let operation_bytes = Family::<OperationLabels, Histogram, 
_>::new(HistogramFactory {
+        let operation_bytes = Family::new(HistogramFactory {
             buckets: self.bytes_buckets.clone(),
         });
-        let operation_bytes_rate = Family::<OperationLabels, Histogram, 
_>::new(HistogramFactory {
+        let operation_bytes_rate = Family::new(HistogramFactory {
             buckets: self.bytes_rate_buckets.clone(),
         });
-        let operation_entries = Family::<OperationLabels, Histogram, 
_>::new(HistogramFactory {
+        let operation_entries = Family::new(HistogramFactory {
             buckets: self.entries_buckets.clone(),
         });
-        let operation_entries_rate =
-            Family::<OperationLabels, Histogram, _>::new(HistogramFactory {
-                buckets: self.entries_rate_buckets.clone(),
-            });
-        let operation_duration_seconds =
-            Family::<OperationLabels, Histogram, _>::new(HistogramFactory {
-                buckets: self.duration_seconds_buckets.clone(),
-            });
-        let operation_errors_total = Family::<OperationLabels, 
Counter>::default();
-        let operation_executing = Family::<OperationLabels, Gauge>::default();
-        let operation_ttfb_seconds =
-            Family::<OperationLabels, Histogram, _>::new(HistogramFactory {
-                buckets: self.ttfb_buckets.clone(),
-            });
-
-        let http_executing = Family::<OperationLabels, Gauge>::default();
-        let http_request_bytes = Family::<OperationLabels, Histogram, 
_>::new(HistogramFactory {
+        let operation_entries_rate = Family::new(HistogramFactory {
+            buckets: self.entries_rate_buckets.clone(),
+        });
+        let operation_duration_seconds = Family::new(HistogramFactory {
+            buckets: self.duration_seconds_buckets.clone(),
+        });
+        let operation_errors_total = Family::default();
+        let operation_executing = Family::default();
+        let operation_ttfb_seconds = Family::new(HistogramFactory {
+            buckets: self.ttfb_buckets.clone(),
+        });
+
+        let http_executing = Family::default();
+        let http_request_bytes = Family::new(HistogramFactory {
             buckets: self.bytes_buckets.clone(),
         });
-        let http_request_bytes_rate =
-            Family::<OperationLabels, Histogram, _>::new(HistogramFactory {
-                buckets: self.bytes_rate_buckets.clone(),
-            });
-        let http_request_duration_seconds =
-            Family::<OperationLabels, Histogram, _>::new(HistogramFactory {
-                buckets: self.duration_seconds_buckets.clone(),
-            });
-        let http_response_bytes = Family::<OperationLabels, Histogram, 
_>::new(HistogramFactory {
+        let http_request_bytes_rate = Family::new(HistogramFactory {
+            buckets: self.bytes_rate_buckets.clone(),
+        });
+        let http_request_duration_seconds = Family::new(HistogramFactory {
+            buckets: self.duration_seconds_buckets.clone(),
+        });
+        let http_response_bytes = Family::new(HistogramFactory {
             buckets: self.bytes_buckets.clone(),
         });
-        let http_response_bytes_rate =
-            Family::<OperationLabels, Histogram, _>::new(HistogramFactory {
-                buckets: self.bytes_rate_buckets.clone(),
-            });
-        let http_response_duration_seconds =
-            Family::<OperationLabels, Histogram, _>::new(HistogramFactory {
-                buckets: self.duration_seconds_buckets.clone(),
-            });
-        let http_connection_errors_total = Family::<OperationLabels, 
Counter>::default();
-        let http_status_errors_total = Family::<OperationLabels, 
Counter>::default();
+        let http_response_bytes_rate = Family::new(HistogramFactory {
+            buckets: self.bytes_rate_buckets.clone(),
+        });
+        let http_response_duration_seconds = Family::new(HistogramFactory {
+            buckets: self.duration_seconds_buckets.clone(),
+        });
+        let http_connection_errors_total = Family::default();
+        let http_status_errors_total = Family::default();
 
         let interceptor = FastmetricsInterceptor {
             operation_bytes,
@@ -257,7 +323,7 @@ impl FastmetricsLayerBuilder {
 
     /// Register the metrics into the global registry and return a 
[`FastmetricsLayer`].
     ///
-    /// # Examples
+    /// # Example
     ///
     /// ```no_run
     /// # use opendal::layers::FastmetricsLayer;
diff --git a/core/src/layers/prometheus.rs b/core/src/layers/prometheus.rs
index 95b9d9e2f..7667f0604 100644
--- a/core/src/layers/prometheus.rs
+++ b/core/src/layers/prometheus.rs
@@ -41,8 +41,9 @@ use crate::*;
 ///
 /// # Examples
 ///
+/// ## Basic Usage
+///
 /// ```no_run
-/// # use log::debug;
 /// # use log::info;
 /// # use opendal::layers::PrometheusLayer;
 /// # use opendal::services;
@@ -61,11 +62,10 @@ use crate::*;
 ///             .expect("register metrics successfully"),
 ///     )
 ///     .finish();
-/// debug!("operator: {op:?}");
 ///
 /// // Write data into object test.
 /// op.write("test", "Hello, World!").await?;
-/// // Read data from object.
+/// // Read data from the object.
 /// let bs = op.read("test").await?;
 /// info!("content: {}", String::from_utf8_lossy(&bs.to_bytes()));
 ///
@@ -79,8 +79,62 @@ use crate::*;
 /// encoder.encode(&prometheus::gather(), &mut buffer).unwrap();
 /// println!("## Prometheus Metrics");
 /// println!("{}", String::from_utf8(buffer.clone()).unwrap());
+/// # Ok(())
+/// # }
+/// ```
+///
+/// ## Global Instance
+///
+/// `PrometheusLayer` needs to be registered before instantiation.
+///
+/// If there are multiple operators in an application that need the 
`PrometheusLayer`, we could
+/// instantiate it once and pass it to multiple operators. But we cannot 
directly call
+/// `.layer(PrometheusLayer::builder().register(&registry)?)` for different 
services, because
+/// registering the same metrics multiple times to the same registry will 
cause register errors.
+/// Therefore, we can provide a global instance for the `PrometheusLayer`.
+///
+/// ```no_run
+/// # use std::sync::OnceLock;
+/// # use log::info;
+/// # use opendal::layers::PrometheusLayer;
+/// # use opendal::services;
+/// # use opendal::Operator;
+/// # use opendal::Result;
+/// # use prometheus::Encoder;
+///
+/// fn global_prometheus_layer() -> &'static PrometheusLayer {
+///     static GLOBAL: OnceLock<PrometheusLayer> = OnceLock::new();
+///     GLOBAL.get_or_init(|| {
+///         PrometheusLayer::builder()
+///             .register_default()
+///             .expect("Failed to register with the global registry")
+///     })
+/// }
+///
+/// # #[tokio::main]
+/// # async fn main() -> Result<()> {
+/// let op = Operator::new(services::Memory::default())?
+///     .layer(global_prometheus_layer().clone())
+///     .finish();
+///
+/// // Write data into object test.
+/// op.write("test", "Hello, World!").await?;
+///
+/// // Read data from the object.
+/// let bs = op.read("test").await?;
+/// info!("content: {}", String::from_utf8_lossy(&bs.to_bytes()));
 ///
-/// Ok(())
+/// // Get object metadata.
+/// let meta = op.stat("test").await?;
+/// info!("meta: {:?}", meta);
+///
+/// // Export prometheus metrics.
+/// let mut buffer = Vec::<u8>::new();
+/// let encoder = prometheus::TextEncoder::new();
+/// encoder.encode(&prometheus::gather(), &mut buffer).unwrap();
+/// println!("## Prometheus Metrics");
+/// println!("{}", String::from_utf8(buffer.clone()).unwrap());
+/// # Ok(())
 /// # }
 /// ```
 #[derive(Clone, Debug)]
@@ -94,7 +148,6 @@ impl PrometheusLayer {
     /// # Example
     ///
     /// ```no_run
-    /// # use log::debug;
     /// # use opendal::layers::PrometheusLayer;
     /// # use opendal::services;
     /// # use opendal::Operator;
@@ -108,7 +161,7 @@ impl PrometheusLayer {
     ///
     /// let duration_seconds_buckets = prometheus::exponential_buckets(0.01, 
2.0, 16).unwrap();
     /// let bytes_buckets = prometheus::exponential_buckets(1.0, 2.0, 
16).unwrap();
-    /// let op = Operator::new(builder)?
+    /// let _ = Operator::new(builder)?
     ///     .layer(
     ///         PrometheusLayer::builder()
     ///             .duration_seconds_buckets(duration_seconds_buckets)
@@ -117,9 +170,7 @@ impl PrometheusLayer {
     ///             .expect("register metrics successfully"),
     ///     )
     ///     .finish();
-    /// debug!("operator: {op:?}");
-    ///
-    /// Ok(())
+    /// # Ok(())
     /// # }
     /// ```
     pub fn builder() -> PrometheusLayerBuilder {
@@ -212,7 +263,6 @@ impl PrometheusLayerBuilder {
     /// # Example
     ///
     /// ```no_run
-    /// # use log::debug;
     /// # use opendal::layers::PrometheusLayer;
     /// # use opendal::services;
     /// # use opendal::Operator;
@@ -222,18 +272,14 @@ impl PrometheusLayerBuilder {
     /// # async fn main() -> Result<()> {
     /// // Pick a builder and configure it.
     /// let builder = services::Memory::default();
-    /// let registry = prometheus::default_registry();
-    ///
-    /// let op = Operator::new(builder)?
+    /// let _ = Operator::new(builder)?
     ///     .layer(
     ///         PrometheusLayer::builder()
-    ///             .register(registry)
+    ///             .register(prometheus::default_registry())
     ///             .expect("register metrics successfully"),
     ///     )
     ///     .finish();
-    /// debug!("operator: {op:?}");
-    ///
-    /// Ok(())
+    /// # Ok(())
     /// # }
     /// ```
     pub fn register(self, registry: &Registry) -> Result<PrometheusLayer> {
@@ -455,7 +501,6 @@ impl PrometheusLayerBuilder {
     /// # Example
     ///
     /// ```no_run
-    /// # use log::debug;
     /// # use opendal::layers::PrometheusLayer;
     /// # use opendal::services;
     /// # use opendal::Operator;
@@ -465,17 +510,14 @@ impl PrometheusLayerBuilder {
     /// # async fn main() -> Result<()> {
     /// // Pick a builder and configure it.
     /// let builder = services::Memory::default();
-    ///
-    /// let op = Operator::new(builder)?
+    /// let _ = Operator::new(builder)?
     ///     .layer(
     ///         PrometheusLayer::builder()
     ///             .register_default()
     ///             .expect("register metrics successfully"),
     ///     )
     ///     .finish();
-    /// debug!("operator: {op:?}");
-    ///
-    /// Ok(())
+    /// # Ok(())
     /// # }
     /// ```
     pub fn register_default(self) -> Result<PrometheusLayer> {
diff --git a/core/src/layers/prometheus_client.rs 
b/core/src/layers/prometheus_client.rs
index b9f6743db..f6836f00e 100644
--- a/core/src/layers/prometheus_client.rs
+++ b/core/src/layers/prometheus_client.rs
@@ -44,7 +44,6 @@ use crate::*;
 /// # Examples
 ///
 /// ```no_run
-/// # use log::debug;
 /// # use log::info;
 /// # use opendal::layers::PrometheusClientLayer;
 /// # use opendal::services;
@@ -58,11 +57,10 @@ use crate::*;
 /// let op = Operator::new(services::Memory::default())?
 ///     .layer(PrometheusClientLayer::builder().register(&mut registry))
 ///     .finish();
-/// debug!("operator: {op:?}");
 ///
 /// // Write data into object test.
 /// op.write("test", "Hello, World!").await?;
-/// // Read data from object.
+/// // Read data from the object.
 /// let bs = op.read("test").await?;
 /// info!("content: {}", String::from_utf8_lossy(&bs.to_bytes()));
 ///
@@ -75,8 +73,7 @@ use crate::*;
 /// prometheus_client::encoding::text::encode(&mut buf, &registry).unwrap();
 /// println!("## Prometheus Metrics");
 /// println!("{}", buf);
-///
-/// Ok(())
+/// # Ok(())
 /// # }
 /// ```
 #[derive(Clone, Debug)]
@@ -182,10 +179,9 @@ impl PrometheusClientLayerBuilder {
 
     /// Register the metrics into the registry and return a 
[`PrometheusClientLayer`].
     ///
-    /// # Examples
+    /// # Example
     ///
     /// ```no_run
-    /// # use log::debug;
     /// # use opendal::layers::PrometheusClientLayer;
     /// # use opendal::services;
     /// # use opendal::Operator;
@@ -197,12 +193,10 @@ impl PrometheusClientLayerBuilder {
     /// let builder = services::Memory::default();
     /// let mut registry = prometheus_client::registry::Registry::default();
     ///
-    /// let op = Operator::new(builder)?
+    /// let _ = Operator::new(builder)?
     ///     .layer(PrometheusClientLayer::builder().register(&mut registry))
     ///     .finish();
-    /// debug!("operator: {op:?}");
-    ///
-    /// Ok(())
+    /// # Ok(())
     /// # }
     /// ```
     pub fn register(self, registry: &mut Registry) -> PrometheusClientLayer {

Reply via email to