feat: Allow event name to be provided to IsEnabled check in Logger (#2756)

This commit is contained in:
Cijo Thomas 2025-03-04 15:39:58 -08:00 committed by GitHub
parent c5a4b7f436
commit ff33638d1e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 108 additions and 27 deletions

View File

@ -136,9 +136,11 @@ where
{ {
fn enabled(&self, _metadata: &Metadata) -> bool { fn enabled(&self, _metadata: &Metadata) -> bool {
#[cfg(feature = "spec_unstable_logs_enabled")] #[cfg(feature = "spec_unstable_logs_enabled")]
return self return self.logger.event_enabled(
.logger severity_of_level(_metadata.level()),
.event_enabled(severity_of_level(_metadata.level()), _metadata.target()); _metadata.target(),
None,
);
#[cfg(not(feature = "spec_unstable_logs_enabled"))] #[cfg(not(feature = "spec_unstable_logs_enabled"))]
true true
} }

View File

@ -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 scope name. This is already done in OTLP Exporters, so this change should be
transparent to most users. 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 ## 0.28.1
Released 2025-Feb-12 Released 2025-Feb-12

View File

@ -52,7 +52,7 @@ impl LogProcessor for NoopProcessor {
&self, &self,
_level: opentelemetry::logs::Severity, _level: opentelemetry::logs::Severity,
_target: &str, _target: &str,
_name: &str, _name: Option<&str>,
) -> bool { ) -> bool {
self.enabled self.enabled
} }

View File

@ -155,10 +155,12 @@ where
event: &tracing::Event<'_>, event: &tracing::Event<'_>,
_ctx: tracing_subscriber::layer::Context<'_, S>, _ctx: tracing_subscriber::layer::Context<'_, S>,
) { ) {
let severity = severity_of_level(event.metadata().level()); let metadata = event.metadata();
let target = event.metadata().target(); let severity = severity_of_level(metadata.level());
let target = metadata.target();
let name = metadata.name();
#[cfg(feature = "spec_unstable_logs_enabled")] #[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. // TODO: See if we need internal logs or track the count.
return; return;
} }
@ -169,16 +171,13 @@ where
#[cfg(feature = "experimental_metadata_attributes")] #[cfg(feature = "experimental_metadata_attributes")]
let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata()); 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(); let mut log_record = self.logger.create_log_record();
// TODO: Fix heap allocation // TODO: Fix heap allocation
log_record.set_target(target.to_string()); 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_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); let mut visitor = EventVisitor::new(&mut log_record);
#[cfg(feature = "experimental_metadata_attributes")] #[cfg(feature = "experimental_metadata_attributes")]
visitor.visit_experimental_metadata(meta); visitor.visit_experimental_metadata(meta);
@ -226,9 +225,10 @@ mod tests {
use opentelemetry::logs::Severity; use opentelemetry::logs::Severity;
use opentelemetry::trace::TracerProvider; use opentelemetry::trace::TracerProvider;
use opentelemetry::trace::{TraceContextExt, TraceFlags, Tracer}; use opentelemetry::trace::{TraceContextExt, TraceFlags, Tracer};
use opentelemetry::InstrumentationScope;
use opentelemetry::{logs::AnyValue, Key}; use opentelemetry::{logs::AnyValue, Key};
use opentelemetry_sdk::error::OTelSdkResult; 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::{LogBatch, LogExporter};
use opentelemetry_sdk::logs::{SdkLogRecord, SdkLoggerProvider}; use opentelemetry_sdk::logs::{SdkLogRecord, SdkLoggerProvider};
use opentelemetry_sdk::trace::{Sampler, SdkTracerProvider}; use opentelemetry_sdk::trace::{Sampler, SdkTracerProvider};
@ -244,10 +244,7 @@ mod tests {
} }
#[allow(impl_trait_overcaptures)] // can only be fixed with Rust 1.82+ #[allow(impl_trait_overcaptures)] // can only be fixed with Rust 1.82+
fn create_tracing_subscriber( fn create_tracing_subscriber(logger_provider: &SdkLoggerProvider) -> impl tracing::Subscriber {
_exporter: InMemoryLogExporter,
logger_provider: &SdkLoggerProvider,
) -> impl tracing::Subscriber {
let level_filter = tracing_subscriber::filter::LevelFilter::WARN; // Capture WARN and ERROR levels let level_filter = tracing_subscriber::filter::LevelFilter::WARN; // Capture WARN and ERROR levels
let layer = let layer =
layer::OpenTelemetryTracingBridge::new(logger_provider).with_filter(level_filter); // No filter based on target, only based on log level 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()) .with_simple_exporter(exporter.clone())
.build(); .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 // avoiding setting tracing subscriber as global as that does not
// play well with unit tests. // play well with unit tests.
@ -450,7 +447,7 @@ mod tests {
.with_simple_exporter(exporter.clone()) .with_simple_exporter(exporter.clone())
.build(); .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 // avoiding setting tracing subscriber as global as that does not
// play well with unit tests. // play well with unit tests.
@ -627,7 +624,7 @@ mod tests {
.with_simple_exporter(exporter.clone()) .with_simple_exporter(exporter.clone())
.build(); .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 // avoiding setting tracing subscriber as global as that does not
// play well with unit tests. // play well with unit tests.
@ -703,7 +700,7 @@ mod tests {
.with_simple_exporter(exporter.clone()) .with_simple_exporter(exporter.clone())
.build(); .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 // avoiding setting tracing subscriber as global as that does not
// play well with unit tests. // play well with unit tests.
@ -785,4 +782,70 @@ mod tests {
assert!(!attributes_key.contains(&Key::new("log.target"))); 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");
}
} }

View File

@ -38,10 +38,13 @@
- **Breaking** The SpanExporter::export() method no longer requires a mutable reference to self. - **Breaking** The SpanExporter::export() method no longer requires a mutable reference to self.
Before: Before:
```rust ```rust
async fn export(&mut self, batch: Vec<SpanData>) -> OTelSdkResult async fn export(&mut self, batch: Vec<SpanData>) -> OTelSdkResult
``` ```
After: After:
```rust ```rust
async fn export(&self, batch: Vec<SpanData>) -> OTelSdkResult async fn export(&self, batch: Vec<SpanData>) -> OTelSdkResult
``` ```
@ -52,6 +55,11 @@
when its `shutdown` is invoked. when its `shutdown` is invoked.
- Reduced some info level logs to debug - 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 ## 0.28.0

View File

@ -141,7 +141,7 @@ pub trait LogExporter: Send + Sync + Debug {
} }
#[cfg(feature = "spec_unstable_logs_enabled")] #[cfg(feature = "spec_unstable_logs_enabled")]
/// Check if logs are 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 // By default, all logs are enabled
true true
} }

