From dfb3a39abe68b156aa12a278b7eb29fb30d10e4d Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Tue, 30 Sep 2025 15:45:02 +0200 Subject: [PATCH 01/11] feat(log): support combined `LogFilter`s and `RecordMapping`s --- CHANGELOG.md | 9 ++++ Cargo.lock | 1 + sentry-log/Cargo.toml | 1 + sentry-log/src/lib.rs | 17 +++++++ sentry-log/src/logger.rs | 107 +++++++++++++++++++++++++++------------ sentry/tests/test_log.rs | 80 +++++++++++++++++++++++++++++ 6 files changed, 184 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b6cd5e90..21d1db4d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## Unreleased + +### Breaking changes + +- feat(log): support combined `LogFilter`s and `RecordMapping`s by @lcian + - `sentry::integrations::log::LogFilter` has been changed to a `bitflags` struct. + - It's now possible to map a `log` record to multiple items in Sentry by combining multiple log filters in the filter, e.g. `log::Level::ERROR => LogFilter::Event | LogFilter::Log`. + - It's also possible to use `sentry::integrations::log::RecordMapping::Combined` to map a `log` record to multiple items in Sentry. + ## 0.43.0 ### Breaking changes diff --git a/Cargo.lock b/Cargo.lock index 6a7469908..347312525 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3264,6 +3264,7 @@ dependencies = [ name = "sentry-log" version = "0.43.0" dependencies = [ + "bitflags 2.9.1", "log", "pretty_env_logger", "sentry", diff --git a/sentry-log/Cargo.toml b/sentry-log/Cargo.toml index 4559551d0..3c1aaf92b 100644 --- a/sentry-log/Cargo.toml +++ b/sentry-log/Cargo.toml @@ -19,6 +19,7 @@ logs = ["sentry-core/logs"] [dependencies] sentry-core = { version = "0.43.0", path = "../sentry-core" } log = { version = "0.4.8", features = ["std", "kv"] } +bitflags = "2.0.0" [dev-dependencies] sentry = { path = "../sentry", default-features = false, features = ["test"] } diff --git a/sentry-log/src/lib.rs b/sentry-log/src/lib.rs index 56d986539..836fcfc6b 100644 --- a/sentry-log/src/lib.rs +++ b/sentry-log/src/lib.rs @@ -46,6 +46,23 @@ //! _ => LogFilter::Ignore, //! }); //! ``` +//! +//! # Sending multiple items to Sentry +//! +//! To map a log record to multiple items in Sentry, you can combine multiple log filters +//! using the bitwise or operator: +//! +//! ``` +//! use sentry_log::LogFilter; +//! +//! let logger = sentry_log::SentryLogger::new().filter(|md| match md.level() { +//! log::Level::Error => LogFilter::Event | LogFilter::Log, +//! log::Level::Warn => LogFilter::Breadcrumb | LogFilter::Log, +//! _ => LogFilter::Ignore, +//! }); +//! ``` +//! +//! If you're using a custom record mapper instead of a filter, use `RecordMapping::Combined`. #![doc(html_favicon_url = "https://sentry-brand.storage.googleapis.com/favicon.ico")] #![doc(html_logo_url = "https://sentry-brand.storage.googleapis.com/sentry-glyph-black.png")] diff --git a/sentry-log/src/logger.rs b/sentry-log/src/logger.rs index 7308afa95..804632e09 100644 --- a/sentry-log/src/logger.rs +++ b/sentry-log/src/logger.rs @@ -1,24 +1,27 @@ use log::Record; use sentry_core::protocol::{Breadcrumb, Event}; +use bitflags::bitflags; + #[cfg(feature = "logs")] use crate::converters::log_from_record; use crate::converters::{breadcrumb_from_record, event_from_record, exception_from_record}; -/// The action that Sentry should perform for a [`log::Metadata`]. -#[derive(Debug)] -pub enum LogFilter { - /// Ignore the [`Record`]. - Ignore, - /// Create a [`Breadcrumb`] from this [`Record`]. - Breadcrumb, - /// Create a message [`Event`] from this [`Record`]. - Event, - /// Create an exception [`Event`] from this [`Record`]. - Exception, - /// Create a [`sentry_core::protocol::Log`] from this [`Record`]. - #[cfg(feature = "logs")] - Log, +bitflags! { + /// The action that Sentry should perform for a [`log::Metadata`]. + #[derive(Debug, Clone, Copy)] + pub struct LogFilter: u32 { + /// Ignore the [`Record`]. + const Ignore = 0b0000; + /// Create a [`Breadcrumb`] from this [`Record`]. + const Breadcrumb = 0b0001; + /// Create a message [`Event`] from this [`Record`]. + const Event = 0b0010; + /// Create an exception [`Event`] from this [`Record`]. + const Exception = 0b0100; + /// Create a [`sentry_core::protocol::Log`] from this [`Record`]. + const Log = 0b1000; + } } /// The type of Data Sentry should ingest for a [`log::Record`]. @@ -34,6 +37,28 @@ pub enum RecordMapping { /// Captures the [`sentry_core::protocol::Log`] to Sentry. #[cfg(feature = "logs")] Log(sentry_core::protocol::Log), + /// Captures multiple items to Sentry. + /// Nesting multiple `RecordMapping::Combined` inside each other will cause the inner mappings to be ignored. + Combined(CombinedRecordMapping), +} + +/// A list of record mappings. +#[derive(Debug)] +pub struct CombinedRecordMapping(Vec); + +impl From for CombinedRecordMapping { + fn from(value: RecordMapping) -> Self { + match value { + RecordMapping::Combined(combined) => combined, + _ => CombinedRecordMapping(vec![value]), + } + } +} + +impl From> for CombinedRecordMapping { + fn from(value: Vec) -> Self { + Self(value) + } } /// The default log filter. @@ -132,30 +157,50 @@ impl SentryLogger { impl log::Log for SentryLogger { fn enabled(&self, metadata: &log::Metadata<'_>) -> bool { - self.dest.enabled(metadata) || !matches!((self.filter)(metadata), LogFilter::Ignore) + self.dest.enabled(metadata) || !((self.filter)(metadata).is_empty()) } fn log(&self, record: &log::Record<'_>) { - let item: RecordMapping = match &self.mapper { + let items = match &self.mapper { Some(mapper) => mapper(record), - None => match (self.filter)(record.metadata()) { - LogFilter::Ignore => RecordMapping::Ignore, - LogFilter::Breadcrumb => RecordMapping::Breadcrumb(breadcrumb_from_record(record)), - LogFilter::Event => RecordMapping::Event(event_from_record(record)), - LogFilter::Exception => RecordMapping::Event(exception_from_record(record)), + None => { + let filter = (self.filter)(record.metadata()); + let mut items = vec![]; + if filter.contains(LogFilter::Breadcrumb) { + items.push(RecordMapping::Breadcrumb(breadcrumb_from_record(record))); + } + if filter.contains(LogFilter::Event) { + items.push(RecordMapping::Event(event_from_record(record))); + } + if filter.contains(LogFilter::Exception) { + items.push(RecordMapping::Event(exception_from_record(record))); + } #[cfg(feature = "logs")] - LogFilter::Log => RecordMapping::Log(log_from_record(record)), - }, + if filter.contains(LogFilter::Log) { + items.push(RecordMapping::Log(log_from_record(record))); + } + RecordMapping::Combined(CombinedRecordMapping(items)) + } }; - - match item { - RecordMapping::Ignore => {} - RecordMapping::Breadcrumb(b) => sentry_core::add_breadcrumb(b), - RecordMapping::Event(e) => { - sentry_core::capture_event(e); + let items = CombinedRecordMapping::from(items); + + for item in items.0 { + match item { + RecordMapping::Ignore => {} + RecordMapping::Breadcrumb(breadcrumb) => sentry_core::add_breadcrumb(breadcrumb), + RecordMapping::Event(event) => { + sentry_core::capture_event(event); + } + #[cfg(feature = "logs")] + RecordMapping::Log(log) => { + sentry_core::Hub::with_active(|hub| hub.capture_log(log)) + } + RecordMapping::Combined(_) => { + sentry_core::sentry_debug!( + "[SentryLogger] found nested CombinedEventMapping, ignoring" + ) + } } - #[cfg(feature = "logs")] - RecordMapping::Log(log) => sentry_core::Hub::with_active(|hub| hub.capture_log(log)), } self.dest.log(record) diff --git a/sentry/tests/test_log.rs b/sentry/tests/test_log.rs index c460cf4ba..e1750e7b6 100644 --- a/sentry/tests/test_log.rs +++ b/sentry/tests/test_log.rs @@ -26,6 +26,86 @@ fn test_log() { assert_eq!(event.breadcrumbs[0].message, Some("Hello World!".into())); } +#[test] +fn test_combined_log_filters() { + let logger = sentry_log::SentryLogger::new().filter(|md| match md.level() { + log::Level::Error => sentry_log::LogFilter::Breadcrumb | sentry_log::LogFilter::Event, + log::Level::Warn => sentry_log::LogFilter::Event, + _ => sentry_log::LogFilter::Ignore, + }); + + // Only set logger if not already set to avoid conflicts with other tests + if log::set_boxed_logger(Box::new(logger)).is_ok() { + log::set_max_level(log::LevelFilter::Trace); + } + + let events = sentry::test::with_captured_events(|| { + log::error!("Both a breadcrumb and an event"); + log::warn!("An event"); + }); + + assert_eq!(events.len(), 2); + + assert_eq!( + events[0].message, + Some("Both a breadcrumb and an event".to_owned()) + ); + + assert_eq!(events[1].message, Some("An event".to_owned())); + assert_eq!(events[1].breadcrumbs.len(), 1); + assert_eq!( + events[1].breadcrumbs[0].message, + Some("Both a breadcrumb and an event".into()) + ); +} + +#[test] +fn test_combined_record_mapper() { + let logger = sentry_log::SentryLogger::new().mapper(|record| match record.metadata().level() { + log::Level::Error => { + let breadcrumb = sentry_log::breadcrumb_from_record(record); + let sentry_event = sentry_log::event_from_record(record); + + sentry_log::RecordMapping::Combined( + vec![ + sentry_log::RecordMapping::Breadcrumb(breadcrumb), + sentry_log::RecordMapping::Event(sentry_event), + ] + .into(), + ) + } + log::Level::Warn => { + let sentry_event = sentry_log::event_from_record(record); + sentry_log::RecordMapping::Event(sentry_event) + } + _ => sentry_log::RecordMapping::Ignore, + }); + + // Only set logger if not already set to avoid conflicts with other tests + if log::set_boxed_logger(Box::new(logger)).is_ok() { + log::set_max_level(log::LevelFilter::Trace); + } + + let events = sentry::test::with_captured_events(|| { + log::error!("Both a breadcrumb and an event"); + log::warn!("An event"); + }); + + assert_eq!(events.len(), 2); + + assert_eq!( + events[0].message, + Some("Both a breadcrumb and an event".to_owned()) + ); + + assert_eq!(events[1].message, Some("An event".to_owned())); + assert_eq!(events[1].breadcrumbs.len(), 1); + assert_eq!( + events[1].breadcrumbs[0].message, + Some("Both a breadcrumb and an event".into()) + ); +} + #[test] fn test_slog() { let drain = sentry_slog::SentryDrain::new(slog::Discard); From 65f7c9724f249a3fef75a0164ae69d8d5fd87adf Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Tue, 30 Sep 2025 16:05:58 +0200 Subject: [PATCH 02/11] improve --- sentry-log/src/logger.rs | 9 +-- sentry/tests/test_log.rs | 80 ----------------------- sentry/tests/test_log_combined_filters.rs | 37 +++++++++++ 3 files changed, 42 insertions(+), 84 deletions(-) create mode 100644 sentry/tests/test_log_combined_filters.rs diff --git a/sentry-log/src/logger.rs b/sentry-log/src/logger.rs index 804632e09..925e0f25e 100644 --- a/sentry-log/src/logger.rs +++ b/sentry-log/src/logger.rs @@ -9,7 +9,7 @@ use crate::converters::{breadcrumb_from_record, event_from_record, exception_fro bitflags! { /// The action that Sentry should perform for a [`log::Metadata`]. - #[derive(Debug, Clone, Copy)] + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct LogFilter: u32 { /// Ignore the [`Record`]. const Ignore = 0b0000; @@ -38,7 +38,8 @@ pub enum RecordMapping { #[cfg(feature = "logs")] Log(sentry_core::protocol::Log), /// Captures multiple items to Sentry. - /// Nesting multiple `RecordMapping::Combined` inside each other will cause the inner mappings to be ignored. + /// Nesting multiple `RecordMapping::Combined` is not supported and will cause the mappings to + /// be ignored. Combined(CombinedRecordMapping), } @@ -157,11 +158,11 @@ impl SentryLogger { impl log::Log for SentryLogger { fn enabled(&self, metadata: &log::Metadata<'_>) -> bool { - self.dest.enabled(metadata) || !((self.filter)(metadata).is_empty()) + self.dest.enabled(metadata) || !(self.filter)(metadata) == LogFilter::Ignore } fn log(&self, record: &log::Record<'_>) { - let items = match &self.mapper { + let items: RecordMapping = match &self.mapper { Some(mapper) => mapper(record), None => { let filter = (self.filter)(record.metadata()); diff --git a/sentry/tests/test_log.rs b/sentry/tests/test_log.rs index e1750e7b6..c460cf4ba 100644 --- a/sentry/tests/test_log.rs +++ b/sentry/tests/test_log.rs @@ -26,86 +26,6 @@ fn test_log() { assert_eq!(event.breadcrumbs[0].message, Some("Hello World!".into())); } -#[test] -fn test_combined_log_filters() { - let logger = sentry_log::SentryLogger::new().filter(|md| match md.level() { - log::Level::Error => sentry_log::LogFilter::Breadcrumb | sentry_log::LogFilter::Event, - log::Level::Warn => sentry_log::LogFilter::Event, - _ => sentry_log::LogFilter::Ignore, - }); - - // Only set logger if not already set to avoid conflicts with other tests - if log::set_boxed_logger(Box::new(logger)).is_ok() { - log::set_max_level(log::LevelFilter::Trace); - } - - let events = sentry::test::with_captured_events(|| { - log::error!("Both a breadcrumb and an event"); - log::warn!("An event"); - }); - - assert_eq!(events.len(), 2); - - assert_eq!( - events[0].message, - Some("Both a breadcrumb and an event".to_owned()) - ); - - assert_eq!(events[1].message, Some("An event".to_owned())); - assert_eq!(events[1].breadcrumbs.len(), 1); - assert_eq!( - events[1].breadcrumbs[0].message, - Some("Both a breadcrumb and an event".into()) - ); -} - -#[test] -fn test_combined_record_mapper() { - let logger = sentry_log::SentryLogger::new().mapper(|record| match record.metadata().level() { - log::Level::Error => { - let breadcrumb = sentry_log::breadcrumb_from_record(record); - let sentry_event = sentry_log::event_from_record(record); - - sentry_log::RecordMapping::Combined( - vec![ - sentry_log::RecordMapping::Breadcrumb(breadcrumb), - sentry_log::RecordMapping::Event(sentry_event), - ] - .into(), - ) - } - log::Level::Warn => { - let sentry_event = sentry_log::event_from_record(record); - sentry_log::RecordMapping::Event(sentry_event) - } - _ => sentry_log::RecordMapping::Ignore, - }); - - // Only set logger if not already set to avoid conflicts with other tests - if log::set_boxed_logger(Box::new(logger)).is_ok() { - log::set_max_level(log::LevelFilter::Trace); - } - - let events = sentry::test::with_captured_events(|| { - log::error!("Both a breadcrumb and an event"); - log::warn!("An event"); - }); - - assert_eq!(events.len(), 2); - - assert_eq!( - events[0].message, - Some("Both a breadcrumb and an event".to_owned()) - ); - - assert_eq!(events[1].message, Some("An event".to_owned())); - assert_eq!(events[1].breadcrumbs.len(), 1); - assert_eq!( - events[1].breadcrumbs[0].message, - Some("Both a breadcrumb and an event".into()) - ); -} - #[test] fn test_slog() { let drain = sentry_slog::SentryDrain::new(slog::Discard); diff --git a/sentry/tests/test_log_combined_filters.rs b/sentry/tests/test_log_combined_filters.rs new file mode 100644 index 000000000..8dd4b74ce --- /dev/null +++ b/sentry/tests/test_log_combined_filters.rs @@ -0,0 +1,37 @@ +#![cfg(feature = "test")] + +// Test `log` integration with combined filters. +// This must be in a separate file because `log::set_boxed_logger` can only be called once. + +#[test] +fn test_log_combined_filters() { + let logger = sentry_log::SentryLogger::new().filter(|md| match md.level() { + log::Level::Error => sentry_log::LogFilter::Breadcrumb | sentry_log::LogFilter::Event, + log::Level::Warn => sentry_log::LogFilter::Event, + _ => sentry_log::LogFilter::Ignore, + }); + + log::set_boxed_logger(Box::new(logger)) + .map(|()| log::set_max_level(log::LevelFilter::Trace)) + .unwrap(); + + let events = sentry::test::with_captured_events(|| { + log::error!("Both a breadcrumb and an event"); + log::warn!("An event"); + log::trace!("Ignored"); + }); + + assert_eq!(events.len(), 2); + + assert_eq!( + events[0].message, + Some("Both a breadcrumb and an event".to_owned()) + ); + + assert_eq!(events[1].message, Some("An event".to_owned())); + assert_eq!(events[1].breadcrumbs.len(), 1); + assert_eq!( + events[1].breadcrumbs[0].message, + Some("Both a breadcrumb and an event".into()) + ); +} From fb6dc781b5837efd8209a43dc1c5fe1dee1deb82 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Tue, 30 Sep 2025 16:07:26 +0200 Subject: [PATCH 03/11] improve --- sentry/tests/test_log_combined_filters.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry/tests/test_log_combined_filters.rs b/sentry/tests/test_log_combined_filters.rs index 8dd4b74ce..3342743ba 100644 --- a/sentry/tests/test_log_combined_filters.rs +++ b/sentry/tests/test_log_combined_filters.rs @@ -1,6 +1,6 @@ #![cfg(feature = "test")] -// Test `log` integration with combined filters. +// Test `log` integration with combined `LogFilter`s. // This must be in a separate file because `log::set_boxed_logger` can only be called once. #[test] From 79261c2fe689b6b51430c298778a4a04f657e78a Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:07:44 +0200 Subject: [PATCH 04/11] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21d1db4d2..1c120e8a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Breaking changes -- feat(log): support combined `LogFilter`s and `RecordMapping`s by @lcian +- feat(log): support combined LogFilters and RecordMappings ([#914](https://github.com/getsentry/sentry-rust/pull/914)) by @lcian - `sentry::integrations::log::LogFilter` has been changed to a `bitflags` struct. - It's now possible to map a `log` record to multiple items in Sentry by combining multiple log filters in the filter, e.g. `log::Level::ERROR => LogFilter::Event | LogFilter::Log`. - It's also possible to use `sentry::integrations::log::RecordMapping::Combined` to map a `log` record to multiple items in Sentry. From c5668e71ae7f9ca80333c1facd2783f5055c57ae Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:22:59 +0200 Subject: [PATCH 05/11] ref(log): send logs by default when logs feature flag is used --- sentry-log/src/logger.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sentry-log/src/logger.rs b/sentry-log/src/logger.rs index 925e0f25e..fb53cc074 100644 --- a/sentry-log/src/logger.rs +++ b/sentry-log/src/logger.rs @@ -68,7 +68,13 @@ impl From> for CombinedRecordMapping { /// `warning` and `info`, and `debug` and `trace` logs are ignored. pub fn default_filter(metadata: &log::Metadata) -> LogFilter { match metadata.level() { + #[cfg(feature = "logs")] + log::Level::Error => LogFilter::Exception | LogFilter::Log, + #[cfg(not(feature = "logs"))] log::Level::Error => LogFilter::Exception, + #[cfg(feature = "logs")] + log::Level::Warn | log::Level::Info => LogFilter::Breadcrumb | LogFilter::Log, + #[cfg(not(feature = "logs"))] log::Level::Warn | log::Level::Info => LogFilter::Breadcrumb, log::Level::Debug | log::Level::Trace => LogFilter::Ignore, } From b79bfd72dada71a5dfd317e81bea40f5f9be8f13 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:29:56 +0200 Subject: [PATCH 06/11] changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c120e8a6..406107460 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ - It's now possible to map a `log` record to multiple items in Sentry by combining multiple log filters in the filter, e.g. `log::Level::ERROR => LogFilter::Event | LogFilter::Log`. - It's also possible to use `sentry::integrations::log::RecordMapping::Combined` to map a `log` record to multiple items in Sentry. +### Behavioral changes + +- ref(log): send logs by default when logs feature flag is enabled ([#915](https://github.com/getsentry/sentry-rust/pull/915)) + - If the `logs` feature flag is enabled, the default Sentry `log` logger now sends logs for all events at or above INFO. + ## 0.43.0 ### Breaking changes From 056715685ce12560f5c43d87538cfeb0f2207016 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Wed, 1 Oct 2025 14:35:38 +0200 Subject: [PATCH 07/11] docs --- sentry-log/src/lib.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sentry-log/src/lib.rs b/sentry-log/src/lib.rs index 836fcfc6b..775221c66 100644 --- a/sentry-log/src/lib.rs +++ b/sentry-log/src/lib.rs @@ -11,13 +11,10 @@ //! - Records can be captured as traditional [logs](https://docs.sentry.io/product/explore/logs/) //! Logs can be viewed and queried in the Logs explorer. //! -//! By default anything above `Info` is recorded as a breadcrumb and -//! anything above `Error` is captured as error event. -//! -//! To capture records as Sentry logs: -//! 1. Enable the `logs` feature of the `sentry` crate. -//! 2. Initialize the SDK with `enable_logs: true` in your client options. -//! 3. Set up a custom filter (see below) to map records to logs (`LogFilter::Log`) based on criteria such as severity. +//! By default anything at or above `Info` is recorded as a breadcrumb and +//! anything at or above `Error` is captured as error event. +//! Additionally, if the `sentry` crate is used with the `logs` feature flag, anything at or above `Info` +//! is captured as a [Structured Log](https://docs.sentry.io/product/explore/logs/). //! //! # Examples //! From 7d96f91c412cf51dd7a7a54dac2181e9578f54ea Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Thu, 2 Oct 2025 09:04:36 +0200 Subject: [PATCH 08/11] trigger CI From 979411c06eb6c64d6f6010650b2cca827eb0de4d Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Thu, 2 Oct 2025 09:14:50 +0200 Subject: [PATCH 09/11] gate --- sentry-log/src/logger.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/sentry-log/src/logger.rs b/sentry-log/src/logger.rs index 925e0f25e..fc2372143 100644 --- a/sentry-log/src/logger.rs +++ b/sentry-log/src/logger.rs @@ -20,6 +20,7 @@ bitflags! { /// Create an exception [`Event`] from this [`Record`]. const Exception = 0b0100; /// Create a [`sentry_core::protocol::Log`] from this [`Record`]. + #[cfg(feature = "logs")] const Log = 0b1000; } } From 0da7c5e35895a2e3a83dc10bbc4533f1640be828 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Thu, 2 Oct 2025 09:45:15 +0200 Subject: [PATCH 10/11] fix --- sentry-log/src/logger.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry-log/src/logger.rs b/sentry-log/src/logger.rs index fc2372143..847d89df7 100644 --- a/sentry-log/src/logger.rs +++ b/sentry-log/src/logger.rs @@ -159,7 +159,7 @@ impl SentryLogger { impl log::Log for SentryLogger { fn enabled(&self, metadata: &log::Metadata<'_>) -> bool { - self.dest.enabled(metadata) || !(self.filter)(metadata) == LogFilter::Ignore + self.dest.enabled(metadata) || !((self.filter)(metadata) == LogFilter::Ignore) } fn log(&self, record: &log::Record<'_>) { From af75932584de6babd021286f9ef08dda2514cf0d Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Tue, 7 Oct 2025 11:35:04 +0200 Subject: [PATCH 11/11] fix --- sentry-log/src/logger.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/sentry-log/src/logger.rs b/sentry-log/src/logger.rs index 06930bd1f..f6cabd2a9 100644 --- a/sentry-log/src/logger.rs +++ b/sentry-log/src/logger.rs @@ -38,29 +38,6 @@ pub enum RecordMapping { /// Captures the [`sentry_core::protocol::Log`] to Sentry. #[cfg(feature = "logs")] Log(sentry_core::protocol::Log), - /// Captures multiple items to Sentry. - /// Nesting multiple `RecordMapping::Combined` is not supported and will cause the mappings to - /// be ignored. - Combined(CombinedRecordMapping), -} - -/// A list of record mappings. -#[derive(Debug)] -pub struct CombinedRecordMapping(Vec); - -impl From for CombinedRecordMapping { - fn from(value: RecordMapping) -> Self { - match value { - RecordMapping::Combined(combined) => combined, - _ => CombinedRecordMapping(vec![value]), - } - } -} - -impl From> for CombinedRecordMapping { - fn from(value: Vec) -> Self { - Self(value) - } } impl From for Vec {