Skip to content

Commit c8dbd93

Browse files
committed
feat(metrics): make BoundCounter and BoundHistogram cloneable
Switch from Box<dyn ...> to Arc<dyn ...> and derive Clone so a single bound state can be shared across threads or modules without re-binding. Drop semantics are unchanged: bound_count is decremented when the last clone is dropped, matching Rust's RAII expectations for handle types. Mirrors the existing Clone behavior on Counter and Histogram.
1 parent 4e5d67c commit c8dbd93

2 files changed

Lines changed: 14 additions & 4 deletions

File tree

opentelemetry/src/metrics/instruments/counter.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl<T> Counter<T> {
3838
/// Binds this counter to a fixed set of attributes.
3939
#[cfg(feature = "experimental_metrics_bound_instruments")]
4040
pub fn bind(&self, attributes: &[KeyValue]) -> BoundCounter<T> {
41-
BoundCounter(self.0.bind(attributes))
41+
BoundCounter(Arc::from(self.0.bind(attributes)))
4242
}
4343
}
4444

@@ -73,9 +73,14 @@ impl<T> fmt::Debug for ObservableCounter<T> {
7373
/// Created by calling [`Counter::bind`] with an attribute set. All subsequent
7474
/// [`add`](BoundCounter::add) calls use the pre-resolved attributes, bypassing
7575
/// per-call attribute lookup for significantly better performance.
76+
///
77+
/// `BoundCounter` can be cloned cheaply to share a single bound state across
78+
/// threads or modules without re-binding. The underlying tracker is reclaimed
79+
/// when the last clone is dropped.
7680
#[cfg(feature = "experimental_metrics_bound_instruments")]
81+
#[derive(Clone)]
7782
#[must_use = "dropping a BoundCounter immediately is a no-op; store it to benefit from pre-bound attributes"]
78-
pub struct BoundCounter<T>(Box<dyn BoundSyncInstrument<T> + Send + Sync>);
83+
pub struct BoundCounter<T>(Arc<dyn BoundSyncInstrument<T> + Send + Sync>);
7984

8085
#[cfg(feature = "experimental_metrics_bound_instruments")]
8186
impl<T> fmt::Debug for BoundCounter<T> {

opentelemetry/src/metrics/instruments/histogram.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl<T> Histogram<T> {
3838
/// Binds this histogram to a fixed set of attributes.
3939
#[cfg(feature = "experimental_metrics_bound_instruments")]
4040
pub fn bind(&self, attributes: &[KeyValue]) -> BoundHistogram<T> {
41-
BoundHistogram(self.0.bind(attributes))
41+
BoundHistogram(Arc::from(self.0.bind(attributes)))
4242
}
4343
}
4444

@@ -47,9 +47,14 @@ impl<T> Histogram<T> {
4747
/// Created by calling [`Histogram::bind`] with an attribute set. All subsequent
4848
/// [`record`](BoundHistogram::record) calls use the pre-resolved attributes, bypassing
4949
/// per-call attribute lookup for significantly better performance.
50+
///
51+
/// `BoundHistogram` can be cloned cheaply to share a single bound state across
52+
/// threads or modules without re-binding. The underlying tracker is reclaimed
53+
/// when the last clone is dropped.
5054
#[cfg(feature = "experimental_metrics_bound_instruments")]
55+
#[derive(Clone)]
5156
#[must_use = "dropping a BoundHistogram immediately is a no-op; store it to benefit from pre-bound attributes"]
52-
pub struct BoundHistogram<T>(Box<dyn BoundSyncInstrument<T> + Send + Sync>);
57+
pub struct BoundHistogram<T>(Arc<dyn BoundSyncInstrument<T> + Send + Sync>);
5358

5459
#[cfg(feature = "experimental_metrics_bound_instruments")]
5560
impl<T> fmt::Debug for BoundHistogram<T> {

0 commit comments

Comments
 (0)