Skip to content

Commit 972a97e

Browse files
committed
feat!(init-tracing-opentelemetry): no longer default configuration, delegate interpretation of environment variables to setup endpoint to opentelementry.
Continue to detecte protocol, to initialize (or not) the Span exporter
1 parent c2bae4b commit 972a97e

File tree

2 files changed

+62
-148
lines changed

2 files changed

+62
-148
lines changed
+60-143
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
use std::{collections::HashMap, str::FromStr};
2-
31
use opentelemetry::trace::TraceError;
4-
use opentelemetry_otlp::{SpanExporter, WithHttpConfig};
5-
use opentelemetry_sdk::{trace::Sampler, trace::TracerProvider, Resource};
2+
use opentelemetry_otlp::SpanExporter;
3+
use opentelemetry_sdk::{trace::TracerProvider, Resource};
64
#[cfg(feature = "tls")]
75
use {opentelemetry_otlp::WithTonicConfig, tonic::transport::ClientTlsConfig};
86

@@ -19,62 +17,44 @@ pub fn init_tracerprovider<F>(
1917
where
2018
F: FnOnce(opentelemetry_sdk::trace::Builder) -> opentelemetry_sdk::trace::Builder,
2119
{
22-
use opentelemetry_otlp::WithExportConfig;
23-
20+
debug_env();
2421
let (maybe_protocol, maybe_endpoint) = read_protocol_and_endpoint_from_env();
25-
let (protocol, endpoint) =
26-
infer_protocol_and_endpoint(maybe_protocol.as_deref(), maybe_endpoint.as_deref());
27-
tracing::debug!(target: "otel::setup", OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = endpoint);
28-
tracing::debug!(target: "otel::setup", OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = protocol);
29-
let exporter: SpanExporter = match protocol.as_str() {
30-
"http/protobuf" => SpanExporter::builder()
31-
.with_http()
32-
.with_endpoint(endpoint)
33-
.with_headers(read_headers_from_env())
34-
.build()?,
22+
let protocol = infer_protocol(maybe_protocol.as_deref(), maybe_endpoint.as_deref());
23+
24+
let exporter: Option<SpanExporter> = match protocol.as_deref() {
25+
Some("http/protobuf") => Some(SpanExporter::builder().with_http().build()?),
3526
#[cfg(feature = "tls")]
36-
"grpc/tls" => SpanExporter::builder()
37-
.with_tonic()
38-
.with_tls_config(ClientTlsConfig::new().with_native_roots())
39-
.with_endpoint(endpoint)
40-
.build()?,
41-
_ => SpanExporter::builder()
42-
.with_tonic()
43-
.with_endpoint(endpoint)
44-
.build()?,
27+
Some("grpc/tls") => Some(
28+
SpanExporter::builder()
29+
.with_tonic()
30+
.with_tls_config(ClientTlsConfig::new().with_native_roots())
31+
.build()?,
32+
),
33+
Some("grpc") => Some(SpanExporter::builder().with_tonic().build()?),
34+
Some(x) => {
35+
tracing::warn!("unknown '{x}' env var set or infered for OTEL_EXPORTER_OTLP_TRACES_PROTOCOL or OTEL_EXPORTER_OTLP_PROTOCOL; no span exporter will be created");
36+
None
37+
}
38+
None => {
39+
tracing::warn!("no env var set or infered for OTEL_EXPORTER_OTLP_TRACES_PROTOCOL or OTEL_EXPORTER_OTLP_PROTOCOL; no span exporter will be created");
40+
None
41+
}
4542
};
46-
47-
let mut trace_provider: opentelemetry_sdk::trace::Builder = TracerProvider::builder()
48-
.with_config(
49-
opentelemetry_sdk::trace::Config::default()
50-
.with_resource(resource)
51-
.with_sampler(read_sampler_from_env()),
52-
)
53-
.with_batch_exporter(exporter, opentelemetry_sdk::runtime::Tokio);
43+
let mut trace_provider: opentelemetry_sdk::trace::Builder =
44+
TracerProvider::builder().with_resource(resource);
45+
if let Some(exporter) = exporter {
46+
trace_provider =
47+
trace_provider.with_batch_exporter(exporter, opentelemetry_sdk::runtime::Tokio);
48+
}
5449

5550
trace_provider = transform(trace_provider);
5651
Ok(trace_provider.build())
5752
}
5853

59-
/// turn a string of "k1=v1,k2=v2,..." into an iterator of (key, value) tuples
60-
fn parse_headers(val: &str) -> impl Iterator<Item = (String, String)> + '_ {
61-
val.split(',').filter_map(|kv| {
62-
let s = kv
63-
.split_once('=')
64-
.map(|(k, v)| (k.to_owned(), v.to_owned()));
65-
s
66-
})
67-
}
68-
69-
fn read_headers_from_env() -> HashMap<String, String> {
70-
let mut headers = HashMap::new();
71-
headers.extend(parse_headers(
72-
&std::env::var("OTEL_EXPORTER_OTLP_HEADERS").unwrap_or_default(),
73-
));
74-
headers.extend(parse_headers(
75-
&std::env::var("OTEL_EXPORTER_OTLP_TRACES_HEADERS").unwrap_or_default(),
76-
));
77-
headers
54+
pub fn debug_env() {
55+
std::env::vars()
56+
.filter(|(k, _)| k.starts_with("OTEL_"))
57+
.for_each(|(k, v)| tracing::debug!(target: "otel::setup::env", key = %k, value = %v));
7858
}
7959

8060
fn read_protocol_and_endpoint_from_env() -> (Option<String>, Option<String>) {
@@ -94,68 +74,27 @@ fn read_protocol_and_endpoint_from_env() -> (Option<String>, Option<String>) {
9474
(maybe_protocol, maybe_endpoint)
9575
}
9676

97-
/// see <https://opentelemetry.io/docs/reference/specification/sdk-environment-variables/#general-sdk-configuration>
98-
/// TODO log error and infered sampler
99-
fn read_sampler_from_env() -> Sampler {
100-
let mut name = std::env::var("OTEL_TRACES_SAMPLER")
101-
.ok()
102-
.unwrap_or_default()
103-
.to_lowercase();
104-
let v = match name.as_str() {
105-
"always_on" => Sampler::AlwaysOn,
106-
"always_off" => Sampler::AlwaysOff,
107-
"traceidratio" => Sampler::TraceIdRatioBased(read_sampler_arg_from_env(1f64)),
108-
"parentbased_always_on" => Sampler::ParentBased(Box::new(Sampler::AlwaysOn)),
109-
"parentbased_always_off" => Sampler::ParentBased(Box::new(Sampler::AlwaysOff)),
110-
"parentbased_traceidratio" => Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(
111-
read_sampler_arg_from_env(1f64),
112-
))),
113-
"jaeger_remote" => todo!("unsupported: OTEL_TRACES_SAMPLER='jaeger_remote'"),
114-
"xray" => todo!("unsupported: OTEL_TRACES_SAMPLER='xray'"),
115-
_ => {
116-
name = "parentbased_always_on".to_string();
117-
Sampler::ParentBased(Box::new(Sampler::AlwaysOn))
77+
#[allow(unused_mut)]
78+
fn infer_protocol(maybe_protocol: Option<&str>, maybe_endpoint: Option<&str>) -> Option<String> {
79+
let mut maybe_protocol = match (maybe_protocol, maybe_endpoint) {
80+
(Some(protocol), _) => Some(protocol.to_string()),
81+
(None, Some(endpoint)) => {
82+
if endpoint.contains(":4317") {
83+
Some("grpc".to_string())
84+
} else {
85+
Some("http/protobuf".to_string())
86+
}
11887
}
88+
_ => None,
11989
};
120-
tracing::debug!(target: "otel::setup", OTEL_TRACES_SAMPLER = name);
121-
v
122-
}
123-
124-
fn read_sampler_arg_from_env<T>(default: T) -> T
125-
where
126-
T: FromStr + Copy + std::fmt::Debug,
127-
{
128-
//TODO Log for invalid value (how to log)
129-
let v = std::env::var("OTEL_TRACES_SAMPLER_ARG")
130-
.map_or(default, |s| T::from_str(&s).unwrap_or(default));
131-
tracing::debug!(target: "otel::setup", OTEL_TRACES_SAMPLER_ARG = ?v);
132-
v
133-
}
134-
135-
fn infer_protocol_and_endpoint(
136-
maybe_protocol: Option<&str>,
137-
maybe_endpoint: Option<&str>,
138-
) -> (String, String) {
139-
#[cfg_attr(not(feature = "tls"), allow(unused_mut))]
140-
let mut protocol = maybe_protocol.unwrap_or_else(|| {
141-
if maybe_endpoint.map_or(false, |e| e.contains(":4317")) {
142-
"grpc"
143-
} else {
144-
"http/protobuf"
145-
}
146-
});
147-
14890
#[cfg(feature = "tls")]
149-
if protocol == "grpc" && maybe_endpoint.unwrap_or("").starts_with("https") {
150-
protocol = "grpc/tls";
91+
if maybe_protocol.as_deref() == Some("grpc")
92+
&& maybe_endpoint.is_some_and(|e| e.starts_with("https"))
93+
{
94+
maybe_protocol = Some("grpc/tls".to_string());
15195
}
15296

153-
let endpoint = match protocol {
154-
"http/protobuf" => maybe_endpoint.unwrap_or("http://localhost:4318/v1/traces"), //Devskim: ignore DS137138
155-
_ => maybe_endpoint.unwrap_or("http://localhost:4317"), //Devskim: ignore DS137138
156-
};
157-
158-
(protocol.to_string(), endpoint.to_string())
97+
maybe_protocol
15998
}
16099

161100
#[cfg(test)]
@@ -166,60 +105,38 @@ mod tests {
166105
use super::*;
167106

168107
#[rstest]
169-
#[case(None, None, "http/protobuf", "http://localhost:4318/v1/traces")] //Devskim: ignore DS137138
170-
#[case(
171-
Some("http/protobuf"),
172-
None,
173-
"http/protobuf",
174-
"http://localhost:4318/v1/traces"
175-
)] //Devskim: ignore DS137138
176-
#[case(Some("grpc"), None, "grpc", "http://localhost:4317")] //Devskim: ignore DS137138
177-
#[case(None, Some("http://localhost:4317"), "grpc", "http://localhost:4317")] //Devskim: ignore DS137138
108+
#[case(None, None, None)] //Devskim: ignore DS137138
109+
#[case(Some("http/protobuf"), None, Some("http/protobuf"))] //Devskim: ignore DS137138
110+
#[case(Some("grpc"), None, Some("grpc"))] //Devskim: ignore DS137138
111+
#[case(None, Some("http://localhost:4317"), Some("grpc"))] //Devskim: ignore DS137138
178112
#[cfg_attr(
179113
feature = "tls",
180-
case(
181-
None,
182-
Some("https://localhost:4317"),
183-
"grpc/tls",
184-
"https://localhost:4317"
185-
)
114+
case(None, Some("https://localhost:4317"), Some("grpc/tls"))
186115
)]
187116
#[cfg_attr(
188117
feature = "tls",
189-
case(
190-
Some("grpc/tls"),
191-
Some("https://localhost:4317"),
192-
"grpc/tls",
193-
"https://localhost:4317"
194-
)
118+
case(Some("grpc/tls"), Some("https://localhost:4317"), Some("grpc/tls"))
195119
)]
196120
#[case(
197121
Some("http/protobuf"),
198122
Some("http://localhost:4318/v1/traces"), //Devskim: ignore DS137138
199-
"http/protobuf",
200-
"http://localhost:4318/v1/traces" //Devskim: ignore DS137138
123+
Some("http/protobuf"),
201124
)]
202125
#[case(
203126
Some("http/protobuf"),
204127
Some("https://examples.com:4318/v1/traces"),
205-
"http/protobuf",
206-
"https://examples.com:4318/v1/traces"
128+
Some("http/protobuf")
207129
)]
208130
#[case(
209131
Some("http/protobuf"),
210132
Some("https://examples.com:4317"),
211-
"http/protobuf",
212-
"https://examples.com:4317"
133+
Some("http/protobuf")
213134
)]
214-
fn test_infer_protocol_and_endpoint(
135+
fn test_infer_protocol(
215136
#[case] traces_protocol: Option<&str>,
216137
#[case] traces_endpoint: Option<&str>,
217-
#[case] expected_protocol: &str,
218-
#[case] expected_endpoint: &str,
138+
#[case] expected_protocol: Option<&str>,
219139
) {
220-
assert!(
221-
infer_protocol_and_endpoint(traces_protocol, traces_endpoint)
222-
== (expected_protocol.to_string(), expected_endpoint.to_string())
223-
);
140+
assert!(infer_protocol(traces_protocol, traces_endpoint).as_deref() == expected_protocol);
224141
}
225142
}

init-tracing-opentelemetry/src/stdio.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,8 @@ where
2424
BatchSpanProcessor::builder(exporter, opentelemetry_sdk::runtime::Tokio).build();
2525
let mut provider_builder: opentelemetry_sdk::trace::Builder = TracerProvider::builder()
2626
.with_span_processor(processor)
27-
.with_config(
28-
sdktrace::Config::default()
29-
.with_resource(resource)
30-
.with_sampler(sdktrace::Sampler::AlwaysOn),
31-
);
27+
.with_resource(resource)
28+
.with_sampler(sdktrace::Sampler::AlwaysOn);
3229
provider_builder = transform(provider_builder);
3330
// tracer used in libraries/crates that optionally includes version and schema url
3431
let scope = InstrumentationScope::builder(env!("CARGO_PKG_NAME"))

0 commit comments

Comments
 (0)