Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add global::meter_provider_shutdown #1623

Merged
merged 20 commits into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions examples/metrics-advanced/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use opentelemetry::global::{meter_provider, set_meter_provider, shutdown_meter_provider};
use opentelemetry::metrics::Unit;
use opentelemetry::Key;
use opentelemetry::{metrics::MeterProvider as _, KeyValue};
Expand All @@ -7,7 +8,7 @@ use opentelemetry_sdk::metrics::{
use opentelemetry_sdk::{runtime, Resource};
use std::error::Error;

fn init_meter_provider() -> SdkMeterProvider {
fn init_meter_provider() {
// for example 1
let my_view_rename_and_unit = |i: &Instrument| {
if i.name == "my_histogram" {
Expand Down Expand Up @@ -50,7 +51,7 @@ fn init_meter_provider() -> SdkMeterProvider {
// Ok(serde_json::to_writer_pretty(writer, &data).unwrap()))
.build();
let reader = PeriodicReader::builder(exporter, runtime::Tokio).build();
SdkMeterProvider::builder()
let provider = SdkMeterProvider::builder()
.with_reader(reader)
.with_resource(Resource::new(vec![KeyValue::new(
"service.name",
Expand All @@ -59,13 +60,14 @@ fn init_meter_provider() -> SdkMeterProvider {
.with_view(my_view_rename_and_unit)
.with_view(my_view_drop_attributes)
.with_view(my_view_change_aggregation)
.build()
.build();
set_meter_provider(provider);
}

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

// Example 1 - Rename metric using View.
// This instrument will be renamed to "my_histogram_renamed",
Expand Down Expand Up @@ -151,6 +153,6 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
// Metrics are exported by default every 30 seconds when using stdout exporter,
// however shutting down the MeterProvider here instantly flushes
// the metrics, instead of waiting for the 30 sec interval.
meter_provider.shutdown()?;
shutdown_meter_provider();
Ok(())
}
14 changes: 8 additions & 6 deletions examples/metrics-basic/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
use opentelemetry::global::{meter_provider, set_meter_provider, shutdown_meter_provider};
use opentelemetry::metrics::Unit;
use opentelemetry::{metrics::MeterProvider as _, KeyValue};
use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider};
use opentelemetry_sdk::{runtime, Resource};
use std::error::Error;

fn init_meter_provider() -> SdkMeterProvider {
fn init_meter_provider() {
let exporter = opentelemetry_stdout::MetricsExporterBuilder::default()
// uncomment the below lines to pretty print output.
// .with_encoder(|writer, data|
// Ok(serde_json::to_writer_pretty(writer, &data).unwrap()))
.build();
let reader = PeriodicReader::builder(exporter, runtime::Tokio).build();
SdkMeterProvider::builder()
let provider = SdkMeterProvider::builder()
.with_reader(reader)
.with_resource(Resource::new(vec![KeyValue::new(
"service.name",
"metrics-basic-example",
)]))
.build()
.build();
set_meter_provider(provider);
}

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

// Create a meter from the above MeterProvider.
let meter = meter_provider.meter("mylibraryname");
let meter = meter_provider().meter("mylibraryname");

// Create a Counter Instrument.
let counter = meter.u64_counter("my_counter").init();
Expand Down Expand Up @@ -146,6 +148,6 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
// Metrics are exported by default every 30 seconds when using stdout exporter,
// however shutting down the MeterProvider here instantly flushes
// the metrics, instead of waiting for the 30 sec interval.
meter_provider.shutdown()?;
shutdown_meter_provider();
Ok(())
}
18 changes: 11 additions & 7 deletions opentelemetry-otlp/examples/basic-otlp-http/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use once_cell::sync::Lazy;
use opentelemetry::{
global, metrics,
global,
metrics::MetricsError,
trace::{TraceContextExt, TraceError, Tracer},
Key, KeyValue,
};
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
use opentelemetry_otlp::WithExportConfig;
use opentelemetry_sdk::logs as sdklogs;
use opentelemetry_sdk::metrics as sdkmetrics;
use opentelemetry_sdk::resource;
use opentelemetry_sdk::trace as sdktrace;

Expand Down Expand Up @@ -44,19 +44,23 @@ fn init_tracer() -> Result<sdktrace::Tracer, TraceError> {
.install_batch(opentelemetry_sdk::runtime::Tokio)
}

fn init_metrics() -> metrics::Result<sdkmetrics::SdkMeterProvider> {
fn init_metrics() -> Result<(), MetricsError> {
let export_config = opentelemetry_otlp::ExportConfig {
endpoint: "http://localhost:4318/v1/metrics".to_string(),
..opentelemetry_otlp::ExportConfig::default()
};
opentelemetry_otlp::new_pipeline()
let provider = opentelemetry_otlp::new_pipeline()
.metrics(opentelemetry_sdk::runtime::Tokio)
.with_exporter(
opentelemetry_otlp::new_exporter()
.http()
.with_export_config(export_config),
)
.build()
.build();
match provider {
Ok(provider) => Ok(()),
Err(err) => Err(err),
}
}

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

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

global::shutdown_tracer_provider();
global::shutdown_logger_provider();
meter_provider.shutdown()?;
global::shutdown_meter_provider();

Ok(())
}
20 changes: 12 additions & 8 deletions opentelemetry-otlp/examples/basic-otlp/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
use log::{info, Level};
use once_cell::sync::Lazy;
use opentelemetry::global;
use opentelemetry::global::{self, shutdown_meter_provider};
use opentelemetry::global::{logger_provider, shutdown_logger_provider, shutdown_tracer_provider};
use opentelemetry::logs::LogError;
use opentelemetry::metrics::MetricsError;
use opentelemetry::trace::TraceError;
use opentelemetry::{
metrics,
trace::{TraceContextExt, Tracer},
Key, KeyValue,
};
use opentelemetry_appender_log::OpenTelemetryLogBridge;
use opentelemetry_otlp::{ExportConfig, WithExportConfig};
use opentelemetry_sdk::logs::Config;
use opentelemetry_sdk::{metrics::SdkMeterProvider, runtime, trace as sdktrace, Resource};
use opentelemetry_sdk::{runtime, trace as sdktrace, Resource};
use std::error::Error;

fn init_tracer() -> Result<sdktrace::Tracer, TraceError> {
Expand All @@ -32,12 +32,12 @@ fn init_tracer() -> Result<sdktrace::Tracer, TraceError> {
.install_batch(runtime::Tokio)
}

fn init_metrics() -> metrics::Result<SdkMeterProvider> {
fn init_metrics() -> Result<(), MetricsError> {
let export_config = ExportConfig {
endpoint: "http://localhost:4317".to_string(),
..ExportConfig::default()
};
opentelemetry_otlp::new_pipeline()
let provider = opentelemetry_otlp::new_pipeline()
.metrics(runtime::Tokio)
.with_exporter(
opentelemetry_otlp::new_exporter()
Expand All @@ -48,7 +48,11 @@ fn init_metrics() -> metrics::Result<SdkMeterProvider> {
opentelemetry_semantic_conventions::resource::SERVICE_NAME,
"basic-otlp-metrics-example",
)]))
.build()
.build();
match provider {
Ok(_provider) => Ok(()),
Err(err) => Err(err),
}
}

fn init_logs() -> Result<opentelemetry_sdk::logs::Logger, LogError> {
Expand Down Expand Up @@ -87,7 +91,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
// matches the containing block, reporting traces and metrics during the whole
// execution.
let _ = init_tracer()?;
let meter_provider = init_metrics()?;
let _ = init_metrics()?;

// Initialize logs, which sets the global loggerprovider.
let _ = init_logs();
Expand Down Expand Up @@ -139,7 +143,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {

shutdown_tracer_provider();
shutdown_logger_provider();
meter_provider.shutdown()?;
shutdown_meter_provider();

Ok(())
}
11 changes: 11 additions & 0 deletions opentelemetry-sdk/src/metrics/meter_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
};

use opentelemetry::{
global,
metrics::{noop::NoopMeterCore, Meter, MeterProvider, MetricsError, Result},
KeyValue,
};
Expand Down Expand Up @@ -113,6 +114,16 @@
}
}

impl Drop for SdkMeterProvider {
fn drop(&mut self) {
if self.is_shutdown.load(Ordering::Relaxed) {
return;

Check warning on line 120 in opentelemetry-sdk/src/metrics/meter_provider.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/metrics/meter_provider.rs#L120

Added line #L120 was not covered by tests
}
if let Err(err) = self.shutdown() {
global::handle_error(err);

Check warning on line 123 in opentelemetry-sdk/src/metrics/meter_provider.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry-sdk/src/metrics/meter_provider.rs#L123

Added line #L123 was not covered by tests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this might cause false alarms.. it is normal for users to call shutdown of their own, and then drop will call it again, causing the global error handler to print a message. It is unactionable for users, and they haven't anything wrong either.... Might need to revisit.

Copy link

@bwalk-at-ibm bwalk-at-ibm Apr 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's even worse because this is bugged because dropping just one reference to any metrics provider will shutdown and terminate the underlying data (pipelines), invalidating all copies, especially the registered global metrics provider.

}
}
}
impl MeterProvider for SdkMeterProvider {
fn versioned_meter(
&self,
Expand Down
13 changes: 7 additions & 6 deletions opentelemetry-stdout/examples/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#[cfg(all(feature = "metrics", feature = "trace"))]
use opentelemetry::{
metrics::MeterProvider as _,
global,
trace::{Span, Tracer, TracerProvider as _},
KeyValue,
};
Expand All @@ -22,17 +22,18 @@ fn init_trace() -> TracerProvider {
}

#[cfg(all(feature = "metrics", feature = "trace"))]
fn init_metrics() -> SdkMeterProvider {
fn init_metrics() {
let exporter = opentelemetry_stdout::MetricsExporter::default();
let reader = PeriodicReader::builder(exporter, runtime::Tokio).build();
SdkMeterProvider::builder().with_reader(reader).build()
let provider = SdkMeterProvider::builder().with_reader(reader).build();
global::set_meter_provider(provider);
}

#[tokio::main]
#[cfg(all(feature = "metrics", feature = "trace"))]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let tracer_provider = init_trace();
let meter_provider = init_metrics();
init_metrics();

let tracer = tracer_provider.tracer("stdout-test");
let mut span = tracer.start("test_span");
Expand All @@ -43,11 +44,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
);
span.end();

let meter = meter_provider.meter("stdout-test");
let meter = global::meter("stdout-test");
let c = meter.u64_counter("test_events").init();
c.add(1, &[KeyValue::new("test_key", "test_value")]);

meter_provider.shutdown()?;
global::shutdown_meter_provider();

Ok(())
}
Expand Down
5 changes: 5 additions & 0 deletions opentelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

## vNext

### Added

- [#1623](https://github.com/open-telemetry/opentelemetry-rust/pull/1623) Add global::meter_provider_shutdown

### Removed

- Remove `urlencoding` crate dependency. [#1613](https://github.com/open-telemetry/opentelemetry-rust/pull/1613)

## v0.22.0
Expand Down
7 changes: 6 additions & 1 deletion opentelemetry/src/global/metrics.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::metrics::{self, Meter, MeterProvider};
use crate::metrics::{self, noop::NoopMeterProvider, Meter, MeterProvider};
use crate::KeyValue;
use core::fmt;
use once_cell::sync::Lazy;
Expand Down Expand Up @@ -116,6 +116,11 @@
meter_provider().meter(name.into())
}

/// Shut down the current global [`MeterProvider`].
pub fn shutdown_meter_provider() {
set_meter_provider(NoopMeterProvider::new());
}

Check warning on line 122 in opentelemetry/src/global/metrics.rs

View check run for this annotation

Codecov / codecov/patch

opentelemetry/src/global/metrics.rs#L120-L122

Added lines #L120 - L122 were not covered by tests

/// Creates a [`Meter`] with the name, version and schema url.
///
/// - name SHOULD uniquely identify the instrumentation scope, such as the instrumentation library (e.g. io.opentelemetry.contrib.mongodb), package, module or class name.
Expand Down
Loading