Skip to content

Commit 108161c

Browse files
cijothomasTommyCpp
andauthored
Add log export benchmark to measure the cost paid for async abstraction (#2027)
Co-authored-by: Zhongyang Wu <[email protected]>
1 parent 72ac56f commit 108161c

File tree

2 files changed

+181
-0
lines changed

2 files changed

+181
-0
lines changed

opentelemetry-sdk/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ required-features = ["testing"]
8585
name = "log_processor"
8686
harness = false
8787

88+
[[bench]]
89+
name = "log_exporter"
90+
harness = false
91+
8892
[[bench]]
8993
name = "batch_span_processor"
9094
harness = false
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/*
2+
The benchmark results:
3+
criterion = "0.5.1"
4+
OS: Ubuntu 22.04.3 LTS (5.15.146.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+
| LogExporterWithFuture | 280 ns |
10+
| LogExporterWithoutFuture | 255 ns |
11+
*/
12+
13+
use std::sync::Mutex;
14+
use std::time::SystemTime;
15+
16+
use async_trait::async_trait;
17+
use criterion::{criterion_group, criterion_main, Criterion};
18+
19+
use opentelemetry::logs::{LogRecord as _, LogResult, Logger as _, LoggerProvider as _, Severity};
20+
21+
use opentelemetry_sdk::export::logs::LogData;
22+
use opentelemetry_sdk::logs::LogProcessor;
23+
use opentelemetry_sdk::logs::LoggerProvider;
24+
use pprof::criterion::{Output, PProfProfiler};
25+
use std::fmt::Debug;
26+
27+
// Run this benchmark with:
28+
// cargo bench --bench log_exporter
29+
#[async_trait]
30+
pub trait LogExporterWithFuture: Send + Sync + Debug {
31+
async fn export(&mut self, batch: Vec<LogData>);
32+
}
33+
34+
pub trait LogExporterWithoutFuture: Send + Sync + Debug {
35+
fn export(&mut self, batch: Vec<LogData>);
36+
}
37+
38+
#[derive(Debug)]
39+
struct NoOpExporterWithFuture {}
40+
41+
#[async_trait]
42+
impl LogExporterWithFuture for NoOpExporterWithFuture {
43+
async fn export(&mut self, _batch: Vec<LogData>) {}
44+
}
45+
46+
#[derive(Debug)]
47+
struct NoOpExporterWithoutFuture {}
48+
impl LogExporterWithoutFuture for NoOpExporterWithoutFuture {
49+
fn export(&mut self, _batch: Vec<LogData>) {}
50+
}
51+
52+
#[derive(Debug)]
53+
struct ExportingProcessorWithFuture {
54+
exporter: Mutex<NoOpExporterWithFuture>,
55+
}
56+
57+
impl ExportingProcessorWithFuture {
58+
fn new(exporter: NoOpExporterWithFuture) -> Self {
59+
ExportingProcessorWithFuture {
60+
exporter: Mutex::new(exporter),
61+
}
62+
}
63+
}
64+
65+
impl LogProcessor for ExportingProcessorWithFuture {
66+
fn emit(&self, data: &mut LogData) {
67+
let mut exporter = self.exporter.lock().expect("lock error");
68+
futures_executor::block_on(exporter.export(vec![data.clone()]));
69+
}
70+
71+
fn force_flush(&self) -> LogResult<()> {
72+
Ok(())
73+
}
74+
75+
fn shutdown(&self) -> LogResult<()> {
76+
Ok(())
77+
}
78+
}
79+
80+
#[derive(Debug)]
81+
struct ExportingProcessorWithoutFuture {
82+
exporter: Mutex<NoOpExporterWithoutFuture>,
83+
}
84+
85+
impl ExportingProcessorWithoutFuture {
86+
fn new(exporter: NoOpExporterWithoutFuture) -> Self {
87+
ExportingProcessorWithoutFuture {
88+
exporter: Mutex::new(exporter),
89+
}
90+
}
91+
}
92+
93+
impl LogProcessor for ExportingProcessorWithoutFuture {
94+
fn emit(&self, data: &mut LogData) {
95+
self.exporter
96+
.lock()
97+
.expect("lock error")
98+
.export(vec![data.clone()]);
99+
}
100+
101+
fn force_flush(&self) -> LogResult<()> {
102+
Ok(())
103+
}
104+
105+
fn shutdown(&self) -> LogResult<()> {
106+
Ok(())
107+
}
108+
}
109+
110+
fn criterion_benchmark(c: &mut Criterion) {
111+
exporter_with_future(c);
112+
exporter_without_future(c);
113+
}
114+
115+
fn exporter_with_future(c: &mut Criterion) {
116+
let provider = LoggerProvider::builder()
117+
.with_log_processor(ExportingProcessorWithFuture::new(NoOpExporterWithFuture {}))
118+
.build();
119+
let logger = provider.logger("benchmark");
120+
121+
c.bench_function("LogExporterWithFuture", |b| {
122+
b.iter(|| {
123+
let mut log_record = logger.create_log_record();
124+
let now = SystemTime::now();
125+
log_record.set_observed_timestamp(now);
126+
log_record.set_target("my-target".to_string());
127+
log_record.set_event_name("CheckoutFailed");
128+
log_record.set_severity_number(Severity::Warn);
129+
log_record.set_severity_text("WARN");
130+
log_record.add_attribute("book_id", "12345");
131+
log_record.add_attribute("book_title", "Rust Programming Adventures");
132+
log_record.add_attribute("message", "Unable to process checkout.");
133+
134+
logger.emit(log_record);
135+
});
136+
});
137+
}
138+
139+
fn exporter_without_future(c: &mut Criterion) {
140+
let provider = LoggerProvider::builder()
141+
.with_log_processor(ExportingProcessorWithoutFuture::new(
142+
NoOpExporterWithoutFuture {},
143+
))
144+
.build();
145+
let logger = provider.logger("benchmark");
146+
147+
c.bench_function("LogExporterWithoutFuture", |b| {
148+
b.iter(|| {
149+
let mut log_record = logger.create_log_record();
150+
let now = SystemTime::now();
151+
log_record.set_observed_timestamp(now);
152+
log_record.set_target("my-target".to_string());
153+
log_record.set_event_name("CheckoutFailed");
154+
log_record.set_severity_number(Severity::Warn);
155+
log_record.set_severity_text("WARN");
156+
log_record.add_attribute("book_id", "12345");
157+
log_record.add_attribute("book_title", "Rust Programming Adventures");
158+
log_record.add_attribute("message", "Unable to process checkout.");
159+
160+
logger.emit(log_record);
161+
});
162+
});
163+
}
164+
165+
#[cfg(not(target_os = "windows"))]
166+
criterion_group! {
167+
name = benches;
168+
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
169+
targets = criterion_benchmark
170+
}
171+
#[cfg(target_os = "windows")]
172+
criterion_group! {
173+
name = benches;
174+
config = Criterion::default();
175+
targets = criterion_benchmark
176+
}
177+
criterion_main!(benches);

0 commit comments

Comments
 (0)