Skip to content

Commit 14f6e00

Browse files
Add an example of how to connect to an external otlp using tonic, tls and tokio (#449)
Co-authored-by: Zhongyang Wu <[email protected]>
1 parent 181ac82 commit 14f6e00

File tree

4 files changed

+137
-0
lines changed

4 files changed

+137
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ members = [
1818
"examples/basic",
1919
"examples/basic-otlp",
2020
"examples/datadog",
21+
"examples/external-otlp-tonic-tokio",
2122
"examples/grpc",
2223
"examples/http",
2324
"examples/tracing-grpc",
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "external-otlp-tonic-tokio"
3+
version = "0.1.0"
4+
edition = "2018"
5+
6+
[dependencies]
7+
futures = "0.3"
8+
opentelemetry = { path = "../../opentelemetry", features = [
9+
"tokio-support",
10+
"metrics",
11+
"serialize"
12+
] }
13+
opentelemetry-otlp = { path = "../../opentelemetry-otlp", features = [
14+
"tonic",
15+
"tls",
16+
"tls-roots",
17+
] }
18+
serde_json = "1.0"
19+
tokio = { version = "1.0", features = ["full"] }
20+
tonic = "0.4.0"
21+
url = "2.2.0"
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# External OTLP collector with tonic and tokio with TLS
2+
3+
This example shows basic span, and exports to OTLP enabled collectors, like honeycomb, lightstep and other services.
4+
As these services all reside outside your own infrastructure, they require TLS for encryption to ensure your data safety.
5+
With this example, you can export to any service that supports OTLP by using environment variables.
6+
The following example exports data to Honeycomb:
7+
8+
```shell
9+
OTLP_TONIC_ENDPOINT=https://api.honeycomb.io:443 \
10+
OTLP_TONIC_X_HONEYCOMB_TEAM=token \
11+
OTLP_TONIC_X_HONEYCOMB_DATASET=dataset \'
12+
cargo run --bin external-otlp-tonic-tokio
13+
```
14+
15+
The only required variable is `OTLP_TONIC_ENDPOINT` and any other variable that beggins with the prefix `OTLP_TONIC_` will be sent as headers
16+
e.g.: `OTLP_TONIC_X_HONEYCOMB_TEAM` becomes `x-honeycomb-team` and `OTLP_TONIC_X_HONEYCOMB_DATASET` becomes `x-honeycomb-dataset`.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//! This should show how to connect to a third party collector like
2+
//! honeycomb or lightstep using tonic with tls and using tokio as reactor.
3+
//! To run this you have to specify a few environment variables like in the example:
4+
//! ```shell
5+
//! OTLP_TONIC_ENDPOINT=https://api.honeycomb.io:443 \
6+
//! OTLP_TONIC_X_HONEYCOMB_TEAM=token \
7+
//! OTLP_TONIC_X_HONEYCOMB_DATASET=dataset \'
8+
//! cargo run --bin external-otlp-tonic-tokio
9+
//! ```
10+
use opentelemetry::trace::TraceError;
11+
use opentelemetry::{global, sdk::trace as sdktrace};
12+
use opentelemetry::{
13+
trace::{TraceContextExt, Tracer},
14+
Key,
15+
};
16+
use tonic::{
17+
metadata::{MetadataKey, MetadataMap},
18+
transport::ClientTlsConfig,
19+
};
20+
use url::Url;
21+
22+
use std::{env::vars, str::FromStr, time::Duration};
23+
use std::{
24+
env::{remove_var, var},
25+
error::Error,
26+
};
27+
28+
// Use the variables to try and export the example to any external collector that accepts otlp
29+
// like: oltp itself, honeycomb or lightstep
30+
const ENDPOINT: &str = "OTLP_TONIC_ENDPOINT";
31+
const HEADER_PREFIX: &str = "OTLP_TONIC_";
32+
33+
fn init_tracer() -> Result<(sdktrace::Tracer, opentelemetry_otlp::Uninstall), TraceError> {
34+
let endpoint = var(ENDPOINT).unwrap_or_else(|_| {
35+
panic!(
36+
"You must specify and endpoint to connect to with the variable {:?}.",
37+
ENDPOINT
38+
)
39+
});
40+
let endpoint = Url::parse(&endpoint).expect("endpoint is not a valid url");
41+
remove_var(ENDPOINT);
42+
let mut metadata = MetadataMap::new();
43+
for (key, value) in vars()
44+
.filter(|(name, _)| name.starts_with(HEADER_PREFIX))
45+
.map(|(name, value)| {
46+
let header_name = name
47+
.strip_prefix(HEADER_PREFIX)
48+
.map(|h| h.replace("_", "-"))
49+
.map(|h| h.to_ascii_lowercase())
50+
.unwrap();
51+
(header_name, value)
52+
})
53+
{
54+
metadata.insert(MetadataKey::from_str(&key).unwrap(), value.parse().unwrap());
55+
}
56+
57+
opentelemetry_otlp::new_pipeline()
58+
.with_endpoint(endpoint.as_str())
59+
.with_metadata(dbg!(metadata))
60+
.with_tls_config(
61+
ClientTlsConfig::new().domain_name(
62+
endpoint
63+
.host_str()
64+
.expect("the specified endpoint should have a valid host"),
65+
),
66+
)
67+
.install()
68+
}
69+
70+
const LEMONS_KEY: Key = Key::from_static_str("ex.com/lemons");
71+
const ANOTHER_KEY: Key = Key::from_static_str("ex.com/another");
72+
73+
#[tokio::main]
74+
async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
75+
let (_, _guard) = init_tracer()?;
76+
77+
let tracer = global::tracer("ex.com/basic");
78+
79+
tracer.in_span("operation", |cx| {
80+
let span = cx.span();
81+
span.add_event(
82+
"Nice operation!".to_string(),
83+
vec![Key::new("bogons").i64(100)],
84+
);
85+
span.set_attribute(ANOTHER_KEY.string("yes"));
86+
87+
tracer.in_span("Sub operation...", |cx| {
88+
let span = cx.span();
89+
span.set_attribute(LEMONS_KEY.string("five"));
90+
91+
span.add_event("Sub span event".to_string(), vec![]);
92+
});
93+
});
94+
95+
// wait for 1 minutes so that we could see metrics being pushed via OTLP every 10 seconds.
96+
tokio::time::sleep(Duration::from_secs(60)).await;
97+
98+
Ok(())
99+
}

0 commit comments

Comments
 (0)