Files
jcoffey-dev 1e7e8dfd48
ci / fork-checks (pull_request) Skipped
ci / build (pull_request) Skipped
github/ci (branch) GitHub Actions
ci / github (pull_request) Successful in 7m26s
Vendor upstream's opentelemetry-rust fork at the pinned commit
2026-10-27 22:55:35 -07:00

185 lines
5.9 KiB
Rust

/*
The benchmark results:
criterion = "0.5.1"
OS: Ubuntu 22.04.3 LTS (5.15.146.1-microsoft-standard-WSL2)
Hardware: AMD EPYC 7763 64-Core Processor - 2.44 GHz, 16vCPUs,
RAM: 64.0 GB
| Test | Average time|
|--------------------------------|-------------|
| LogExporterWithFuture | 111 ns |
| LogExporterWithoutFuture | 92 ns |
*/
use opentelemetry::time::now;
use opentelemetry_sdk::error::OTelSdkResult;
use std::sync::Mutex;
use criterion::{criterion_group, criterion_main, Criterion};
use opentelemetry::logs::{LogRecord as _, Logger, LoggerProvider, Severity};
use opentelemetry::InstrumentationScope;
use opentelemetry_sdk::logs::LogBatch;
use opentelemetry_sdk::logs::LogProcessor;
use opentelemetry_sdk::logs::SdkLogRecord;
use opentelemetry_sdk::logs::SdkLoggerProvider;
#[cfg(all(not(target_os = "windows"), feature = "bench_profiling"))]
use pprof::criterion::{Output, PProfProfiler};
use std::fmt::Debug;
// Run this benchmark with:
// cargo bench --bench log_exporter
pub trait LogExporterWithFuture: Send + Sync + Debug {
fn export(&mut self, batch: LogBatch<'_>) -> impl std::future::Future<Output = ()> + Send;
}
pub trait LogExporterWithoutFuture: Send + Sync + Debug {
fn export(&mut self, batch: LogBatch<'_>);
}
#[derive(Debug)]
struct NoOpExporterWithFuture {}
impl LogExporterWithFuture for NoOpExporterWithFuture {
async fn export(&mut self, _batch: LogBatch<'_>) {}
}
#[derive(Debug)]
struct NoOpExporterWithoutFuture {}
impl LogExporterWithoutFuture for NoOpExporterWithoutFuture {
fn export(&mut self, _batch: LogBatch<'_>) {}
}
#[derive(Debug)]
struct ExportingProcessorWithFuture {
exporter: Mutex<NoOpExporterWithFuture>,
}
impl ExportingProcessorWithFuture {
fn new(exporter: NoOpExporterWithFuture) -> Self {
ExportingProcessorWithFuture {
exporter: Mutex::new(exporter),
}
}
}
impl LogProcessor for ExportingProcessorWithFuture {
fn emit(&self, record: &mut SdkLogRecord, scope: &InstrumentationScope) {
let mut exporter = self.exporter.lock().expect("lock error");
let logs = [(record as &SdkLogRecord, scope)];
futures_executor::block_on(exporter.export(LogBatch::new(&logs)));
}
fn force_flush(&self) -> OTelSdkResult {
Ok(())
}
fn shutdown_with_timeout(&self, _timeout: std::time::Duration) -> OTelSdkResult {
Ok(())
}
}
#[derive(Debug)]
struct ExportingProcessorWithoutFuture {
exporter: Mutex<NoOpExporterWithoutFuture>,
}
impl ExportingProcessorWithoutFuture {
fn new(exporter: NoOpExporterWithoutFuture) -> Self {
ExportingProcessorWithoutFuture {
exporter: Mutex::new(exporter),
}
}
}
impl LogProcessor for ExportingProcessorWithoutFuture {
fn emit(&self, record: &mut SdkLogRecord, scope: &InstrumentationScope) {
let logs = [(record as &SdkLogRecord, scope)];
self.exporter
.lock()
.expect("lock error")
.export(LogBatch::new(&logs));
}
fn force_flush(&self) -> OTelSdkResult {
Ok(())
}
fn shutdown_with_timeout(&self, _timeout: std::time::Duration) -> OTelSdkResult {
Ok(())
}
}
fn criterion_benchmark(c: &mut Criterion) {
exporter_with_future(c);
exporter_without_future(c);
}
fn exporter_with_future(c: &mut Criterion) {
let provider = SdkLoggerProvider::builder()
.with_log_processor(ExportingProcessorWithFuture::new(NoOpExporterWithFuture {}))
.build();
let logger = provider.logger("benchmark");
c.bench_function("LogExporterWithFuture", |b| {
b.iter(|| {
let mut log_record = logger.create_log_record();
let now = now();
log_record.set_observed_timestamp(now);
log_record.set_target("my-target".to_string());
log_record.set_event_name("CheckoutFailed");
log_record.set_severity_number(Severity::Warn);
log_record.set_severity_text("WARN");
log_record.add_attribute("book_id", "12345");
log_record.add_attribute("book_title", "Rust Programming Adventures");
log_record.add_attribute("message", "Unable to process checkout.");
logger.emit(log_record);
});
});
}
fn exporter_without_future(c: &mut Criterion) {
let provider = SdkLoggerProvider::builder()
.with_log_processor(ExportingProcessorWithoutFuture::new(
NoOpExporterWithoutFuture {},
))
.build();
let logger = provider.logger("benchmark");
c.bench_function("LogExporterWithoutFuture", |b| {
b.iter(|| {
let mut log_record = logger.create_log_record();
let now = now();
log_record.set_observed_timestamp(now);
log_record.set_target("my-target".to_string());
log_record.set_event_name("CheckoutFailed");
log_record.set_severity_number(Severity::Warn);
log_record.set_severity_text("WARN");
log_record.add_attribute("book_id", "12345");
log_record.add_attribute("book_title", "Rust Programming Adventures");
log_record.add_attribute("message", "Unable to process checkout.");
logger.emit(log_record);
});
});
}
#[cfg(all(not(target_os = "windows"), feature = "bench_profiling"))]
criterion_group! {
name = benches;
config = Criterion::default()
.warm_up_time(std::time::Duration::from_secs(1))
.measurement_time(std::time::Duration::from_secs(2))
.with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
targets = criterion_benchmark
}
#[cfg(any(target_os = "windows", not(feature = "bench_profiling")))]
criterion_group! {
name = benches;
config = Criterion::default()
.warm_up_time(std::time::Duration::from_secs(1))
.measurement_time(std::time::Duration::from_secs(2));
targets = criterion_benchmark
}
criterion_main!(benches);