From edb0d5857f63674392e3d0cad40a6b5b161c17d1 Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Wed, 26 Feb 2025 12:08:01 -0800 Subject: [PATCH] docs: Modify examples to show best practices - reuse tracer (#2709) --- .../tracing-http-propagator/src/server.rs | 30 ++++-- opentelemetry-sdk/Cargo.toml | 5 +- opentelemetry-sdk/benches/tracer_creation.rs | 100 ++++++++++++++++++ opentelemetry/src/context.rs | 2 +- opentelemetry/src/trace/span_context.rs | 4 +- 5 files changed, 126 insertions(+), 15 deletions(-) create mode 100644 opentelemetry-sdk/benches/tracer_creation.rs diff --git a/examples/tracing-http-propagator/src/server.rs b/examples/tracing-http-propagator/src/server.rs index bc38649196..e882de1586 100644 --- a/examples/tracing-http-propagator/src/server.rs +++ b/examples/tracing-http-propagator/src/server.rs @@ -2,7 +2,7 @@ use http_body_util::{combinators::BoxBody, BodyExt, Full}; use hyper::{body::Incoming, service::service_fn, Request, Response, StatusCode}; use hyper_util::rt::{TokioExecutor, TokioIo}; use opentelemetry::{ - global, + global::{self, BoxedTracer}, trace::{FutureExt, Span, SpanKind, TraceContextExt, Tracer}, Context, KeyValue, }; @@ -10,9 +10,14 @@ use opentelemetry_http::{Bytes, HeaderExtractor}; use opentelemetry_sdk::{propagation::TraceContextPropagator, trace::SdkTracerProvider}; use opentelemetry_semantic_conventions::trace; use opentelemetry_stdout::SpanExporter; -use std::{convert::Infallible, net::SocketAddr}; +use std::{convert::Infallible, net::SocketAddr, sync::OnceLock}; use tokio::net::TcpListener; +fn get_tracer() -> &'static BoxedTracer { + static TRACER: OnceLock = OnceLock::new(); + TRACER.get_or_init(|| global::tracer("example/server")) +} + // Utility function to extract the context from the incoming request headers fn extract_context_from_request(req: &Request) -> Context { global::get_text_map_propagator(|propagator| { @@ -24,11 +29,11 @@ fn extract_context_from_request(req: &Request) -> Context { async fn handle_health_check( _req: Request, ) -> Result>, Infallible> { - let tracer = global::tracer("example/server"); + let tracer = get_tracer(); let mut span = tracer .span_builder("health_check") .with_kind(SpanKind::Internal) - .start(&tracer); + .start(tracer); span.add_event("Health check accessed", vec![]); let res = Response::new( @@ -44,11 +49,11 @@ async fn handle_health_check( async fn handle_echo( req: Request, ) -> Result>, Infallible> { - let tracer = global::tracer("example/server"); + let tracer = get_tracer(); let mut span = tracer .span_builder("echo") .with_kind(SpanKind::Internal) - .start(&tracer); + .start(tracer); span.add_event("Echoing back the request", vec![]); let res = Response::new(req.into_body().boxed()); @@ -63,11 +68,11 @@ async fn router( let parent_cx = extract_context_from_request(&req); let response = { // Create a span parenting the remote client span. - let tracer = global::tracer("example/server"); + let tracer = get_tracer(); let mut span = tracer .span_builder("router") .with_kind(SpanKind::Server) - .start_with_context(&tracer, &parent_cx); + .start_with_context(tracer, &parent_cx); span.add_event("dispatching request", vec![]); @@ -88,7 +93,7 @@ async fn router( response } -fn init_tracer() { +fn init_tracer() -> SdkTracerProvider { global::set_text_map_propagator(TraceContextPropagator::new()); // Setup tracerprovider with stdout exporter @@ -97,14 +102,15 @@ fn init_tracer() { .with_simple_exporter(SpanExporter::default()) .build(); - global::set_tracer_provider(provider); + global::set_tracer_provider(provider.clone()); + provider } #[tokio::main] async fn main() { use hyper_util::server::conn::auto::Builder; - init_tracer(); + let provider = init_tracer(); let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); let listener = TcpListener::bind(addr).await.unwrap(); @@ -116,4 +122,6 @@ async fn main() { eprintln!("{err}"); } } + + provider.shutdown().expect("Shutdown provider failed"); } diff --git a/opentelemetry-sdk/Cargo.toml b/opentelemetry-sdk/Cargo.toml index 45819b89c0..ab7c13ba19 100644 --- a/opentelemetry-sdk/Cargo.toml +++ b/opentelemetry-sdk/Cargo.toml @@ -83,12 +83,15 @@ harness = false [[bench]] name = "trace" harness = false -required-features = ["testing"] [[bench]] name = "log_processor" harness = false +[[bench]] +name = "tracer_creation" +harness = false + [[bench]] name = "log_exporter" harness = false diff --git a/opentelemetry-sdk/benches/tracer_creation.rs b/opentelemetry-sdk/benches/tracer_creation.rs new file mode 100644 index 0000000000..f342ab1068 --- /dev/null +++ b/opentelemetry-sdk/benches/tracer_creation.rs @@ -0,0 +1,100 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use opentelemetry::{ + global::{self, BoxedTracer}, + InstrumentationScope, KeyValue, +}; +use opentelemetry_sdk::trace as sdktrace; +use std::sync::OnceLock; + +#[cfg(not(target_os = "windows"))] +use pprof::criterion::{Output, PProfProfiler}; + +/* +Adding results in comments for a quick reference. +Apple M4 Pro + Total Number of Cores: 14 (10 performance and 4 efficiency) + +Tracer_With_Name/new_each_time 20 ns +Tracer_With_Name/reuse_existing 383 ps +Tracer_With_Name_And_Scope_Attrs/new_each_time 63 ns +Tracer_With_Name_And_Scope_Attrs/reuse_existing 385 ps +*/ + +fn get_tracer() -> &'static BoxedTracer { + static TRACER: OnceLock = OnceLock::new(); + TRACER.get_or_init(|| global::tracer("tracer")) +} + +fn get_tracer_with_scope_attrs() -> &'static BoxedTracer { + static TRACER_WITH_ATTRS: OnceLock = OnceLock::new(); + TRACER_WITH_ATTRS.get_or_init(|| { + let scope = InstrumentationScope::builder("tracer") + .with_attributes([KeyValue::new("key", "value")]) + .build(); + global::tracer_with_scope(scope) + }) +} + +fn create_provider() -> sdktrace::SdkTracerProvider { + // Provider is empty, no exporters, no processors etc. + // as the goal is measurement of tracer creation time. + sdktrace::SdkTracerProvider::builder().build() +} + +fn criterion_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("Tracer_With_Name"); + group.bench_function("new_each_time", |b| { + let provider = create_provider(); + global::set_tracer_provider(provider); + b.iter(|| { + black_box(global::tracer("tracer")); + }); + }); + + group.bench_function("reuse_existing", |b| { + let provider = create_provider(); + global::set_tracer_provider(provider); + b.iter(|| { + black_box(get_tracer()); + }); + }); + + group.finish(); + + let mut group = c.benchmark_group("Tracer_With_Name_And_Scope_Attrs"); + group.bench_function("new_each_time", |b| { + let provider = create_provider(); + global::set_tracer_provider(provider); + b.iter(|| { + let scope = InstrumentationScope::builder("tracer") + .with_attributes([KeyValue::new("key", "value")]) + .build(); + black_box(global::tracer_with_scope(scope)); + }); + }); + + group.bench_function("reuse_existing", |b| { + let provider = create_provider(); + global::set_tracer_provider(provider); + b.iter(|| { + black_box(get_tracer_with_scope_attrs()); + }); + }); + group.finish(); +} + +#[cfg(not(target_os = "windows"))] +criterion_group! { + name = benches; + config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); + targets = criterion_benchmark +} + +#[cfg(target_os = "windows")] +criterion_group! { + name = benches; + config = Criterion::default(); + targets = criterion_benchmark +} + +criterion_main!(benches); diff --git a/opentelemetry/src/context.rs b/opentelemetry/src/context.rs index 4398e7b589..045efdafdb 100644 --- a/opentelemetry/src/context.rs +++ b/opentelemetry/src/context.rs @@ -339,7 +339,7 @@ impl fmt::Debug for Context { } } - dbg.field("entries", &entries).finish() + dbg.field("entries count", &entries).finish() } } diff --git a/opentelemetry/src/trace/span_context.rs b/opentelemetry/src/trace/span_context.rs index f6dcc1a961..1e20a4f2ef 100644 --- a/opentelemetry/src/trace/span_context.rs +++ b/opentelemetry/src/trace/span_context.rs @@ -400,7 +400,7 @@ mod tests { let cx = Context::current(); assert_eq!( format!("{:?}", cx), - "Context { span: \"None\", entries: 0 }" + "Context { span: \"None\", entries count: 0 }" ); let cx = Context::current().with_remote_span_context(SpanContext::NONE); assert_eq!( @@ -413,7 +413,7 @@ mod tests { is_remote: false, \ trace_state: TraceState(None) \ }, \ - entries: 1 \ + entries count: 1 \ }" ); }