Skip to content

Commit edb0d58

Browse files
authored
docs: Modify examples to show best practices - reuse tracer (#2709)
1 parent 11ed8e0 commit edb0d58

File tree

5 files changed

+126
-15
lines changed

5 files changed

+126
-15
lines changed

examples/tracing-http-propagator/src/server.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,22 @@ use http_body_util::{combinators::BoxBody, BodyExt, Full};
22
use hyper::{body::Incoming, service::service_fn, Request, Response, StatusCode};
33
use hyper_util::rt::{TokioExecutor, TokioIo};
44
use opentelemetry::{
5-
global,
5+
global::{self, BoxedTracer},
66
trace::{FutureExt, Span, SpanKind, TraceContextExt, Tracer},
77
Context, KeyValue,
88
};
99
use opentelemetry_http::{Bytes, HeaderExtractor};
1010
use opentelemetry_sdk::{propagation::TraceContextPropagator, trace::SdkTracerProvider};
1111
use opentelemetry_semantic_conventions::trace;
1212
use opentelemetry_stdout::SpanExporter;
13-
use std::{convert::Infallible, net::SocketAddr};
13+
use std::{convert::Infallible, net::SocketAddr, sync::OnceLock};
1414
use tokio::net::TcpListener;
1515

16+
fn get_tracer() -> &'static BoxedTracer {
17+
static TRACER: OnceLock<BoxedTracer> = OnceLock::new();
18+
TRACER.get_or_init(|| global::tracer("example/server"))
19+
}
20+
1621
// Utility function to extract the context from the incoming request headers
1722
fn extract_context_from_request(req: &Request<Incoming>) -> Context {
1823
global::get_text_map_propagator(|propagator| {
@@ -24,11 +29,11 @@ fn extract_context_from_request(req: &Request<Incoming>) -> Context {
2429
async fn handle_health_check(
2530
_req: Request<Incoming>,
2631
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, Infallible> {
27-
let tracer = global::tracer("example/server");
32+
let tracer = get_tracer();
2833
let mut span = tracer
2934
.span_builder("health_check")
3035
.with_kind(SpanKind::Internal)
31-
.start(&tracer);
36+
.start(tracer);
3237
span.add_event("Health check accessed", vec![]);
3338

3439
let res = Response::new(
@@ -44,11 +49,11 @@ async fn handle_health_check(
4449
async fn handle_echo(
4550
req: Request<Incoming>,
4651
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, Infallible> {
47-
let tracer = global::tracer("example/server");
52+
let tracer = get_tracer();
4853
let mut span = tracer
4954
.span_builder("echo")
5055
.with_kind(SpanKind::Internal)
51-
.start(&tracer);
56+
.start(tracer);
5257
span.add_event("Echoing back the request", vec![]);
5358

5459
let res = Response::new(req.into_body().boxed());
@@ -63,11 +68,11 @@ async fn router(
6368
let parent_cx = extract_context_from_request(&req);
6469
let response = {
6570
// Create a span parenting the remote client span.
66-
let tracer = global::tracer("example/server");
71+
let tracer = get_tracer();
6772
let mut span = tracer
6873
.span_builder("router")
6974
.with_kind(SpanKind::Server)
70-
.start_with_context(&tracer, &parent_cx);
75+
.start_with_context(tracer, &parent_cx);
7176

7277
span.add_event("dispatching request", vec![]);
7378

@@ -88,7 +93,7 @@ async fn router(
8893
response
8994
}
9095

91-
fn init_tracer() {
96+
fn init_tracer() -> SdkTracerProvider {
9297
global::set_text_map_propagator(TraceContextPropagator::new());
9398

9499
// Setup tracerprovider with stdout exporter
@@ -97,14 +102,15 @@ fn init_tracer() {
97102
.with_simple_exporter(SpanExporter::default())
98103
.build();
99104

100-
global::set_tracer_provider(provider);
105+
global::set_tracer_provider(provider.clone());
106+
provider
101107
}
102108

103109
#[tokio::main]
104110
async fn main() {
105111
use hyper_util::server::conn::auto::Builder;
106112

107-
init_tracer();
113+
let provider = init_tracer();
108114
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
109115
let listener = TcpListener::bind(addr).await.unwrap();
110116

@@ -116,4 +122,6 @@ async fn main() {
116122
eprintln!("{err}");
117123
}
118124
}
125+
126+
provider.shutdown().expect("Shutdown provider failed");
119127
}

opentelemetry-sdk/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,15 @@ harness = false
8383
[[bench]]
8484
name = "trace"
8585
harness = false
86-
required-features = ["testing"]
8786

8887
[[bench]]
8988
name = "log_processor"
9089
harness = false
9190

91+
[[bench]]
92+
name = "tracer_creation"
93+
harness = false
94+
9295
[[bench]]
9396
name = "log_exporter"
9497
harness = false
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
2+
use opentelemetry::{
3+
global::{self, BoxedTracer},
4+
InstrumentationScope, KeyValue,
5+
};
6+
use opentelemetry_sdk::trace as sdktrace;
7+
use std::sync::OnceLock;
8+
9+
#[cfg(not(target_os = "windows"))]
10+
use pprof::criterion::{Output, PProfProfiler};
11+
12+
/*
13+
Adding results in comments for a quick reference.
14+
Apple M4 Pro
15+
Total Number of Cores: 14 (10 performance and 4 efficiency)
16+
17+
Tracer_With_Name/new_each_time 20 ns
18+
Tracer_With_Name/reuse_existing 383 ps
19+
Tracer_With_Name_And_Scope_Attrs/new_each_time 63 ns
20+
Tracer_With_Name_And_Scope_Attrs/reuse_existing 385 ps
21+
*/
22+
23+
fn get_tracer() -> &'static BoxedTracer {
24+
static TRACER: OnceLock<BoxedTracer> = OnceLock::new();
25+
TRACER.get_or_init(|| global::tracer("tracer"))
26+
}
27+
28+
fn get_tracer_with_scope_attrs() -> &'static BoxedTracer {
29+
static TRACER_WITH_ATTRS: OnceLock<BoxedTracer> = OnceLock::new();
30+
TRACER_WITH_ATTRS.get_or_init(|| {
31+
let scope = InstrumentationScope::builder("tracer")
32+
.with_attributes([KeyValue::new("key", "value")])
33+
.build();
34+
global::tracer_with_scope(scope)
35+
})
36+
}
37+
38+
fn create_provider() -> sdktrace::SdkTracerProvider {
39+
// Provider is empty, no exporters, no processors etc.
40+
// as the goal is measurement of tracer creation time.
41+
sdktrace::SdkTracerProvider::builder().build()
42+
}
43+
44+
fn criterion_benchmark(c: &mut Criterion) {
45+
let mut group = c.benchmark_group("Tracer_With_Name");
46+
group.bench_function("new_each_time", |b| {
47+
let provider = create_provider();
48+
global::set_tracer_provider(provider);
49+
b.iter(|| {
50+
black_box(global::tracer("tracer"));
51+
});
52+
});
53+
54+
group.bench_function("reuse_existing", |b| {
55+
let provider = create_provider();
56+
global::set_tracer_provider(provider);
57+
b.iter(|| {
58+
black_box(get_tracer());
59+
});
60+
});
61+
62+
group.finish();
63+
64+
let mut group = c.benchmark_group("Tracer_With_Name_And_Scope_Attrs");
65+
group.bench_function("new_each_time", |b| {
66+
let provider = create_provider();
67+
global::set_tracer_provider(provider);
68+
b.iter(|| {
69+
let scope = InstrumentationScope::builder("tracer")
70+
.with_attributes([KeyValue::new("key", "value")])
71+
.build();
72+
black_box(global::tracer_with_scope(scope));
73+
});
74+
});
75+
76+
group.bench_function("reuse_existing", |b| {
77+
let provider = create_provider();
78+
global::set_tracer_provider(provider);
79+
b.iter(|| {
80+
black_box(get_tracer_with_scope_attrs());
81+
});
82+
});
83+
group.finish();
84+
}
85+
86+
#[cfg(not(target_os = "windows"))]
87+
criterion_group! {
88+
name = benches;
89+
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
90+
targets = criterion_benchmark
91+
}
92+
93+
#[cfg(target_os = "windows")]
94+
criterion_group! {
95+
name = benches;
96+
config = Criterion::default();
97+
targets = criterion_benchmark
98+
}
99+
100+
criterion_main!(benches);

opentelemetry/src/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ impl fmt::Debug for Context {
339339
}
340340
}
341341

342-
dbg.field("entries", &entries).finish()
342+
dbg.field("entries count", &entries).finish()
343343
}
344344
}
345345

opentelemetry/src/trace/span_context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ mod tests {
400400
let cx = Context::current();
401401
assert_eq!(
402402
format!("{:?}", cx),
403-
"Context { span: \"None\", entries: 0 }"
403+
"Context { span: \"None\", entries count: 0 }"
404404
);
405405
let cx = Context::current().with_remote_span_context(SpanContext::NONE);
406406
assert_eq!(
@@ -413,7 +413,7 @@ mod tests {
413413
is_remote: false, \
414414
trace_state: TraceState(None) \
415415
}, \
416-
entries: 1 \
416+
entries count: 1 \
417417
}"
418418
);
419419
}

0 commit comments

Comments
 (0)