7 7 | //! real time.
|
8 8 |
|
9 9 | use crate::instruments::{
|
10 10 | AsyncInstrumentBuilder, AsyncMeasure, Histogram, InstrumentBuilder, MonotonicCounter,
|
11 11 | UpDownCounter,
|
12 12 | };
|
13 13 | use crate::{attributes::Attributes, instruments::ProvideInstrument};
|
14 14 | use std::{borrow::Cow, fmt::Debug, sync::Arc};
|
15 15 |
|
16 16 | /// Provides named instances of [Meter].
|
17 - | pub trait ProvideMeter: Send + Sync + Debug {
|
17 + | pub trait ProvideMeter: Send + Sync + Debug + 'static {
|
18 18 | /// Get or create a named [Meter].
|
19 19 | fn get_meter(&self, scope: &'static str, attributes: Option<&Attributes>) -> Meter;
|
20 + |
|
21 + | /// Downcast to `Any` for type inspection.
|
22 + | ///
|
23 + | /// This method enables runtime type checking via downcasting to concrete types.
|
24 + | ///
|
25 + | /// Implementations must return `self` to enable proper downcasting:
|
26 + | ///
|
27 + | /// ```ignore
|
28 + | /// impl ProvideMeter for MyProvider {
|
29 + | /// fn as_any(&self) -> &dyn std::any::Any {
|
30 + | /// self
|
31 + | /// }
|
32 + | /// }
|
33 + | /// ```
|
34 + | ///
|
35 + | /// # Example Usage
|
36 + | ///
|
37 + | /// ```ignore
|
38 + | /// use aws_smithy_observability::meter::ProvideMeter;
|
39 + | /// use aws_smithy_observability_otel::meter::OtelMeterProvider;
|
40 + | ///
|
41 + | /// fn check_provider_type(provider: &dyn ProvideMeter) {
|
42 + | /// // Downcast to check if this is an OpenTelemetry provider
|
43 + | /// if provider.as_any().downcast_ref::<OtelMeterProvider>().is_some() {
|
44 + | /// println!("This is an OpenTelemetry provider");
|
45 + | /// }
|
46 + | /// }
|
47 + | /// ```
|
48 + | fn as_any(&self) -> &dyn std::any::Any;
|
20 49 | }
|
21 50 |
|
22 51 | /// The entry point to creating instruments. A grouping of related metrics.
|
23 52 | #[derive(Clone)]
|
24 53 | pub struct Meter {
|
25 54 | pub(crate) instrument_provider: Arc<dyn ProvideInstrument + Send + Sync>,
|
26 55 | }
|
27 56 |
|
28 57 | impl Meter {
|
29 58 | /// Create a new [Meter] from an [ProvideInstrument]
|
30 59 | pub fn new(instrument_provider: Arc<dyn ProvideInstrument + Send + Sync>) -> Self {
|
31 60 | Meter {
|
32 61 | instrument_provider,
|
33 62 | }
|
34 63 | }
|
35 64 |
|
36 65 | /// Create a new Gauge.
|
37 66 | #[allow(clippy::type_complexity)]
|
38 67 | pub fn create_gauge<F>(
|
39 68 | &self,
|
40 69 | name: impl Into<Cow<'static, str>>,
|
41 70 | callback: F,
|
42 71 | ) -> AsyncInstrumentBuilder<'_, Arc<dyn AsyncMeasure<Value = f64>>, f64>
|
43 72 | where
|
44 73 | F: Fn(&dyn AsyncMeasure<Value = f64>) + Send + Sync + 'static,
|
45 74 | {
|
46 75 | AsyncInstrumentBuilder::new(self, name.into(), Arc::new(callback))
|
47 76 | }
|
48 77 |
|
49 78 | /// Create a new [UpDownCounter].
|
69 98 |
|
70 99 | /// Create a new [MonotonicCounter].
|
71 100 | pub fn create_monotonic_counter(
|
72 101 | &self,
|
73 102 | name: impl Into<Cow<'static, str>>,
|
74 103 | ) -> InstrumentBuilder<'_, Arc<dyn MonotonicCounter>> {
|
75 104 | InstrumentBuilder::new(self, name.into())
|
76 105 | }
|
77 106 |
|
78 107 | /// Create a new AsyncMonotonicCounter.
|
79 108 | #[allow(clippy::type_complexity)]
|
80 109 | pub fn create_async_monotonic_counter<F>(
|
81 110 | &self,
|
82 111 | name: impl Into<Cow<'static, str>>,
|
83 112 | callback: F,
|
84 113 | ) -> AsyncInstrumentBuilder<'_, Arc<dyn AsyncMeasure<Value = u64>>, u64>
|
85 114 | where
|
86 115 | F: Fn(&dyn AsyncMeasure<Value = u64>) + Send + Sync + 'static,
|
87 116 | {
|
88 117 | AsyncInstrumentBuilder::new(self, name.into(), Arc::new(callback))
|
89 118 | }
|
90 119 |
|
91 120 | /// Create a new [Histogram].
|
92 121 | pub fn create_histogram(
|
93 122 | &self,
|
94 123 | name: impl Into<Cow<'static, str>>,
|
95 124 | ) -> InstrumentBuilder<'_, Arc<dyn Histogram>> {
|
96 125 | InstrumentBuilder::new(self, name.into())
|
97 126 | }
|
98 127 | }
|
128 + |
|
129 + | #[cfg(test)]
|
130 + | mod tests {
|
131 + | use super::*;
|
132 + | use crate::noop::NoopMeterProvider;
|
133 + |
|
134 + | #[test]
|
135 + | fn test_as_any_downcasting_works() {
|
136 + | // Create a noop provider
|
137 + | let provider = NoopMeterProvider;
|
138 + |
|
139 + | // Convert to trait object
|
140 + | let provider_dyn: &dyn ProvideMeter = &provider;
|
141 + |
|
142 + | // Test that downcasting works when as_any() is properly implemented
|
143 + | let downcast_result = provider_dyn.as_any().downcast_ref::<NoopMeterProvider>();
|
144 + | assert!(
|
145 + | downcast_result.is_some(),
|
146 + | "Downcasting should succeed when as_any() returns self"
|
147 + | );
|
148 + | }
|
149 + |
|
150 + | /// Custom meter provider for testing extensibility.
|
151 + | ///
|
152 + | /// This demonstrates that users can create their own meter provider implementations
|
153 + | /// and that all required types are publicly accessible.
|
154 + | #[derive(Debug)]
|
155 + | struct CustomMeterProvider;
|
156 + |
|
157 + | impl ProvideMeter for CustomMeterProvider {
|
158 + | fn get_meter(&self, _scope: &'static str, _attributes: Option<&Attributes>) -> Meter {
|
159 + | // Create a meter using NoopMeterProvider's implementation
|
160 + | // This demonstrates that users can compose their own providers
|
161 + | let noop_provider = NoopMeterProvider;
|
162 + | noop_provider.get_meter(_scope, _attributes)
|
163 + | }
|
164 + |
|
165 + | fn as_any(&self) -> &dyn std::any::Any {
|
166 + | self
|
167 + | }
|
168 + | }
|
169 + |
|
170 + | #[test]
|
171 + | fn test_custom_provider_extensibility() {
|
172 + | // Create a custom provider
|
173 + | let custom = CustomMeterProvider;
|
174 + | let provider_ref: &dyn ProvideMeter = &custom;
|
175 + |
|
176 + | // Verify custom provider doesn't downcast to NoopMeterProvider
|
177 + | assert!(
|
178 + | provider_ref
|
179 + | .as_any()
|
180 + | .downcast_ref::<NoopMeterProvider>()
|
181 + | .is_none(),
|
182 + | "Custom provider should not downcast to NoopMeterProvider"
|
183 + | );
|
184 + |
|
185 + | // Verify custom provider downcasts to its own type
|
186 + | assert!(
|
187 + | provider_ref
|
188 + | .as_any()
|
189 + | .downcast_ref::<CustomMeterProvider>()
|
190 + | .is_some(),
|
191 + | "Custom provider should downcast to CustomMeterProvider"
|
192 + | );
|
193 + |
|
194 + | // Verify the provider can create meters (demonstrates all required types are accessible)
|
195 + | let meter = custom.get_meter("test_scope", None);
|
196 + |
|
197 + | // Verify we can create instruments from the meter
|
198 + | let _counter = meter.create_monotonic_counter("test_counter").build();
|
199 + | let _histogram = meter.create_histogram("test_histogram").build();
|
200 + | let _up_down = meter.create_up_down_counter("test_up_down").build();
|
201 + |
|
202 + | // If we got here, all required types are publicly accessible
|
203 + | }
|
204 + | }
|