1 use criterion::{criterion_group, criterion_main, Criterion};
2 use opentelemetry::{
3 sdk::trace::{Tracer, TracerProvider},
4 trace::{SpanBuilder, Tracer as _, TracerProvider as _},
5 Context,
6 };
7 use std::time::SystemTime;
8 use tracing::trace_span;
9 use tracing_subscriber::prelude::*;
10
many_children(c: &mut Criterion)11 fn many_children(c: &mut Criterion) {
12 let mut group = c.benchmark_group("otel_many_children");
13
14 group.bench_function("spec_baseline", |b| {
15 let provider = TracerProvider::default();
16 let tracer = provider.tracer("bench");
17 b.iter(|| {
18 fn dummy(tracer: &Tracer, cx: &Context) {
19 for _ in 0..99 {
20 tracer.start_with_context("child", cx);
21 }
22 }
23
24 tracer.in_span("parent", |cx| dummy(&tracer, &cx));
25 });
26 });
27
28 {
29 let _subscriber = tracing_subscriber::registry()
30 .with(RegistryAccessLayer)
31 .set_default();
32 group.bench_function("no_data_baseline", |b| b.iter(tracing_harness));
33 }
34
35 {
36 let _subscriber = tracing_subscriber::registry()
37 .with(OtelDataLayer)
38 .set_default();
39 group.bench_function("data_only_baseline", |b| b.iter(tracing_harness));
40 }
41
42 {
43 let provider = TracerProvider::default();
44 let tracer = provider.tracer("bench");
45 let otel_layer = tracing_opentelemetry::layer()
46 .with_tracer(tracer)
47 .with_tracked_inactivity(false);
48 let _subscriber = tracing_subscriber::registry()
49 .with(otel_layer)
50 .set_default();
51
52 group.bench_function("full", |b| b.iter(tracing_harness));
53 }
54 }
55
56 struct NoDataSpan;
57 struct RegistryAccessLayer;
58
59 impl<S> tracing_subscriber::Layer<S> for RegistryAccessLayer
60 where
61 S: tracing_core::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span>,
62 {
on_new_span( &self, _attrs: &tracing_core::span::Attributes<'_>, id: &tracing::span::Id, ctx: tracing_subscriber::layer::Context<'_, S>, )63 fn on_new_span(
64 &self,
65 _attrs: &tracing_core::span::Attributes<'_>,
66 id: &tracing::span::Id,
67 ctx: tracing_subscriber::layer::Context<'_, S>,
68 ) {
69 let span = ctx.span(id).expect("Span not found, this is a bug");
70 let mut extensions = span.extensions_mut();
71 extensions.insert(NoDataSpan);
72 }
73
on_close(&self, id: tracing::span::Id, ctx: tracing_subscriber::layer::Context<'_, S>)74 fn on_close(&self, id: tracing::span::Id, ctx: tracing_subscriber::layer::Context<'_, S>) {
75 let span = ctx.span(&id).expect("Span not found, this is a bug");
76 let mut extensions = span.extensions_mut();
77
78 extensions.remove::<NoDataSpan>();
79 }
80 }
81
82 struct OtelDataLayer;
83
84 impl<S> tracing_subscriber::Layer<S> for OtelDataLayer
85 where
86 S: tracing_core::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span>,
87 {
on_new_span( &self, attrs: &tracing_core::span::Attributes<'_>, id: &tracing::span::Id, ctx: tracing_subscriber::layer::Context<'_, S>, )88 fn on_new_span(
89 &self,
90 attrs: &tracing_core::span::Attributes<'_>,
91 id: &tracing::span::Id,
92 ctx: tracing_subscriber::layer::Context<'_, S>,
93 ) {
94 let span = ctx.span(id).expect("Span not found, this is a bug");
95 let mut extensions = span.extensions_mut();
96 extensions.insert(
97 SpanBuilder::from_name(attrs.metadata().name()).with_start_time(SystemTime::now()),
98 );
99 }
100
on_close(&self, id: tracing::span::Id, ctx: tracing_subscriber::layer::Context<'_, S>)101 fn on_close(&self, id: tracing::span::Id, ctx: tracing_subscriber::layer::Context<'_, S>) {
102 let span = ctx.span(&id).expect("Span not found, this is a bug");
103 let mut extensions = span.extensions_mut();
104
105 if let Some(builder) = extensions.remove::<SpanBuilder>() {
106 builder.with_end_time(SystemTime::now());
107 }
108 }
109 }
110
tracing_harness()111 fn tracing_harness() {
112 fn dummy() {
113 for _ in 0..99 {
114 let child = trace_span!("child");
115 let _enter = child.enter();
116 }
117 }
118
119 let parent = trace_span!("parent");
120 let _enter = parent.enter();
121
122 dummy();
123 }
124
125 criterion_group!(benches, many_children);
126 criterion_main!(benches);
127