185 lines
5.9 KiB
Rust
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);
|