Skip to content

Commit 7b11341

Browse files
authored
Merge branch 'main' into fix-metrics-u64-serialization
2 parents fa0de1e + b017c7b commit 7b11341

File tree

37 files changed

+1191
-687
lines changed

37 files changed

+1191
-687
lines changed

README.md

+7-6
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,10 @@ Project versioning information and stability guarantees can be found
6565
## Getting Started
6666

6767
```rust
68-
use opentelemetry::{
69-
global,
70-
trace::{Tracer, TracerProvider as _},
68+
use opentelemetry::trace::{
69+
TraceContextExt,
70+
Tracer,
71+
TracerProvider as _,
7172
};
7273
use opentelemetry_sdk::trace::TracerProvider;
7374

@@ -92,9 +93,9 @@ The example above requires the following packages:
9293
```toml
9394
# Cargo.toml
9495
[dependencies]
95-
opentelemetry = "0.22"
96-
opentelemetry_sdk = "0.22"
97-
opentelemetry-stdout = { version = "0.3", features = ["trace"] }
96+
opentelemetry = "0.27"
97+
opentelemetry_sdk = "0.27"
98+
opentelemetry-stdout = { version = "0.27", features = ["trace"] }
9899
```
99100

100101
See the [examples](./examples) directory for different integration patterns.

examples/metrics-advanced/src/main.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,12 @@ fn init_meter_provider() -> opentelemetry_sdk::metrics::SdkMeterProvider {
4949
.with_temporality(Temporality::Delta)
5050
.build();
5151

52-
let reader = PeriodicReader::builder(exporter).build();
53-
5452
let resource = Resource::builder()
5553
.with_service_name("metrics-advanced-example")
5654
.build();
5755

5856
let provider = SdkMeterProvider::builder()
59-
.with_reader(reader)
57+
.with_periodic_exporter(exporter)
6058
.with_resource(resource)
6159
.with_view(my_view_rename_and_unit)
6260
.with_view(my_view_drop_attributes)

examples/metrics-basic/src/main.rs

+38-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use opentelemetry::{global, KeyValue};
2+
use opentelemetry_sdk::error::ShutdownError;
23
use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider};
34
use opentelemetry_sdk::Resource;
45
use std::error::Error;
@@ -9,9 +10,8 @@ fn init_meter_provider() -> opentelemetry_sdk::metrics::SdkMeterProvider {
910
// Build exporter using Delta Temporality (Defaults to Temporality::Cumulative)
1011
// .with_temporality(opentelemetry_sdk::metrics::Temporality::Delta)
1112
.build();
12-
let reader = PeriodicReader::builder(exporter).build();
1313
let provider = SdkMeterProvider::builder()
14-
.with_reader(reader)
14+
.with_periodic_exporter(exporter)
1515
.with_resource(
1616
Resource::builder()
1717
.with_service_name("metrics-basic-example")
@@ -23,7 +23,7 @@ fn init_meter_provider() -> opentelemetry_sdk::metrics::SdkMeterProvider {
2323
}
2424

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

@@ -137,9 +137,41 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
137137
})
138138
.build();
139139

140-
// Metrics are exported by default every 30 seconds when using stdout exporter,
141-
// however shutting down the MeterProvider here instantly flushes
142-
// the metrics, instead of waiting for the 30 sec interval.
140+
// Metrics are exported by default every 30 seconds when using stdout
141+
// exporter, however shutting down the MeterProvider here instantly flushes
142+
// the metrics, instead of waiting for the 30 sec interval. Shutdown returns
143+
// a result, which is bubbled up to the caller The commented code below
144+
// demonstrates handling the shutdown result, instead of bubbling up the
145+
// error.
143146
meter_provider.shutdown()?;
147+
148+
// let shutdown_result = meter_provider.shutdown();
149+
150+
// Handle the shutdown result.
151+
// match shutdown_result {
152+
// Ok(_) => println!("MeterProvider shutdown successfully"),
153+
// Err(e) => {
154+
// match e {
155+
// opentelemetry_sdk::error::ShutdownError::InternalFailure(message) => {
156+
// // This indicates some internal failure during shutdown. The
157+
// // error message is intended for logging purposes only and
158+
// // should not be used to make programmatic decisions.
159+
// println!("MeterProvider shutdown failed: {}", message)
160+
// }
161+
// opentelemetry_sdk::error::ShutdownError::AlreadyShutdown => {
162+
// // This indicates some user code tried to shutdown
163+
// // elsewhere. user need to review their code to ensure
164+
// // shutdown is called only once.
165+
// println!("MeterProvider already shutdown")
166+
// }
167+
// opentelemetry_sdk::error::ShutdownError::Timeout(e) => {
168+
// // This indicates the shutdown timed out, and a good hint to
169+
// // user to increase the timeout. (Shutdown method does not
170+
// // allow custom timeout today, but that is temporary)
171+
// println!("MeterProvider shutdown timed out after {:?}", e)
172+
// }
173+
// }
174+
// }
175+
// }
144176
Ok(())
145177
}

opentelemetry-otlp/CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@
1313
- Remove unnecessarily public trait `opentelemetry_otlp::metrics::MetricsClient`
1414
and `MetricExporter::new(..)` method. Use
1515
`MetricExporter::builder()...build()` to obtain `MetricExporter`.
16+
- The HTTP clients (reqwest, reqwest-blocking, hyper) now support the
17+
timeout internal configured in below order
18+
- Signal specific env variable `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT`,
19+
`OTEL_EXPORTER_OTLP_LOGS_TIMEOUT` or `OTEL_EXPORTER_OTLP_TIMEOUT`.
20+
- `OTEL_EXPORTER_OTLP_TIMEOUT` env variable.
21+
- `with_http().with_timeout()` API method of
22+
`LogExporterBuilder` and `SpanExporterBuilder` and `MetricsExporterBuilder`.
23+
- The default interval of 10sec is used if none is configured.
24+
1625

1726
## 0.27.0
1827

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

+1-3
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,8 @@ fn init_metrics() -> Result<opentelemetry_sdk::metrics::SdkMeterProvider, Metric
6161
.with_endpoint("http://localhost:4318/v1/metrics")
6262
.build()?;
6363

64-
let reader = opentelemetry_sdk::metrics::PeriodicReader::builder(exporter).build();
65-
6664
Ok(SdkMeterProvider::builder()
67-
.with_reader(reader)
65+
.with_periodic_exporter(exporter)
6866
.with_resource(RESOURCE.clone())
6967
.build())
7068
}

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ fn init_traces() -> Result<sdktrace::TracerProvider, TraceError> {
3333

3434
fn init_metrics() -> Result<opentelemetry_sdk::metrics::SdkMeterProvider, MetricError> {
3535
let exporter = MetricExporter::builder().with_tonic().build()?;
36-
let reader = PeriodicReader::builder(exporter).build();
3736

3837
Ok(SdkMeterProvider::builder()
39-
.with_reader(reader)
38+
.with_periodic_exporter(exporter)
4039
.with_resource(RESOURCE.clone())
4140
.build())
4241
}

opentelemetry-otlp/src/exporter/http/metrics.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::sync::Arc;
33
use async_trait::async_trait;
44
use http::{header::CONTENT_TYPE, Method};
55
use opentelemetry::otel_debug;
6+
use opentelemetry_sdk::error::{ShutdownError, ShutdownResult};
67
use opentelemetry_sdk::metrics::data::ResourceMetrics;
78
use opentelemetry_sdk::metrics::{MetricError, MetricResult};
89

@@ -43,8 +44,11 @@ impl MetricsClient for OtlpHttpClient {
4344
Ok(())
4445
}
4546

46-
fn shutdown(&self) -> MetricResult<()> {
47-
let _ = self.client.lock()?.take();
47+
fn shutdown(&self) -> ShutdownResult {
48+
self.client
49+
.lock()
50+
.map_err(|e| ShutdownError::InternalFailure(format!("Failed to acquire lock: {}", e)))?
51+
.take();
4852

4953
Ok(())
5054
}

opentelemetry-otlp/src/exporter/http/mod.rs

+51-52
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,7 @@ mod trace;
4444
use opentelemetry_http::hyper::HyperClient;
4545

4646
/// Configuration of the http transport
47-
#[derive(Debug)]
48-
#[cfg_attr(
49-
all(
50-
not(feature = "reqwest-client"),
51-
not(feature = "reqwest-blocking-client"),
52-
not(feature = "hyper-client")
53-
),
54-
derive(Default)
55-
)]
47+
#[derive(Debug, Default)]
5648
pub struct HttpConfig {
5749
/// Select the HTTP client
5850
client: Option<Arc<dyn HttpClient>>,
@@ -61,44 +53,6 @@ pub struct HttpConfig {
6153
headers: Option<HashMap<String, String>>,
6254
}
6355

64-
#[cfg(any(
65-
feature = "reqwest-blocking-client",
66-
feature = "reqwest-client",
67-
feature = "hyper-client"
68-
))]
69-
impl Default for HttpConfig {
70-
fn default() -> Self {
71-
#[cfg(feature = "reqwest-blocking-client")]
72-
let default_client = std::thread::spawn(|| {
73-
Some(Arc::new(reqwest::blocking::Client::new()) as Arc<dyn HttpClient>)
74-
})
75-
.join()
76-
.expect("creating reqwest::blocking::Client on a new thread not to fail");
77-
#[cfg(all(not(feature = "reqwest-blocking-client"), feature = "reqwest-client"))]
78-
let default_client = Some(Arc::new(reqwest::Client::new()) as Arc<dyn HttpClient>);
79-
#[cfg(all(
80-
not(feature = "reqwest-client"),
81-
not(feature = "reqwest-blocking-client"),
82-
feature = "hyper-client"
83-
))]
84-
// TODO - support configuring custom connector and executor
85-
let default_client = Some(Arc::new(HyperClient::with_default_connector(
86-
Duration::from_secs(10),
87-
None,
88-
)) as Arc<dyn HttpClient>);
89-
#[cfg(all(
90-
not(feature = "reqwest-client"),
91-
not(feature = "reqwest-blocking-client"),
92-
not(feature = "hyper-client")
93-
))]
94-
let default_client = None;
95-
HttpConfig {
96-
client: default_client,
97-
headers: None,
98-
}
99-
}
100-
}
101-
10256
/// Configuration for the OTLP HTTP exporter.
10357
///
10458
/// ## Examples
@@ -171,11 +125,56 @@ impl HttpExporterBuilder {
171125
},
172126
None => self.exporter_config.timeout,
173127
};
174-
let http_client = self
175-
.http_config
176-
.client
177-
.take()
178-
.ok_or(crate::Error::NoHttpClient)?;
128+
129+
#[allow(unused_mut)] // TODO - clippy thinks mut is not needed, but it is
130+
let mut http_client = self.http_config.client.take();
131+
132+
if http_client.is_none() {
133+
#[cfg(all(
134+
not(feature = "reqwest-client"),
135+
not(feature = "reqwest-blocking-client"),
136+
feature = "hyper-client"
137+
))]
138+
{
139+
// TODO - support configuring custom connector and executor
140+
http_client = Some(Arc::new(HyperClient::with_default_connector(timeout, None))
141+
as Arc<dyn HttpClient>);
142+
}
143+
#[cfg(all(
144+
not(feature = "hyper-client"),
145+
not(feature = "reqwest-blocking-client"),
146+
feature = "reqwest-client"
147+
))]
148+
{
149+
http_client = Some(Arc::new(
150+
reqwest::Client::builder()
151+
.timeout(timeout)
152+
.build()
153+
.unwrap_or_default(),
154+
) as Arc<dyn HttpClient>);
155+
}
156+
#[cfg(all(
157+
not(feature = "hyper-client"),
158+
not(feature = "reqwest-client"),
159+
feature = "reqwest-blocking-client"
160+
))]
161+
{
162+
let timeout_clone = timeout;
163+
http_client = Some(Arc::new(
164+
std::thread::spawn(move || {
165+
reqwest::blocking::Client::builder()
166+
.timeout(timeout_clone)
167+
.build()
168+
.unwrap_or_else(|_| reqwest::blocking::Client::new())
169+
})
170+
.join()
171+
.unwrap(), // Unwrap thread result
172+
) as Arc<dyn HttpClient>);
173+
}
174+
}
175+
176+
let http_client = http_client.ok_or(crate::Error::NoHttpClient)?;
177+
179178
#[allow(clippy::mutable_key_type)] // http headers are not mutated
180179
let mut headers: HashMap<HeaderName, HeaderValue> = self
181180
.http_config

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use opentelemetry::otel_debug;
66
use opentelemetry_proto::tonic::collector::metrics::v1::{
77
metrics_service_client::MetricsServiceClient, ExportMetricsServiceRequest,
88
};
9+
use opentelemetry_sdk::error::{ShutdownError, ShutdownResult};
910
use opentelemetry_sdk::metrics::data::ResourceMetrics;
1011
use opentelemetry_sdk::metrics::{MetricError, MetricResult};
1112
use tonic::{codegen::CompressionEncoding, service::Interceptor, transport::Channel, Request};
@@ -89,8 +90,11 @@ impl MetricsClient for TonicMetricsClient {
8990
Ok(())
9091
}
9192

92-
fn shutdown(&self) -> MetricResult<()> {
93-
let _ = self.inner.lock()?.take();
93+
fn shutdown(&self) -> ShutdownResult {
94+
self.inner
95+
.lock()
96+
.map_err(|e| ShutdownError::InternalFailure(format!("Failed to acquire lock: {}", e)))?
97+
.take();
9498

9599
Ok(())
96100
}

opentelemetry-otlp/src/metric.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::NoExporterBuilderSet;
1616

1717
use async_trait::async_trait;
1818
use core::fmt;
19+
use opentelemetry_sdk::error::ShutdownResult;
1920
use opentelemetry_sdk::metrics::MetricResult;
2021

2122
use opentelemetry_sdk::metrics::{
@@ -123,7 +124,7 @@ impl HasHttpConfig for MetricExporterBuilder<HttpExporterBuilderSet> {
123124
#[async_trait]
124125
pub(crate) trait MetricsClient: fmt::Debug + Send + Sync + 'static {
125126
async fn export(&self, metrics: &mut ResourceMetrics) -> MetricResult<()>;
126-
fn shutdown(&self) -> MetricResult<()>;
127+
fn shutdown(&self) -> ShutdownResult;
127128
}
128129

129130
/// Export metrics in OTEL format.
@@ -149,7 +150,7 @@ impl PushMetricExporter for MetricExporter {
149150
Ok(())
150151
}
151152

152-
fn shutdown(&self) -> MetricResult<()> {
153+
fn shutdown(&self) -> ShutdownResult {
153154
self.client.shutdown()
154155
}
155156

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
pub mod logs_asserter;
2-
pub mod metrics_asserter;
2+
pub mod metric_helpers;
33
pub mod test_utils;
44
pub mod trace_asserter;

0 commit comments

Comments
 (0)