Skip to content

Commit a76b1fc

Browse files
committed
avoid new runtime creation in shutdown
1 parent a716211 commit a76b1fc

File tree

5 files changed

+35
-64
lines changed

5 files changed

+35
-64
lines changed

opentelemetry-otlp/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44

55
- The `OTEL_EXPORTER_OTLP_TIMEOUT`, `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT`, `OTEL_EXPORTER_OTLP_METRICS_TIMEOUT` and `OTEL_EXPORTER_OTLP_LOGS_TIMEOUT` are changed from seconds to miliseconds.
66
- Fixed `.with_headers()` in `HttpExporterBuilder` to correctly support multiple key/value pairs. [#2699](https://github.com/open-telemetry/opentelemetry-rust/pull/2699)
7+
- Fixed
8+
[#2770](https://github.com/open-telemetry/opentelemetry-rust/issues/2770) to
9+
properly handle `shutdown()`. When using gRPC/tonic, `shutdown()` must now be
10+
called from a Tokio runtime. Previously, it was required to initialize the
11+
provider from a Tokio runtime, and this requirement is now extended to
12+
`shutdown()` as well.
713

814
## 0.28.0
915

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

Lines changed: 6 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,12 @@ fn init_logs() -> SdkLoggerProvider {
5959
.build()
6060
}
6161

62-
#[tokio::main]
63-
async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
64-
let logger_provider = init_logs();
62+
// #[tokio::main]
63+
fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
64+
let rt = tokio::runtime::Runtime::new()?;
65+
let logger_provider = rt.block_on(async {
66+
init_logs()
67+
});
6568

6669
// Create a new OpenTelemetryTracingBridge using the above LoggerProvider.
6770
let otel_layer = OpenTelemetryTracingBridge::new(&logger_provider);
@@ -98,66 +101,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
98101
.with(otel_layer)
99102
.with(fmt_layer)
100103
.init();
101-
102-
// At this point Logs (OTel Logs and Fmt Logs) are initialized, which will
103-
// allow internal-logs from Tracing/Metrics initializer to be captured.
104-
105-
let tracer_provider = init_traces();
106-
// Set the global tracer provider using a clone of the tracer_provider.
107-
// Setting global tracer provider is required if other parts of the application
108-
// uses global::tracer() or global::tracer_with_version() to get a tracer.
109-
// Cloning simply creates a new reference to the same tracer provider. It is
110-
// important to hold on to the tracer_provider here, so as to invoke
111-
// shutdown on it when application ends.
112-
global::set_tracer_provider(tracer_provider.clone());
113-
114-
let meter_provider = init_metrics();
115-
// Set the global meter provider using a clone of the meter_provider.
116-
// Setting global meter provider is required if other parts of the application
117-
// uses global::meter() or global::meter_with_version() to get a meter.
118-
// Cloning simply creates a new reference to the same meter provider. It is
119-
// important to hold on to the meter_provider here, so as to invoke
120-
// shutdown on it when application ends.
121-
global::set_meter_provider(meter_provider.clone());
122-
123-
let common_scope_attributes = vec![KeyValue::new("scope-key", "scope-value")];
124-
let scope = InstrumentationScope::builder("basic")
125-
.with_version("1.0")
126-
.with_attributes(common_scope_attributes)
127-
.build();
128-
129-
let tracer = global::tracer_with_scope(scope.clone());
130-
let meter = global::meter_with_scope(scope);
131-
132-
let counter = meter
133-
.u64_counter("test_counter")
134-
.with_description("a simple counter for demo purposes.")
135-
.with_unit("my_unit")
136-
.build();
137-
for _ in 0..10 {
138-
counter.add(1, &[KeyValue::new("test_key", "test_value")]);
139-
}
140-
141-
tracer.in_span("Main operation", |cx| {
142-
let span = cx.span();
143-
span.add_event(
144-
"Nice operation!".to_string(),
145-
vec![KeyValue::new("bogons", 100)],
146-
);
147-
span.set_attribute(KeyValue::new("another.key", "yes"));
148-
149-
info!(name: "my-event-inside-span", target: "my-target", "hello from {}. My price is {}. I am also inside a Span!", "banana", 2.99);
150-
151-
tracer.in_span("Sub operation...", |cx| {
152-
let span = cx.span();
153-
span.set_attribute(KeyValue::new("another.key", "yes"));
154-
span.add_event("Sub span event", vec![]);
155-
});
156-
});
157-
158104
info!(name: "my-event", target: "my-target", "hello from {}. My price is {}", "apple", 1.99);
159-
tracer_provider.shutdown()?;
160-
meter_provider.shutdown()?;
161105
logger_provider.shutdown()?;
162106

163107
Ok(())

opentelemetry-otlp/src/exporter/tonic/logs.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,16 @@ impl LogExporter for TonicLogsClient {
8585
}
8686

8787
fn shutdown(&self) -> OTelSdkResult {
88-
let handle = tokio::runtime::Handle::try_current()
89-
.unwrap_or_else(|_| tokio::runtime::Runtime::new().unwrap().handle().clone());
88+
otel_debug!(name: "TonicsLogsClient.Shutdown");
89+
let handle = match tokio::runtime::Handle::try_current() {
90+
Ok(handle) => handle,
91+
Err(e) => {
92+
return Err(OTelSdkError::InternalFailure(format!(
93+
"Shutdown must be called from a tokio runtime: {:?}",
94+
e
95+
)));
96+
}
97+
};
9098

9199
let mut inner = handle.block_on(self.inner.lock());
92100
match inner.take() {

opentelemetry-otlp/src/logs.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,13 @@ impl opentelemetry_sdk::logs::LogExporter for LogExporter {
156156
SupportedTransportClient::Http(client) => client.set_resource(resource),
157157
}
158158
}
159+
160+
fn shutdown(&self) -> OTelSdkResult {
161+
match &self.client {
162+
#[cfg(feature = "grpc-tonic")]
163+
SupportedTransportClient::Tonic(client) => client.shutdown(),
164+
#[cfg(any(feature = "http-proto", feature = "http-json"))]
165+
SupportedTransportClient::Http(client) => client.shutdown(),
166+
}
167+
}
159168
}

opentelemetry-sdk/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@
6060
`LogProcessor` and `LogExporter` traits. `SdkLogger` no longer passes its
6161
`scope` name but instead passes the incoming `name` when invoking
6262
`event_enabled` on processors.
63+
- **Breaking** for custom LogExporter authors: `shutdown()` method in
64+
`LogExporter` trait no longer requires a mutable ref to self. If the exporter
65+
needs to mutate state, it should rely on interior mutability.
66+
[2764](https://github.com/open-telemetry/opentelemetry-rust/pull/2764)
6367

6468
## 0.28.0
6569

0 commit comments

Comments
 (0)