The OpenTelemetry Logs Bridge API provides the foundation for connecting existing logging libraries to OpenTelemetry. This API is not intended for direct use by application developers—instead, it’s designed for logging library authors to build log appenders.
Application developers should use logging libraries like log or tracing along with the provided appenders, not the Bridge API directly.
The Logger trait provides methods to create and emit log records:
pub trait Logger { type LogRecord: LogRecord; /// Creates a new log record builder fn create_log_record(&self) -> Self::LogRecord; /// Emits a log record fn emit(&self, record: Self::LogRecord); /// Checks if a log event is enabled fn event_enabled(&self, level: Severity, target: &str, name: Option<&str>) -> bool;}
Key methods:
create_log_record() - Creates a new log record that can be populated with data
emit() - Sends the log record to the logging pipeline
event_enabled() - Allows early filtering to skip expensive logging operations
When emit() is called within an active trace context, the logger automatically attaches the current trace ID, span ID, and trace flags to the log record.
The LoggerProvider trait creates Logger instances:
pub trait LoggerProvider { type Logger: Logger; /// Returns a logger with the given instrumentation scope fn logger_with_scope(&self, scope: InstrumentationScope) -> Self::Logger; /// Returns a logger with the given name fn logger(&self, name: impl Into<Cow<'static, str>>) -> Self::Logger { let scope = InstrumentationScope::builder(name).build(); self.logger_with_scope(scope) }}
Usage example:
use opentelemetry::logs::LoggerProvider;use opentelemetry::InstrumentationScope;use opentelemetry_sdk::logs::SdkLoggerProvider;let provider = SdkLoggerProvider::builder().build();// Simple logger for applicationslet logger = provider.logger("my-app");// Logger with full instrumentation scope for librarieslet scope = InstrumentationScope::builder(env!("CARGO_PKG_NAME")) .with_version(env!("CARGO_PKG_VERSION")) .with_schema_url("https://opentelemetry.io/schemas/1.0.0") .build();let logger = provider.logger_with_scope(scope);
use std::collections::HashMap;use opentelemetry::{logs::AnyValue, Key};// Lists from iteratorslet list: AnyValue = vec![1, 2, 3] .into_iter() .collect();assert!(matches!(list, AnyValue::ListAny(_)));// Maps from iteratorslet mut map = HashMap::new();map.insert("key", "value");let map_value: AnyValue = map.into_iter().collect();assert!(matches!(map_value, AnyValue::Map(_)));
Performance consideration: The log and tracing crates only support basic types (i64, f64, strings, bool). Complex types like ListAny and Map are available for custom appenders but involve heap allocations.
Always check event_enabled() before expensive operations:
if !logger.event_enabled(severity, target, Some(name)) { return; // Skip expensive serialization}// Only do expensive work if the event is enabledlet mut record = logger.create_log_record();// ... populate record ...logger.emit(record);
This allows processors to filter logs early, avoiding unnecessary work for logs that would be dropped anyway.
For testing or when logging is disabled, use the noop provider:
use opentelemetry::logs::NoopLoggerProvider;let provider = NoopLoggerProvider::new();let logger = provider.logger("my-app");// All operations are no-opslet mut record = logger.create_log_record();logger.emit(record); // Does nothing