sentry_slog/
converters.rs1use sentry_core::protocol::{Breadcrumb, Event, Level, Map, Value};
2use slog::{Key, OwnedKVList, Record, Serializer, KV};
3use std::fmt;
4
5pub fn convert_log_level(level: slog::Level) -> Level {
7 match level {
8 slog::Level::Trace | slog::Level::Debug => Level::Debug,
9 slog::Level::Info => Level::Info,
10 slog::Level::Warning => Level::Warning,
11 slog::Level::Error | slog::Level::Critical => Level::Error,
12 }
13}
14
15struct MapSerializer<'a>(&'a mut Map<String, Value>);
16
17macro_rules! impl_into {
18 ($t:ty => $f:ident) => {
19 fn $f(&mut self, key: Key, val: $t) -> slog::Result {
20 self.0.insert(key.into(), val.into());
21 Ok(())
22 }
23 };
24}
25impl Serializer for MapSerializer<'_> {
26 fn emit_arguments(&mut self, key: Key, val: &fmt::Arguments) -> slog::Result {
27 self.0.insert(key.into(), val.to_string().into());
28 Ok(())
29 }
30
31 fn emit_serde(&mut self, key: Key, val: &dyn slog::SerdeValue) -> slog::Result {
32 let value = serde_json::to_value(val.as_serde()).map_err(|_e| slog::Error::Other)?;
33 self.0.insert(key.into(), value);
34 Ok(())
35 }
36
37 impl_into! { usize => emit_usize }
38 impl_into! { isize => emit_isize }
39 impl_into! { bool => emit_bool }
40 impl_into! { u8 => emit_u8 }
41 impl_into! { i8 => emit_i8 }
42 impl_into! { u16 => emit_u16 }
43 impl_into! { i16 => emit_i16 }
44 impl_into! { u32 => emit_u32 }
45 impl_into! { i32 => emit_i32 }
46 impl_into! { f32 => emit_f32 }
47 impl_into! { u64 => emit_u64 }
48 impl_into! { i64 => emit_i64 }
49 impl_into! { f64 => emit_f64 }
50 impl_into! { &str => emit_str }
51}
52
53fn add_kv_to_map(map: &mut Map<String, Value>, record: &Record, kv: &impl KV) {
55 let _ = record.kv().serialize(record, &mut MapSerializer(map));
57 let _ = kv.serialize(record, &mut MapSerializer(map));
58}
59
60pub fn breadcrumb_from_record(record: &Record, values: &OwnedKVList) -> Breadcrumb {
62 let mut data = Map::new();
63 add_kv_to_map(&mut data, record, values);
64
65 Breadcrumb {
66 ty: "log".into(),
67 message: Some(record.msg().to_string()),
68 level: convert_log_level(record.level()),
69 data,
70 ..Default::default()
71 }
72}
73
74pub fn event_from_record(record: &Record, values: &OwnedKVList) -> Event<'static> {
76 let mut extra = Map::new();
77 add_kv_to_map(&mut extra, record, values);
78 Event {
79 message: Some(record.msg().to_string()),
80 level: convert_log_level(record.level()),
81 extra,
82 ..Default::default()
83 }
84}
85
86pub fn exception_from_record(record: &Record, values: &OwnedKVList) -> Event<'static> {
97 event_from_record(record, values)
102}
103
104#[cfg(test)]
105mod test {
106 use super::*;
107 use serde::Serialize;
108
109 use slog::{b, o, record, Level};
110
111 #[derive(Serialize, Clone)]
112 struct Something {
113 msg: String,
114 count: usize,
115 }
116
117 impl slog::Value for Something {
118 fn serialize(
119 &self,
120 _record: &Record,
121 key: Key,
122 serializer: &mut dyn slog::Serializer,
123 ) -> slog::Result {
124 serializer.emit_serde(key, self)
125 }
126 }
127
128 impl slog::SerdeValue for Something {
129 fn as_serde(&self) -> &dyn erased_serde::Serialize {
130 self
131 }
132
133 fn to_sendable(&self) -> Box<dyn slog::SerdeValue + Send + 'static> {
134 Box::new(self.clone())
135 }
136 }
137
138 #[test]
139 fn test_slog_kvs() {
140 let extras = o!("lib" => "sentry", "version" => 1, "test" => true);
141
142 let mut map: Map<String, Value> = Map::new();
143
144 add_kv_to_map(
145 &mut map,
146 &record!(
147 Level::Debug,
148 "test",
149 &format_args!("Hello, world!"),
150 b!("something" => &Something {
151 msg: "message!".into(),
152 count: 42,
153 })
154 ),
155 &extras,
156 );
157
158 assert_eq!(map.get("lib"), Some(&"sentry".into()));
159 assert_eq!(map.get("version"), Some(&1.into()));
160 assert_eq!(map.get("test"), Some(&true.into()));
161 assert_eq!(
162 map.get("something"),
163 Some(&Value::Object(
164 vec![
165 ("msg".to_string(), Value::from("message!")),
166 ("count".to_string(), Value::from(42))
167 ]
168 .into_iter()
169 .collect()
170 ))
171 )
172 }
173}