sentry_log/
converters.rs

1use sentry_core::protocol::Event;
2#[cfg(feature = "logs")]
3use sentry_core::protocol::{Log, LogAttribute, LogLevel};
4use sentry_core::{Breadcrumb, Level};
5#[cfg(feature = "logs")]
6use std::{collections::BTreeMap, time::SystemTime};
7
8/// Converts a [`log::Level`] to a Sentry [`Level`], used for [`Event`] and [`Breadcrumb`].
9pub fn convert_log_level(level: log::Level) -> Level {
10    match level {
11        log::Level::Error => Level::Error,
12        log::Level::Warn => Level::Warning,
13        log::Level::Info => Level::Info,
14        log::Level::Debug | log::Level::Trace => Level::Debug,
15    }
16}
17
18/// Converts a [`log::Level`] to a Sentry [`LogLevel`], used for [`Log`].
19#[cfg(feature = "logs")]
20pub fn convert_log_level_to_sentry_log_level(level: log::Level) -> LogLevel {
21    match level {
22        log::Level::Error => LogLevel::Error,
23        log::Level::Warn => LogLevel::Warn,
24        log::Level::Info => LogLevel::Info,
25        log::Level::Debug => LogLevel::Debug,
26        log::Level::Trace => LogLevel::Trace,
27    }
28}
29
30/// Creates a [`Breadcrumb`] from a given [`log::Record`].
31pub fn breadcrumb_from_record(record: &log::Record<'_>) -> Breadcrumb {
32    Breadcrumb {
33        ty: "log".into(),
34        level: convert_log_level(record.level()),
35        category: Some(record.target().into()),
36        message: Some(record.args().to_string()),
37        ..Default::default()
38    }
39}
40
41/// Creates an [`Event`] from a given [`log::Record`].
42pub fn event_from_record(record: &log::Record<'_>) -> Event<'static> {
43    Event {
44        logger: Some(record.target().into()),
45        level: convert_log_level(record.level()),
46        message: Some(record.args().to_string()),
47        ..Default::default()
48    }
49}
50
51/// Creates an exception [`Event`] from a given [`log::Record`].
52pub fn exception_from_record(record: &log::Record<'_>) -> Event<'static> {
53    // TODO: Exception records in Sentry need a valid type, value and full stack trace to support
54    // proper grouping and issue metadata generation. log::Record does not contain sufficient
55    // information for this. However, it may contain a serialized error which we can parse to emit
56    // an exception record.
57    event_from_record(record)
58}
59
60/// Creates a [`Log`] from a given [`log::Record`].
61#[cfg(feature = "logs")]
62pub fn log_from_record(record: &log::Record<'_>) -> Log {
63    let mut attributes: BTreeMap<String, LogAttribute> = BTreeMap::new();
64
65    attributes.insert("logger.target".into(), record.target().into());
66    if let Some(module_path) = record.module_path() {
67        attributes.insert("logger.module_path".into(), module_path.into());
68    }
69    if let Some(file) = record.file() {
70        attributes.insert("logger.file".into(), file.into());
71    }
72    if let Some(line) = record.line() {
73        attributes.insert("logger.line".into(), line.into());
74    }
75
76    attributes.insert("sentry.origin".into(), "auto.logger.log".into());
77
78    // TODO: support the `kv` feature and store key value pairs as attributes
79
80    Log {
81        level: convert_log_level_to_sentry_log_level(record.level()),
82        body: format!("{}", record.args()),
83        trace_id: None,
84        timestamp: SystemTime::now(),
85        severity_number: None,
86        attributes,
87    }
88}