Skip to content

Commit 5816ba9

Browse files
committed
[opentelemetry-otlp] adds an example HTTP exporter backed by a Hyper 0.14 Client
Resolves open-telemetry#1659
1 parent b933bdd commit 5816ba9

File tree

5 files changed

+79
-16
lines changed

5 files changed

+79
-16
lines changed

opentelemetry-otlp/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ now use `.with_resource(RESOURCE::default())` to configure Resource when using
1616
These methods would also no longer set the global tracer provider. It would now be the responsibility of users to set it by calling `global::set_tracer_provider(tracer_provider.clone());`. Refer to the [basic-otlp](https://github.com/open-telemetry/opentelemetry-rust/blob/main/opentelemetry-otlp/examples/basic-otlp/src/main.rs) and [basic-otlp-http](https://github.com/open-telemetry/opentelemetry-rust/blob/main/opentelemetry-otlp/examples/basic-otlp-http/src/main.rs) examples on how to initialize OTLP Trace Exporter.
1717
- **Breaking** Correct the misspelling of "webkpi" to "webpki" in features [#1842](https://github.com/open-telemetry/opentelemetry-rust/pull/1842)
1818
- Bump MSRV to 1.70 [#1840](https://github.com/open-telemetry/opentelemetry-rust/pull/1840)
19+
- Adds `hyper` feature to the basic-otlp-http example showing how to export with a custom Hyper Client
1920

2021
## v0.16.0
2122

opentelemetry-otlp/examples/basic-otlp-http/Cargo.toml

+11
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,25 @@ edition = "2021"
55
license = "Apache-2.0"
66
publish = false
77

8+
[features]
9+
default = ["reqwest"]
10+
reqwest = ["opentelemetry-otlp/reqwest-client"]
11+
hyper = ["dep:async-trait", "dep:http", "dep:hyper", "dep:opentelemetry-http", "dep:bytes"]
12+
13+
814
[dependencies]
915
once_cell = { workspace = true }
1016
opentelemetry = { path = "../../../opentelemetry" }
1117
opentelemetry_sdk = { path = "../../../opentelemetry-sdk", features = ["rt-tokio", "metrics", "logs"] }
18+
opentelemetry-http = { path = "../../../opentelemetry-http", optional = true }
1219
opentelemetry-otlp = { path = "../..", features = ["http-proto", "reqwest-client", "logs"] }
1320
opentelemetry-appender-tracing = { path = "../../../opentelemetry-appender-tracing", default-features = false}
1421
opentelemetry-semantic-conventions = { path = "../../../opentelemetry-semantic-conventions" }
1522

23+
async-trait = { workspace = true, optional = true }
24+
bytes = { workspace = true, optional = true }
25+
http = { workspace = true, optional = true }
26+
hyper = { workspace = true, features = ["client"], optional = true }
1627
tokio = { workspace = true, features = ["full"] }
1728
tracing = { workspace = true, features = ["std"]}
1829
tracing-core = { workspace = true }

opentelemetry-otlp/examples/basic-otlp-http/README.md

+8
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ Run the app which exports logs, metrics and traces via OTLP to the collector
5252
cargo run
5353
```
5454

55+
56+
By default the app will use a `reqwest` client to send. A hyper 0.14 client can be used with the `hyper` feature enabled
57+
58+
```shell
59+
cargo run --no-default-features --features=hyper
60+
```
61+
62+
5563
## View results
5664

5765
You should be able to see something similar below with different time and ID in the same console that docker runs.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use async_trait::async_trait;
2+
use bytes::Bytes;
3+
use http::{Request, Response};
4+
use hyper::{
5+
client::{connect::Connect, HttpConnector},
6+
Body, Client,
7+
};
8+
use opentelemetry_http::{HttpClient, HttpError, ResponseExt};
9+
10+
pub struct HyperClient<C> {
11+
inner: hyper::Client<C>,
12+
}
13+
14+
impl Default for HyperClient<HttpConnector> {
15+
fn default() -> Self {
16+
Self {
17+
inner: Client::new(),
18+
}
19+
}
20+
}
21+
22+
impl<C> std::fmt::Debug for HyperClient<C> {
23+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24+
f.debug_struct("HyperClient")
25+
.field("inner", &self.inner)
26+
.finish()
27+
}
28+
}
29+
30+
#[async_trait]
31+
impl<C: Connect + Clone + Send + Sync + 'static> HttpClient for HyperClient<C> {
32+
async fn send(&self, request: Request<Vec<u8>>) -> Result<Response<Bytes>, HttpError> {
33+
let request = request.map(Body::from);
34+
35+
let (parts, body) = self
36+
.inner
37+
.request(request)
38+
.await?
39+
.error_for_status()?
40+
.into_parts();
41+
let body = hyper::body::to_bytes(body).await?;
42+
43+
Ok(Response::from_parts(parts, body))
44+
}
45+
}

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

+14-16
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use opentelemetry::{
66
Key, KeyValue,
77
};
88
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
9-
use opentelemetry_otlp::WithExportConfig;
9+
use opentelemetry_otlp::{HttpExporterBuilder, WithExportConfig};
1010
use opentelemetry_sdk::trace::{self as sdktrace, Config};
1111
use opentelemetry_sdk::{
1212
logs::{self as sdklogs},
@@ -18,45 +18,43 @@ use tracing_subscriber::EnvFilter;
1818

1919
use std::error::Error;
2020

21+
#[cfg(feature = "hyper")]
22+
mod hyper;
23+
2124
static RESOURCE: Lazy<Resource> = Lazy::new(|| {
2225
Resource::new(vec![KeyValue::new(
2326
opentelemetry_semantic_conventions::resource::SERVICE_NAME,
2427
"basic-otlp-example",
2528
)])
2629
});
2730

31+
fn http_exporter() -> HttpExporterBuilder {
32+
let exporter = opentelemetry_otlp::new_exporter().http();
33+
#[cfg(feature = "hyper")]
34+
let exporter = exporter.with_http_client(hyper::HyperClient::default());
35+
exporter
36+
}
37+
2838
fn init_logs() -> Result<sdklogs::LoggerProvider, opentelemetry::logs::LogError> {
2939
opentelemetry_otlp::new_pipeline()
3040
.logging()
3141
.with_resource(RESOURCE.clone())
32-
.with_exporter(
33-
opentelemetry_otlp::new_exporter()
34-
.http()
35-
.with_endpoint("http://localhost:4318/v1/logs"),
36-
)
42+
.with_exporter(http_exporter().with_endpoint("http://localhost:4318/v1/logs"))
3743
.install_batch(opentelemetry_sdk::runtime::Tokio)
3844
}
3945

4046
fn init_tracer_provider() -> Result<sdktrace::TracerProvider, TraceError> {
4147
opentelemetry_otlp::new_pipeline()
4248
.tracing()
43-
.with_exporter(
44-
opentelemetry_otlp::new_exporter()
45-
.http()
46-
.with_endpoint("http://localhost:4318/v1/traces"),
47-
)
49+
.with_exporter(http_exporter().with_endpoint("http://localhost:4318/v1/traces"))
4850
.with_trace_config(Config::default().with_resource(RESOURCE.clone()))
4951
.install_batch(opentelemetry_sdk::runtime::Tokio)
5052
}
5153

5254
fn init_metrics() -> Result<opentelemetry_sdk::metrics::SdkMeterProvider, MetricsError> {
5355
let provider = opentelemetry_otlp::new_pipeline()
5456
.metrics(opentelemetry_sdk::runtime::Tokio)
55-
.with_exporter(
56-
opentelemetry_otlp::new_exporter()
57-
.http()
58-
.with_endpoint("http://localhost:4318/v1/metrics"),
59-
)
57+
.with_exporter(http_exporter().with_endpoint("http://localhost:4318/v1/metrics"))
6058
.with_resource(RESOURCE.clone())
6159
.build();
6260
match provider {

0 commit comments

Comments
 (0)