View File

@ -59,7 +59,7 @@ pub trait LogProcessor: Send + Sync + Debug {
fn shutdown(&self) -> OTelSdkResult; fn shutdown(&self) -> OTelSdkResult;
#[cfg(feature = "spec_unstable_logs_enabled")] #[cfg(feature = "spec_unstable_logs_enabled")]
/// Check if logging is 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 // By default, all logs are enabled
true true
} }

View File

@ -53,10 +53,10 @@ impl opentelemetry::logs::Logger for SdkLogger {
} }
#[cfg(feature = "spec_unstable_logs_enabled")] #[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 self.provider
.log_processors() .log_processors()
.iter() .iter()
.any(|processor| processor.event_enabled(level, target, self.scope.name().as_ref())) .any(|processor| processor.event_enabled(level, target, name))
} }
} }

View File

@ -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). - 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 - *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 ## 0.28.0
Released 2025-Feb-10 Released 2025-Feb-10

View File

@ -21,7 +21,7 @@ pub trait Logger {
#[cfg(feature = "spec_unstable_logs_enabled")] #[cfg(feature = "spec_unstable_logs_enabled")]
/// Check if the given log level is 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. /// Interfaces that can create [`Logger`] instances.

View File

@ -79,7 +79,7 @@ impl Logger for NoopLogger {
} }
fn emit(&self, _record: Self::LogRecord) {} fn emit(&self, _record: Self::LogRecord) {}
#[cfg(feature = "spec_unstable_logs_enabled")] #[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 false
} }
} }