diff --git a/opentelemetry-appender-log/src/lib.rs b/opentelemetry-appender-log/src/lib.rs index 0ff3ecb357..785b616036 100644 --- a/opentelemetry-appender-log/src/lib.rs +++ b/opentelemetry-appender-log/src/lib.rs @@ -136,9 +136,11 @@ where { fn enabled(&self, _metadata: &Metadata) -> bool { #[cfg(feature = "spec_unstable_logs_enabled")] - return self - .logger - .event_enabled(severity_of_level(_metadata.level()), _metadata.target()); + return self.logger.event_enabled( + severity_of_level(_metadata.level()), + _metadata.target(), + None, + ); #[cfg(not(feature = "spec_unstable_logs_enabled"))] true } diff --git a/opentelemetry-appender-tracing/CHANGELOG.md b/opentelemetry-appender-tracing/CHANGELOG.md index 53f5f42093..dacc012cf7 100644 --- a/opentelemetry-appender-tracing/CHANGELOG.md +++ b/opentelemetry-appender-tracing/CHANGELOG.md @@ -38,6 +38,10 @@ Receivers (processors, exporters) are expected to use `LogRecord.target()` as scope name. This is already done in OTLP Exporters, so this change should be transparent to most users. +- Passes event name to the `event_enabled` method on the `Logger`. This allows + implementations (SDK, processor, exporters) to leverage this additional + information to determine if an event is enabled. + ## 0.28.1 Released 2025-Feb-12 diff --git a/opentelemetry-appender-tracing/benches/logs.rs b/opentelemetry-appender-tracing/benches/logs.rs index 0ec47c1863..35b8488bbc 100644 --- a/opentelemetry-appender-tracing/benches/logs.rs +++ b/opentelemetry-appender-tracing/benches/logs.rs @@ -52,7 +52,7 @@ impl LogProcessor for NoopProcessor { &self, _level: opentelemetry::logs::Severity, _target: &str, - _name: &str, + _name: Option<&str>, ) -> bool { self.enabled } diff --git a/opentelemetry-appender-tracing/src/layer.rs b/opentelemetry-appender-tracing/src/layer.rs index 02ebec710d..6a15bc9dba 100644 --- a/opentelemetry-appender-tracing/src/layer.rs +++ b/opentelemetry-appender-tracing/src/layer.rs @@ -155,10 +155,12 @@ where event: &tracing::Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>, ) { - let severity = severity_of_level(event.metadata().level()); - let target = event.metadata().target(); + let metadata = event.metadata(); + let severity = severity_of_level(metadata.level()); + let target = metadata.target(); + let name = metadata.name(); #[cfg(feature = "spec_unstable_logs_enabled")] - if !self.logger.event_enabled(severity, target) { + if !self.logger.event_enabled(severity, target, Some(name)) { // TODO: See if we need internal logs or track the count. return; } @@ -169,16 +171,13 @@ where #[cfg(feature = "experimental_metadata_attributes")] let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata()); - #[cfg(not(feature = "experimental_metadata_attributes"))] - let meta = event.metadata(); - let mut log_record = self.logger.create_log_record(); // TODO: Fix heap allocation log_record.set_target(target.to_string()); - log_record.set_event_name(meta.name()); + log_record.set_event_name(name); log_record.set_severity_number(severity); - log_record.set_severity_text(meta.level().as_str()); + log_record.set_severity_text(metadata.level().as_str()); let mut visitor = EventVisitor::new(&mut log_record); #[cfg(feature = "experimental_metadata_attributes")] visitor.visit_experimental_metadata(meta); @@ -226,9 +225,10 @@ mod tests { use opentelemetry::logs::Severity; use opentelemetry::trace::TracerProvider; use opentelemetry::trace::{TraceContextExt, TraceFlags, Tracer}; + use opentelemetry::InstrumentationScope; use opentelemetry::{logs::AnyValue, Key}; use opentelemetry_sdk::error::OTelSdkResult; - use opentelemetry_sdk::logs::InMemoryLogExporter; + use opentelemetry_sdk::logs::{InMemoryLogExporter, LogProcessor}; use opentelemetry_sdk::logs::{LogBatch, LogExporter}; use opentelemetry_sdk::logs::{SdkLogRecord, SdkLoggerProvider}; use opentelemetry_sdk::trace::{Sampler, SdkTracerProvider}; @@ -244,10 +244,7 @@ mod tests { } #[allow(impl_trait_overcaptures)] // can only be fixed with Rust 1.82+ - fn create_tracing_subscriber( - _exporter: InMemoryLogExporter, - logger_provider: &SdkLoggerProvider, - ) -> impl tracing::Subscriber { + fn create_tracing_subscriber(logger_provider: &SdkLoggerProvider) -> impl tracing::Subscriber { let level_filter = tracing_subscriber::filter::LevelFilter::WARN; // Capture WARN and ERROR levels let layer = layer::OpenTelemetryTracingBridge::new(logger_provider).with_filter(level_filter); // No filter based on target, only based on log level @@ -327,7 +324,7 @@ mod tests { .with_simple_exporter(exporter.clone()) .build(); - let subscriber = create_tracing_subscriber(exporter.clone(), &logger_provider); + let subscriber = create_tracing_subscriber(&logger_provider); // avoiding setting tracing subscriber as global as that does not // play well with unit tests. @@ -450,7 +447,7 @@ mod tests { .with_simple_exporter(exporter.clone()) .build(); - let subscriber = create_tracing_subscriber(exporter.clone(), &logger_provider); + let subscriber = create_tracing_subscriber(&logger_provider); // avoiding setting tracing subscriber as global as that does not // play well with unit tests. @@ -627,7 +624,7 @@ mod tests { .with_simple_exporter(exporter.clone()) .build(); - let subscriber = create_tracing_subscriber(exporter.clone(), &logger_provider); + let subscriber = create_tracing_subscriber(&logger_provider); // avoiding setting tracing subscriber as global as that does not // play well with unit tests. @@ -703,7 +700,7 @@ mod tests { .with_simple_exporter(exporter.clone()) .build(); - let subscriber = create_tracing_subscriber(exporter.clone(), &logger_provider); + let subscriber = create_tracing_subscriber(&logger_provider); // avoiding setting tracing subscriber as global as that does not // play well with unit tests. @@ -785,4 +782,70 @@ mod tests { assert!(!attributes_key.contains(&Key::new("log.target"))); } } + + #[derive(Debug)] + struct LogProcessorWithIsEnabled { + severity_level: Severity, + name: String, + target: String, + } + + impl LogProcessorWithIsEnabled { + fn new(severity_level: Severity, name: String, target: String) -> Self { + LogProcessorWithIsEnabled { + severity_level, + name, + target, + } + } + } + + impl LogProcessor for LogProcessorWithIsEnabled { + fn emit(&self, _record: &mut SdkLogRecord, _scope: &InstrumentationScope) { + // no-op + } + + #[cfg(feature = "spec_unstable_logs_enabled")] + fn event_enabled(&self, level: Severity, target: &str, name: Option<&str>) -> bool { + // assert that passed in arguments are same as the ones set in the test. + assert_eq!(self.severity_level, level); + assert_eq!(self.target, target); + assert_eq!( + self.name, + name.expect("name is expected from tracing appender") + ); + true + } + + fn force_flush(&self) -> OTelSdkResult { + Ok(()) + } + + fn shutdown(&self) -> OTelSdkResult { + Ok(()) + } + } + + #[cfg(feature = "spec_unstable_logs_enabled")] + #[test] + fn is_enabled() { + // Arrange + let logger_provider = SdkLoggerProvider::builder() + .with_log_processor(LogProcessorWithIsEnabled::new( + Severity::Error, + "my-event-name".to_string(), + "my-system".to_string(), + )) + .build(); + + let subscriber = create_tracing_subscriber(&logger_provider); + + // avoiding setting tracing subscriber as global as that does not + // play well with unit tests. + let _guard = tracing::subscriber::set_default(subscriber); + + // Name, Target and Severity are expected to be passed to the IsEnabled check + // The validation is done in the LogProcessorWithIsEnabled struct. + error!(name: "my-event-name", target: "my-system", event_id = 20, user_name = "otel", user_email = "otel@opentelemetry.io"); + } } diff --git a/opentelemetry-sdk/CHANGELOG.md b/opentelemetry-sdk/CHANGELOG.md index ed4cfd098f..93c3b92abb 100644 --- a/opentelemetry-sdk/CHANGELOG.md +++ b/opentelemetry-sdk/CHANGELOG.md @@ -38,10 +38,13 @@ - **Breaking** The SpanExporter::export() method no longer requires a mutable reference to self. Before: + ```rust async fn export(&mut self, batch: Vec) -> OTelSdkResult ``` + After: + ```rust async fn export(&self, batch: Vec) -> OTelSdkResult ``` @@ -52,6 +55,11 @@ when its `shutdown` is invoked. - Reduced some info level logs to debug +- **Breaking** for custom LogProcessor/Exporter authors: Changed `name` + parameter from `&str` to `Option<&str>` in `event_enabled` method on the + `LogProcessor` and `LogExporter` traits. `SdkLogger` no longer passes its + `scope` name but instead passes the incoming `name` when invoking + `event_enabled` on processors. ## 0.28.0 diff --git a/opentelemetry-sdk/src/logs/export.rs b/opentelemetry-sdk/src/logs/export.rs index 4074c6edd8..83322199f8 100644 --- a/opentelemetry-sdk/src/logs/export.rs +++ b/opentelemetry-sdk/src/logs/export.rs @@ -141,7 +141,7 @@ pub trait LogExporter: Send + Sync + Debug { } #[cfg(feature = "spec_unstable_logs_enabled")] /// Check if logs are enabled. - fn event_enabled(&self, _level: Severity, _target: &str, _name: &str) -> bool { + fn event_enabled(&self, _level: Severity, _target: &str, _name: Option<&str>) -> bool { // By default, all logs are enabled true } diff --git a/opentelemetry-sdk/src/logs/log_processor.rs b/opentelemetry-sdk/src/logs/log_processor.rs index 6054aa3415..cc634f063c 100644 --- a/opentelemetry-sdk/src/logs/log_processor.rs +++ b/opentelemetry-sdk/src/logs/log_processor.rs @@ -59,7 +59,7 @@ pub trait LogProcessor: Send + Sync + Debug { fn shutdown(&self) -> OTelSdkResult; #[cfg(feature = "spec_unstable_logs_enabled")] /// Check if logging is enabled - fn event_enabled(&self, _level: Severity, _target: &str, _name: &str) -> bool { + fn event_enabled(&self, _level: Severity, _target: &str, _name: Option<&str>) -> bool { // By default, all logs are enabled true } diff --git a/opentelemetry-sdk/src/logs/logger.rs b/opentelemetry-sdk/src/logs/logger.rs index 78b5bf4885..a3a4e09ac1 100644 --- a/opentelemetry-sdk/src/logs/logger.rs +++ b/opentelemetry-sdk/src/logs/logger.rs @@ -53,10 +53,10 @@ impl opentelemetry::logs::Logger for SdkLogger { } #[cfg(feature = "spec_unstable_logs_enabled")] - fn event_enabled(&self, level: Severity, target: &str) -> bool { + fn event_enabled(&self, level: Severity, target: &str, name: Option<&str>) -> bool { self.provider .log_processors() .iter() - .any(|processor| processor.event_enabled(level, target, self.scope.name().as_ref())) + .any(|processor| processor.event_enabled(level, target, name)) } } diff --git a/opentelemetry/CHANGELOG.md b/opentelemetry/CHANGELOG.md index 7192dd21f6..4247640d8b 100644 --- a/opentelemetry/CHANGELOG.md +++ b/opentelemetry/CHANGELOG.md @@ -11,6 +11,10 @@ - Updated `Baggage` constants to reflect latest standard (`MAX_KEY_VALUE_PAIRS` - 180 -> 64, `MAX_BYTES_FOR_ONE_PAIR` - removed) and increased insert performance see #[2284](https://github.com/open-telemetry/opentelemetry-rust/pull/2284). - *Breaking* Align `Baggage.remove()` signature with `.get()` to take the key as a reference +- Added additional `name: Option<&str>` parameter to the `event_enabled` method + on the `Logger` trait. This allows implementations (SDK, processor, exporters) + to leverage this additional information to determine if an event is enabled. + ## 0.28.0 Released 2025-Feb-10 diff --git a/opentelemetry/src/logs/logger.rs b/opentelemetry/src/logs/logger.rs index c1ef610f3d..38fda2e8fb 100644 --- a/opentelemetry/src/logs/logger.rs +++ b/opentelemetry/src/logs/logger.rs @@ -21,7 +21,7 @@ pub trait Logger { #[cfg(feature = "spec_unstable_logs_enabled")] /// Check if the given log level is enabled. - fn event_enabled(&self, level: Severity, target: &str) -> bool; + fn event_enabled(&self, level: Severity, target: &str, name: Option<&str>) -> bool; } /// Interfaces that can create [`Logger`] instances. diff --git a/opentelemetry/src/logs/noop.rs b/opentelemetry/src/logs/noop.rs index a9706fa5a4..10add3139b 100644 --- a/opentelemetry/src/logs/noop.rs +++ b/opentelemetry/src/logs/noop.rs @@ -79,7 +79,7 @@ impl Logger for NoopLogger { } fn emit(&self, _record: Self::LogRecord) {} #[cfg(feature = "spec_unstable_logs_enabled")] - fn event_enabled(&self, _level: super::Severity, _target: &str) -> bool { + fn event_enabled(&self, _level: super::Severity, _target: &str, _name: Option<&str>) -> bool { false } }