Skip to content

Commit 278f5c7

Browse files
authored
Add benchmark for opentelemetry-appender-tracing (#1649)
1 parent 5b5cb61 commit 278f5c7

File tree

2 files changed

+187
-0
lines changed

2 files changed

+187
-0
lines changed

opentelemetry-appender-tracing/Cargo.toml

+8
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,16 @@ log = { workspace = true }
2424
opentelemetry-stdout = { path = "../opentelemetry-stdout", features = ["logs"] }
2525
opentelemetry_sdk = { path = "../opentelemetry-sdk", features = ["logs", "testing"] }
2626
tracing-log = "0.2"
27+
async-trait = "0.1"
28+
criterion = "0.5.1"
2729

2830
[features]
2931
experimental_metadata_attributes = ["dep:tracing-log"]
3032
logs_level_enabled = ["opentelemetry/logs_level_enabled", "opentelemetry_sdk/logs_level_enabled"]
3133
default = ["logs_level_enabled"]
34+
35+
36+
[[bench]]
37+
name = "logs"
38+
harness = false
39+
required-features = ["logs_level_enabled"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/*
2+
The benchmark results:
3+
criterion = "0.5.1"
4+
OS: Ubuntu 22.04.2 LTS (5.10.102.1-microsoft-standard-WSL2)
5+
Hardware: AMD EPYC 7763 64-Core Processor - 2.44 GHz, 16vCPUs,
6+
RAM: 64.0 GB
7+
| Test | Average time|
8+
|-----------------------------|-------------|
9+
| log_no_subscriber | 313 ps |
10+
| noop_layer_disabled | 12 ns |
11+
| noop_layer_enabled | 25 ns |
12+
| ot_layer_disabled | 19 ns |
13+
| ot_layer_enabled | 561 ns |
14+
*/
15+
16+
use async_trait::async_trait;
17+
use criterion::{criterion_group, criterion_main, Criterion};
18+
use opentelemetry::logs::LogResult;
19+
use opentelemetry::KeyValue;
20+
use opentelemetry_appender_tracing::layer as tracing_layer;
21+
use opentelemetry_sdk::export::logs::{LogData, LogExporter};
22+
use opentelemetry_sdk::logs::{Config, LogProcessor, LoggerProvider};
23+
use opentelemetry_sdk::Resource;
24+
use tracing::error;
25+
use tracing_subscriber::prelude::*;
26+
use tracing_subscriber::Layer;
27+
use tracing_subscriber::Registry;
28+
29+
#[derive(Debug, Clone)]
30+
struct NoopExporter {
31+
enabled: bool,
32+
}
33+
34+
#[async_trait]
35+
impl LogExporter for NoopExporter {
36+
async fn export(&mut self, _: Vec<LogData>) -> LogResult<()> {
37+
LogResult::Ok(())
38+
}
39+
40+
fn event_enabled(&self, _: opentelemetry::logs::Severity, _: &str, _: &str) -> bool {
41+
self.enabled
42+
}
43+
}
44+
45+
#[derive(Debug)]
46+
struct NoopProcessor {
47+
exporter: Box<dyn LogExporter>,
48+
}
49+
50+
impl NoopProcessor {
51+
fn new(exporter: Box<dyn LogExporter>) -> Self {
52+
Self { exporter }
53+
}
54+
}
55+
56+
impl LogProcessor for NoopProcessor {
57+
fn emit(&self, _: LogData) {
58+
// no-op
59+
}
60+
61+
fn force_flush(&self) -> LogResult<()> {
62+
Ok(())
63+
}
64+
65+
fn shutdown(&mut self) -> LogResult<()> {
66+
Ok(())
67+
}
68+
69+
fn event_enabled(
70+
&self,
71+
level: opentelemetry::logs::Severity,
72+
target: &str,
73+
name: &str,
74+
) -> bool {
75+
self.exporter.event_enabled(level, target, name)
76+
}
77+
}
78+
79+
struct NoOpLogLayer {
80+
enabled: bool,
81+
}
82+
83+
impl<S> Layer<S> for NoOpLogLayer
84+
where
85+
S: tracing::Subscriber,
86+
{
87+
fn on_event(
88+
&self,
89+
event: &tracing::Event<'_>,
90+
_ctx: tracing_subscriber::layer::Context<'_, S>,
91+
) {
92+
let mut visitor = NoopEventVisitor;
93+
event.record(&mut visitor);
94+
}
95+
96+
fn event_enabled(
97+
&self,
98+
_event: &tracing::Event<'_>,
99+
_ctx: tracing_subscriber::layer::Context<'_, S>,
100+
) -> bool {
101+
self.enabled
102+
}
103+
}
104+
105+
struct NoopEventVisitor;
106+
107+
impl tracing::field::Visit for NoopEventVisitor {
108+
fn record_debug(&mut self, _field: &tracing::field::Field, _value: &dyn std::fmt::Debug) {}
109+
}
110+
111+
fn benchmark_no_subscriber(c: &mut Criterion) {
112+
c.bench_function("log_no_subscriber", |b| {
113+
b.iter(|| {
114+
error!(
115+
name = "CheckoutFailed",
116+
book_id = "12345",
117+
book_title = "Rust Programming Adventures",
118+
"Unable to process checkout."
119+
);
120+
});
121+
});
122+
}
123+
124+
fn benchmark_with_ot_layer(c: &mut Criterion, enabled: bool, bench_name: &str) {
125+
let exporter = NoopExporter { enabled };
126+
let processor = NoopProcessor::new(Box::new(exporter));
127+
let provider = LoggerProvider::builder()
128+
.with_config(
129+
Config::default().with_resource(Resource::new(vec![KeyValue::new(
130+
"service.name",
131+
"benchmark",
132+
)])),
133+
)
134+
.with_log_processor(processor)
135+
.build();
136+
let ot_layer = tracing_layer::OpenTelemetryTracingBridge::new(&provider);
137+
let subscriber = Registry::default().with(ot_layer);
138+
139+
tracing::subscriber::with_default(subscriber, || {
140+
c.bench_function(bench_name, |b| {
141+
b.iter(|| {
142+
error!(
143+
name = "CheckoutFailed",
144+
book_id = "12345",
145+
book_title = "Rust Programming Adventures",
146+
"Unable to process checkout."
147+
);
148+
});
149+
});
150+
});
151+
}
152+
153+
fn benchmark_with_noop_layer(c: &mut Criterion, enabled: bool, bench_name: &str) {
154+
let subscriber = Registry::default().with(NoOpLogLayer { enabled });
155+
156+
tracing::subscriber::with_default(subscriber, || {
157+
c.bench_function(bench_name, |b| {
158+
b.iter(|| {
159+
error!(
160+
name = "CheckoutFailed",
161+
book_id = "12345",
162+
book_title = "Rust Programming Adventures",
163+
"Unable to process checkout."
164+
);
165+
});
166+
});
167+
});
168+
}
169+
170+
fn criterion_benchmark(c: &mut Criterion) {
171+
benchmark_no_subscriber(c);
172+
benchmark_with_ot_layer(c, true, "ot_layer_enabled");
173+
benchmark_with_ot_layer(c, false, "ot_layer_disabled");
174+
benchmark_with_noop_layer(c, true, "noop_layer_enabled");
175+
benchmark_with_noop_layer(c, false, "noop_layer_disabled");
176+
}
177+
178+
criterion_group!(benches, criterion_benchmark);
179+
criterion_main!(benches);

0 commit comments

Comments
 (0)