Skip to content

Commit bae8fb3

Browse files
lalitbcijothomasTommyCpp
authored
Add global::meter_provider_shutdown (#1623)
Co-authored-by: Cijo Thomas <cithomas@microsoft.com> Co-authored-by: Zhongyang Wu <zhongyang.wu@outlook.com>
1 parent a4fae95 commit bae8fb3

File tree

10 files changed

+129
-47
lines changed

10 files changed

+129
-47
lines changed

examples/metrics-advanced/src/main.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use opentelemetry::global;
12
use opentelemetry::metrics::Unit;
23
use opentelemetry::Key;
34
use opentelemetry::{metrics::MeterProvider as _, KeyValue};
@@ -7,7 +8,7 @@ use opentelemetry_sdk::metrics::{
78
use opentelemetry_sdk::{runtime, Resource};
89
use std::error::Error;
910

10-
fn init_meter_provider() -> SdkMeterProvider {
11+
fn init_meter_provider() {
1112
// for example 1
1213
let my_view_rename_and_unit = |i: &Instrument| {
1314
if i.name == "my_histogram" {
@@ -50,7 +51,7 @@ fn init_meter_provider() -> SdkMeterProvider {
5051
// Ok(serde_json::to_writer_pretty(writer, &data).unwrap()))
5152
.build();
5253
let reader = PeriodicReader::builder(exporter, runtime::Tokio).build();
53-
SdkMeterProvider::builder()
54+
let provider = SdkMeterProvider::builder()
5455
.with_reader(reader)
5556
.with_resource(Resource::new(vec![KeyValue::new(
5657
"service.name",
@@ -59,13 +60,14 @@ fn init_meter_provider() -> SdkMeterProvider {
5960
.with_view(my_view_rename_and_unit)
6061
.with_view(my_view_drop_attributes)
6162
.with_view(my_view_change_aggregation)
62-
.build()
63+
.build();
64+
global::set_meter_provider(provider);
6365
}
6466

6567
#[tokio::main]
6668
async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
67-
let meter_provider = init_meter_provider();
68-
let meter = meter_provider.meter("mylibraryname");
69+
init_meter_provider();
70+
let meter = global::meter("mylibraryname");
6971

7072
// Example 1 - Rename metric using View.
7173
// This instrument will be renamed to "my_histogram_renamed",
@@ -151,6 +153,6 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
151153
// Metrics are exported by default every 30 seconds when using stdout exporter,
152154
// however shutting down the MeterProvider here instantly flushes
153155
// the metrics, instead of waiting for the 30 sec interval.
154-
meter_provider.shutdown()?;
156+
global::shutdown_meter_provider();
155157
Ok(())
156158
}

examples/metrics-basic/src/main.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,34 @@
1+
use opentelemetry::global;
12
use opentelemetry::metrics::Unit;
23
use opentelemetry::{metrics::MeterProvider as _, KeyValue};
34
use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider};
45
use opentelemetry_sdk::{runtime, Resource};
56
use std::error::Error;
67

7-
fn init_meter_provider() -> SdkMeterProvider {
8+
fn init_meter_provider() {
89
let exporter = opentelemetry_stdout::MetricsExporterBuilder::default()
910
// uncomment the below lines to pretty print output.
1011
// .with_encoder(|writer, data|
1112
// Ok(serde_json::to_writer_pretty(writer, &data).unwrap()))
1213
.build();
1314
let reader = PeriodicReader::builder(exporter, runtime::Tokio).build();
14-
SdkMeterProvider::builder()
15+
let provider = SdkMeterProvider::builder()
1516
.with_reader(reader)
1617
.with_resource(Resource::new(vec![KeyValue::new(
1718
"service.name",
1819
"metrics-basic-example",
1920
)]))
20-
.build()
21+
.build();
22+
global::set_meter_provider(provider);
2123
}
2224

2325
#[tokio::main]
2426
async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
2527
// Initialize the MeterProvider with the stdout Exporter.
26-
let meter_provider = init_meter_provider();
28+
init_meter_provider();
2729

2830
// Create a meter from the above MeterProvider.
29-
let meter = meter_provider.meter("mylibraryname");
31+
let meter = global::meter("mylibraryname");
3032

3133
// Create a Counter Instrument.
3234
let counter = meter.u64_counter("my_counter").init();
@@ -146,6 +148,6 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
146148
// Metrics are exported by default every 30 seconds when using stdout exporter,
147149
// however shutting down the MeterProvider here instantly flushes
148150
// the metrics, instead of waiting for the 30 sec interval.
149-
meter_provider.shutdown()?;
151+
global::shutdown_meter_provider();
150152
Ok(())
151153
}

opentelemetry-otlp/examples/basic-otlp-http/src/main.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use once_cell::sync::Lazy;
22
use opentelemetry::{
3-
global, metrics,
3+
global,
4+
metrics::MetricsError,
45
trace::{TraceContextExt, TraceError, Tracer},
56
Key, KeyValue,
67
};
78
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
89
use opentelemetry_otlp::WithExportConfig;
910
use opentelemetry_sdk::logs as sdklogs;
10-
use opentelemetry_sdk::metrics as sdkmetrics;
1111
use opentelemetry_sdk::resource;
1212
use opentelemetry_sdk::trace as sdktrace;
1313

@@ -44,19 +44,20 @@ fn init_tracer() -> Result<sdktrace::Tracer, TraceError> {
4444
.install_batch(opentelemetry_sdk::runtime::Tokio)
4545
}
4646

47-
fn init_metrics() -> metrics::Result<sdkmetrics::SdkMeterProvider> {
47+
fn init_metrics() -> Result<(), MetricsError> {
4848
let export_config = opentelemetry_otlp::ExportConfig {
4949
endpoint: "http://localhost:4318/v1/metrics".to_string(),
5050
..opentelemetry_otlp::ExportConfig::default()
5151
};
52-
opentelemetry_otlp::new_pipeline()
52+
let provider = opentelemetry_otlp::new_pipeline()
5353
.metrics(opentelemetry_sdk::runtime::Tokio)
5454
.with_exporter(
5555
opentelemetry_otlp::new_exporter()
5656
.http()
5757
.with_export_config(export_config),
5858
)
59-
.build()
59+
.build();
60+
provider.map(|_| ())
6061
}
6162

6263
const LEMONS_KEY: Key = Key::from_static_str("ex.com/lemons");
@@ -74,7 +75,7 @@ static COMMON_ATTRIBUTES: Lazy<[KeyValue; 4]> = Lazy::new(|| {
7475
#[tokio::main]
7576
async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
7677
let _ = init_tracer()?;
77-
let meter_provider = init_metrics()?;
78+
let _ = init_metrics()?;
7879
let _ = init_logs();
7980

8081
let tracer = global::tracer("ex.com/basic");
@@ -108,7 +109,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
108109

109110
global::shutdown_tracer_provider();
110111
global::shutdown_logger_provider();
111-
meter_provider.shutdown()?;
112+
global::shutdown_meter_provider();
112113

113114
Ok(())
114115
}

opentelemetry-otlp/examples/basic-otlp/src/main.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
use log::{info, Level};
22
use once_cell::sync::Lazy;
33
use opentelemetry::global;
4-
use opentelemetry::global::{logger_provider, shutdown_logger_provider, shutdown_tracer_provider};
54
use opentelemetry::logs::LogError;
5+
use opentelemetry::metrics::MetricsError;
66
use opentelemetry::trace::TraceError;
77
use opentelemetry::{
8-
metrics,
98
trace::{TraceContextExt, Tracer},
109
Key, KeyValue,
1110
};
1211
use opentelemetry_appender_log::OpenTelemetryLogBridge;
1312
use opentelemetry_otlp::{ExportConfig, WithExportConfig};
1413
use opentelemetry_sdk::logs::Config;
15-
use opentelemetry_sdk::{metrics::SdkMeterProvider, runtime, trace as sdktrace, Resource};
14+
use opentelemetry_sdk::{runtime, trace as sdktrace, Resource};
1615
use std::error::Error;
1716

1817
fn init_tracer() -> Result<sdktrace::Tracer, TraceError> {
@@ -32,12 +31,12 @@ fn init_tracer() -> Result<sdktrace::Tracer, TraceError> {
3231
.install_batch(runtime::Tokio)
3332
}
3433

35-
fn init_metrics() -> metrics::Result<SdkMeterProvider> {
34+
fn init_metrics() -> Result<(), MetricsError> {
3635
let export_config = ExportConfig {
3736
endpoint: "http://localhost:4317".to_string(),
3837
..ExportConfig::default()
3938
};
40-
opentelemetry_otlp::new_pipeline()
39+
let provider = opentelemetry_otlp::new_pipeline()
4140
.metrics(runtime::Tokio)
4241
.with_exporter(
4342
opentelemetry_otlp::new_exporter()
@@ -48,7 +47,11 @@ fn init_metrics() -> metrics::Result<SdkMeterProvider> {
4847
opentelemetry_semantic_conventions::resource::SERVICE_NAME,
4948
"basic-otlp-metrics-example",
5049
)]))
51-
.build()
50+
.build();
51+
match provider {
52+
Ok(_provider) => Ok(()),
53+
Err(err) => Err(err),
54+
}
5255
}
5356

5457
fn init_logs() -> Result<opentelemetry_sdk::logs::Logger, LogError> {
@@ -87,13 +90,13 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
8790
// matches the containing block, reporting traces and metrics during the whole
8891
// execution.
8992
let _ = init_tracer()?;
90-
let meter_provider = init_metrics()?;
93+
let _ = init_metrics()?;
9194

9295
// Initialize logs, which sets the global loggerprovider.
9396
let _ = init_logs();
9497

9598
// Retrieve the global LoggerProvider.
96-
let logger_provider = logger_provider();
99+
let logger_provider = global::logger_provider();
97100

98101
// Create a new OpenTelemetryLogBridge using the above LoggerProvider.
99102
let otel_log_appender = OpenTelemetryLogBridge::new(&logger_provider);
@@ -137,9 +140,9 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
137140

138141
info!(target: "my-target", "hello from {}. My price is {}", "apple", 1.99);
139142

140-
shutdown_tracer_provider();
141-
shutdown_logger_provider();
142-
meter_provider.shutdown()?;
143+
global::shutdown_tracer_provider();
144+
global::shutdown_logger_provider();
145+
global::shutdown_meter_provider();
143146

144147
Ok(())
145148
}

opentelemetry-sdk/CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
dependency on crossbeam-channel.
77
[1612](https://github.com/open-telemetry/opentelemetry-rust/pull/1612/files)
88
- [#1422](https://github.com/open-telemetry/opentelemetry-rust/pull/1422)
9-
Fix metrics aggregation bug when using Views to drop attributes.
9+
Fix metrics aggregation bug when using Views to drop attributes.
10+
- [#1623](https://github.com/open-telemetry/opentelemetry-rust/pull/1623) Add Drop implementation for SdkMeterProvider, which shuts down
11+
metricreaders, thereby allowing metrics still in memory to be flushed out.
1012

1113
## v0.22.1
1214

opentelemetry-sdk/src/metrics/meter_provider.rs

+39-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::{
99
};
1010

1111
use opentelemetry::{
12+
global,
1213
metrics::{noop::NoopMeterCore, Meter, MeterProvider, MetricsError, Result},
1314
KeyValue,
1415
};
@@ -113,6 +114,13 @@ impl SdkMeterProvider {
113114
}
114115
}
115116

117+
impl Drop for SdkMeterProvider {
118+
fn drop(&mut self) {
119+
if let Err(err) = self.shutdown() {
120+
global::handle_error(err);
121+
}
122+
}
123+
}
116124
impl MeterProvider for SdkMeterProvider {
117125
fn versioned_meter(
118126
&self,
@@ -211,6 +219,7 @@ impl fmt::Debug for MeterProviderBuilder {
211219
mod tests {
212220
use crate::testing::metrics::metric_reader::TestMetricReader;
213221
use crate::Resource;
222+
use opentelemetry::global;
214223
use opentelemetry::Key;
215224
use opentelemetry::KeyValue;
216225
use std::env;
@@ -228,14 +237,14 @@ mod tests {
228237
expect.map(|s| s.to_string())
229238
);
230239
};
231-
let reader = TestMetricReader {};
240+
let reader = TestMetricReader::new();
232241
let default_meter_provider = super::SdkMeterProvider::builder()
233242
.with_reader(reader)
234243
.build();
235244
assert_service_name(default_meter_provider, Some("unknown_service"));
236245

237246
// If user provided a resource, use that.
238-
let reader2 = TestMetricReader {};
247+
let reader2 = TestMetricReader::new();
239248
let custom_meter_provider = super::SdkMeterProvider::builder()
240249
.with_reader(reader2)
241250
.with_resource(Resource::new(vec![KeyValue::new(
@@ -250,7 +259,7 @@ mod tests {
250259
Some("key1=value1, k2, k3=value2"),
251260
|| {
252261
// If `OTEL_RESOURCE_ATTRIBUTES` is set, read them automatically
253-
let reader3 = TestMetricReader {};
262+
let reader3 = TestMetricReader::new();
254263
let env_resource_provider = super::SdkMeterProvider::builder()
255264
.with_reader(reader3)
256265
.build();
@@ -273,7 +282,7 @@ mod tests {
273282
"OTEL_RESOURCE_ATTRIBUTES",
274283
Some("my-custom-key=env-val,k2=value2"),
275284
|| {
276-
let reader4 = TestMetricReader {};
285+
let reader4 = TestMetricReader::new();
277286
let user_provided_resource_config_provider = super::SdkMeterProvider::builder()
278287
.with_reader(reader4)
279288
.with_resource(Resource::default().merge(&mut Resource::new(vec![
@@ -295,12 +304,37 @@ mod tests {
295304
);
296305

297306
// If user provided a resource, it takes priority during collision.
298-
let reader5 = TestMetricReader {};
307+
let reader5 = TestMetricReader::new();
299308
let no_service_name = super::SdkMeterProvider::builder()
300309
.with_reader(reader5)
301310
.with_resource(Resource::empty())
302311
.build();
303312

304313
assert_service_name(no_service_name, None);
305314
}
315+
316+
#[test]
317+
fn test_meter_provider_shutdown() {
318+
let reader = TestMetricReader::new();
319+
let provider = super::SdkMeterProvider::builder()
320+
.with_reader(reader.clone())
321+
.build();
322+
global::set_meter_provider(provider.clone());
323+
assert!(!provider
324+
.is_shutdown
325+
.load(std::sync::atomic::Ordering::Relaxed));
326+
assert!(!reader.is_shutdown());
327+
// create a meter and an instrument
328+
let meter = global::meter("test");
329+
let counter = meter.u64_counter("test_counter").init();
330+
// no need to drop a meter for meter_provider shutdown
331+
global::shutdown_meter_provider();
332+
assert!(provider
333+
.is_shutdown
334+
.load(std::sync::atomic::Ordering::Relaxed));
335+
assert!(reader.is_shutdown());
336+
// TODO Fix: the instrument is still available, and can be used.
337+
// While the reader is shutdown, and no collect is happening
338+
counter.add(1, &[]);
339+
}
306340
}

0 commit comments

Comments
 (0)