Skip to content

Commit 2f0a241

Browse files
committed
Support forwarding structured data to log implementation
See: #328
1 parent c6eba10 commit 2f0a241

File tree

2 files changed

+111
-12
lines changed

2 files changed

+111
-12
lines changed

kv.rs

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use slog::{Record, Serializer};
1+
use slog::{Record, Serializer, KV};
2+
3+
use std::fmt::Arguments;
24

35
pub(crate) struct Visitor {
46
kvs: Vec<(String, String)>,
@@ -25,11 +27,105 @@ impl<'kvs, 'a> log::kv::Visitor<'kvs> for Visitor {
2527
}
2628
}
2729

28-
impl slog::KV for Visitor {
30+
impl KV for Visitor {
2931
fn serialize(&self, _record: &Record, serializer: &mut dyn Serializer) -> slog::Result {
3032
for (key, val) in &self.kvs {
3133
serializer.emit_str(key.to_owned().into(), val.as_str())?;
3234
}
3335
Ok(())
3436
}
3537
}
38+
39+
/// Create a [`log::kv::Source`] for the key-value pairs for a slog record.
40+
pub(crate) fn get_kv_source<'a>(
41+
record: &'a slog::Record<'a>,
42+
logger_kv: &'a slog::OwnedKVList,
43+
) -> std::io::Result<Vec<(String, OwnedValue)>> {
44+
let mut serialized_source = LogSerializer(vec![]);
45+
46+
record.kv().serialize(record, &mut serialized_source)?;
47+
logger_kv.serialize(record, &mut serialized_source)?;
48+
Ok(serialized_source.0)
49+
}
50+
51+
/// A wrapper around [`log::kv::Value`], that owns the data included.
52+
///
53+
/// In particular this is necessary for strings, and large integers (u128, and i128), because the
54+
/// `Value` type itself only supports references, which must survive for the lifetime of the
55+
/// visitor.
56+
pub(crate) enum OwnedValue {
57+
Value(log::kv::Value<'static>),
58+
Str(String),
59+
U128(Box<u128>),
60+
I128(Box<i128>),
61+
}
62+
63+
impl log::kv::value::ToValue for OwnedValue {
64+
fn to_value(&self) -> log::kv::Value<'_> {
65+
use OwnedValue::*;
66+
67+
match self {
68+
Value(v) => v.to_value(),
69+
Str(s) => s.to_value(),
70+
U128(v) => v.to_value(),
71+
I128(v) => v.to_value(),
72+
}
73+
}
74+
}
75+
76+
struct LogSerializer(Vec<(String, OwnedValue)>);
77+
78+
impl LogSerializer {
79+
fn add(&mut self, key: slog::Key, val: OwnedValue) -> slog::Result {
80+
self.0.push((key.into(), val));
81+
Ok(())
82+
}
83+
}
84+
85+
macro_rules! emit_to_value {
86+
($f:ident : $t:ty) => {
87+
fn $f(&mut self, key: slog::Key, val: $t) -> slog::Result {
88+
self.add(key, OwnedValue::Value(val.into()))
89+
}
90+
};
91+
}
92+
93+
impl Serializer for LogSerializer {
94+
fn emit_arguments(&mut self, key: slog::Key, val: &Arguments<'_>) -> slog::Result {
95+
self.add(key, OwnedValue::Str(val.to_string()))
96+
}
97+
98+
emit_to_value!(emit_usize: usize);
99+
emit_to_value!(emit_isize: isize);
100+
emit_to_value!(emit_bool: bool);
101+
emit_to_value!(emit_char: char);
102+
emit_to_value!(emit_u8: u8);
103+
emit_to_value!(emit_i8: i8);
104+
emit_to_value!(emit_u16: u16);
105+
emit_to_value!(emit_i16: i16);
106+
emit_to_value!(emit_u32: u32);
107+
emit_to_value!(emit_i32: i32);
108+
emit_to_value!(emit_f32: f32);
109+
emit_to_value!(emit_f64: f64);
110+
111+
fn emit_u128(&mut self, key: slog::Key, val: u128) -> slog::Result {
112+
self.add(key, OwnedValue::U128(Box::new(val)))
113+
}
114+
115+
fn emit_i128(&mut self, key: slog::Key, val: i128) -> slog::Result {
116+
self.add(key, OwnedValue::I128(Box::new(val)))
117+
}
118+
119+
fn emit_str(&mut self, key: slog::Key, val: &str) -> slog::Result {
120+
self.add(key, OwnedValue::Str(val.to_string()))
121+
}
122+
123+
fn emit_unit(&mut self, key: slog::Key) -> slog::Result {
124+
use log::kv::ToValue;
125+
self.add(key, OwnedValue::Value(().to_value()))
126+
}
127+
128+
fn emit_none(&mut self, key: slog::Key) -> slog::Result {
129+
self.emit_unit(key)
130+
}
131+
}

lib.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -266,16 +266,19 @@ impl slog::Drain for StdLog {
266266
* This avoids using the private log::__private_api_log api function,
267267
* which is just a thin wrapper around a `RecordBuilder`.
268268
*/
269-
log::logger().log(
270-
&log::Record::builder()
271-
.args(format_args!("{}", lazy))
272-
.level(level)
273-
.target(target)
274-
.module_path_static(Some(info.module()))
275-
.file_static(Some(info.file()))
276-
.line(Some(info.line()))
277-
.build(),
278-
);
269+
let mut record_builder = log::Record::builder();
270+
record_builder
271+
.level(level)
272+
.target(target)
273+
.module_path_static(Some(info.module()))
274+
.file_static(Some(info.file()))
275+
.line(Some(info.line()));
276+
#[cfg(feature = "kv_unstable")]
277+
let source = kv::get_kv_source(info, logger_values)?;
278+
#[cfg(feature = "kv_unstable")]
279+
record_builder.key_values(&source);
280+
281+
log::logger().log(&record_builder.args(format_args!("{}", lazy)).build());
279282

280283
Ok(())
281284
}

0 commit comments

Comments
 (0)