Skip to content

Commit 07aa6dc

Browse files
authored
Reduce allocations for kv from log to slog (#25)
See: rust-lang/log#328
1 parent c6eba10 commit 07aa6dc

File tree

2 files changed

+67
-20
lines changed

2 files changed

+67
-20
lines changed

kv.rs

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,82 @@
1+
use log::kv::value::Error as ValueError;
12
use slog::{Record, Serializer};
23

3-
pub(crate) struct Visitor {
4-
kvs: Vec<(String, String)>,
4+
struct Visitor<'s> {
5+
serializer: &'s mut dyn Serializer,
56
}
67

7-
impl Visitor {
8-
pub fn new() -> Self {
9-
Self { kvs: vec![] }
8+
impl<'s> Visitor<'s> {
9+
pub fn new(serializer: &'s mut dyn Serializer) -> Self {
10+
Self { serializer }
1011
}
1112
}
1213

13-
impl<'kvs, 'a> log::kv::Visitor<'kvs> for Visitor {
14+
pub(crate) struct SourceKV<'kvs>(pub &'kvs dyn log::kv::source::Source);
15+
16+
struct KeyVisit<'s> {
17+
serializer: &'s mut dyn Serializer,
18+
key: &'s str,
19+
}
20+
21+
impl<'kvs> log::kv::Visitor<'kvs> for Visitor<'kvs> {
1422
fn visit_pair(
1523
&mut self,
1624
key: log::kv::Key<'kvs>,
1725
val: log::kv::Value<'kvs>,
1826
) -> Result<(), log::kv::Error> {
19-
let key = key.to_string();
20-
if let Some(val) = val.to_borrowed_str() {
21-
let val = val.to_string();
22-
self.kvs.push((key, val));
27+
val.visit(KeyVisit {
28+
serializer: self.serializer,
29+
key: key.as_str(),
30+
})
31+
}
32+
}
33+
34+
macro_rules! visit_to_emit {
35+
($t:ty : $vname:ident -> $ename:ident) => {
36+
fn $vname(&mut self, value: $t) -> Result<(), ValueError> {
37+
self.serializer
38+
.$ename(self.key.to_string().into(), value)
39+
.map_err(to_value_err)
2340
}
24-
Ok(())
41+
};
42+
}
43+
44+
impl<'s> log::kv::value::Visit<'s> for KeyVisit<'s> {
45+
fn visit_any(&mut self, value: log::kv::Value<'_>) -> Result<(), ValueError> {
46+
let key = self.key.to_string().into();
47+
self.serializer
48+
.emit_arguments(key, &format_args!("{}", value))
49+
.map_err(to_value_err)
2550
}
51+
52+
visit_to_emit!(u64: visit_u64 -> emit_u64);
53+
visit_to_emit!(i64: visit_i64 -> emit_i64);
54+
visit_to_emit!(u128: visit_u128 -> emit_u128);
55+
visit_to_emit!(i128: visit_i128 -> emit_i128);
56+
visit_to_emit!(f64: visit_f64 -> emit_f64);
57+
visit_to_emit!(bool: visit_bool -> emit_bool);
58+
visit_to_emit!(&str: visit_str -> emit_str);
59+
visit_to_emit!(char: visit_char -> emit_char);
60+
visit_to_emit!(&(dyn std::error::Error + 'static): visit_error -> emit_error);
2661
}
2762

28-
impl slog::KV for Visitor {
63+
impl slog::KV for SourceKV<'_> {
2964
fn serialize(&self, _record: &Record, serializer: &mut dyn Serializer) -> slog::Result {
30-
for (key, val) in &self.kvs {
31-
serializer.emit_str(key.to_owned().into(), val.as_str())?;
32-
}
33-
Ok(())
65+
// Unfortunately, there isn't a way for use to pass the original error through.
66+
self.0
67+
.visit(&mut Visitor::new(serializer))
68+
.map_err(|_| slog::Error::Other)
3469
}
3570
}
71+
72+
fn to_value_err(err: slog::Error) -> ValueError {
73+
use slog::Error::*;
74+
75+
match err {
76+
Io(e) => e.into(),
77+
Fmt(e) => e.into(),
78+
Other => ValueError::boxed(err),
79+
}
80+
}
81+
82+
// TODO: support going the other way

lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ impl log::Log for Logger {
100100
};
101101
#[cfg(feature = "kv_unstable")]
102102
{
103-
let key_values = r.key_values();
104-
let mut visitor = kv::Visitor::new();
105-
key_values.visit(&mut visitor).unwrap();
106-
slog_scope::with_logger(|logger| logger.log(&slog::Record::new(&s, args, b!(visitor))))
103+
let key_values = kv::SourceKV(r.key_values());
104+
slog_scope::with_logger(|logger| {
105+
logger.log(&slog::Record::new(&s, args, b!(key_values)))
106+
})
107107
}
108108
#[cfg(not(feature = "kv_unstable"))]
109109
slog_scope::with_logger(|logger| logger.log(&slog::Record::new(&s, args, b!())))

0 commit comments

Comments
 (0)