Skip to content

Commit 697c0b3

Browse files
committed
feat(layer): simple renames of flattened event fields
1 parent edcff72 commit 697c0b3

3 files changed

Lines changed: 181 additions & 0 deletions

File tree

src/layer/mod.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use uuid::Uuid;
3030
use crate::{
3131
cached::Cached,
3232
fields::{JsonFields, JsonFieldsInner},
33+
serde::RenamedFields,
3334
visitor::JsonVisitor,
3435
};
3536

@@ -790,6 +791,21 @@ where
790791
self
791792
}
792793

794+
pub fn with_flattened_event_with_renames<F, T>(&mut self, renames: F, context: T) -> &mut Self
795+
where
796+
F: for<'a> Fn(&'a str, &'a T) -> &'a str + Send + Sync + 'static + Clone,
797+
T: Clone + Send + Sync + 'static,
798+
{
799+
self.flattened_values.insert(
800+
FlatSchemaKey::FlattenedEvent,
801+
JsonValue::DynamicFromEvent(Box::new(move |event| {
802+
serde_json::to_value(RenamedFields::new(event.event(), renames.clone(), &context))
803+
.ok()
804+
})),
805+
);
806+
self
807+
}
808+
793809
/// Sets whether or not the log line will include the current span in formatted events.
794810
pub fn with_current_span(&mut self, key: impl Into<String>) -> &mut Self {
795811
self.keyed_values.insert(
@@ -1158,6 +1174,8 @@ fn write_escaped(writer: &mut dyn fmt::Write, value: &str) -> Result<(), fmt::Er
11581174

11591175
#[cfg(test)]
11601176
mod tests {
1177+
use std::collections::HashMap;
1178+
11611179
use serde_json::json;
11621180
use tracing::subscriber::with_default;
11631181
use tracing_subscriber::{registry, Layer, Registry};
@@ -1214,4 +1232,37 @@ mod tests {
12141232
tracing::info!(does = "not matter", "whatever");
12151233
});
12161234
}
1235+
1236+
#[test]
1237+
fn flattened_event_with_renames() {
1238+
let renames = HashMap::from([
1239+
("message".to_owned(), "msg".to_owned()),
1240+
("msg".to_owned(), "message".to_owned()),
1241+
("same".to_owned(), "same".to_owned()),
1242+
("different".to_owned(), "gone".to_owned()),
1243+
]);
1244+
let mut layer = JsonLayer::stdout();
1245+
layer.with_flattened_event_with_renames(
1246+
move |name, map| map.get(name).unwrap().as_str(),
1247+
renames,
1248+
);
1249+
1250+
let expected = json!({
1251+
"message": "msg",
1252+
"msg": "message",
1253+
"same": "same",
1254+
"gone": "different",
1255+
"another": "another",
1256+
});
1257+
1258+
test_json(&expected, layer, || {
1259+
tracing::info!(
1260+
msg = "msg",
1261+
same = "same",
1262+
different = "different",
1263+
another = "another",
1264+
"message"
1265+
);
1266+
});
1267+
}
12171268
}

src/serde/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
mod tracing_serde;
2+
13
use serde_json::ser::Formatter;
4+
pub(crate) use tracing_serde::RenamedFields;
25

36
pub(crate) struct JsonSubscriberFormatter;
47

src/serde/tracing_serde.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
use std::{fmt, mem::transmute};
2+
3+
use serde::{ser::SerializeMap, Serialize, Serializer};
4+
use tracing::{field::Visit, Event};
5+
use tracing_core::Field;
6+
7+
pub(crate) struct RenamedFields<'a, F, C> {
8+
event: &'a Event<'a>,
9+
renames: F,
10+
context: &'a C,
11+
}
12+
13+
impl<'a, F, C> RenamedFields<'a, F, C> {
14+
pub(crate) fn new(event: &'a Event<'a>, renames: F, context: &'a C) -> Self {
15+
Self {
16+
event,
17+
renames,
18+
context,
19+
}
20+
}
21+
}
22+
23+
impl<F, C> Serialize for RenamedFields<'_, F, C>
24+
where
25+
F: for<'a> Fn(&'a str, &'a C) -> &'a str + Send + Sync + 'static,
26+
{
27+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
28+
where
29+
S: Serializer,
30+
{
31+
let len = self.event.fields().count();
32+
let serializer = serializer.serialize_map(Some(len))?;
33+
let renames: &'static F = unsafe { transmute(&self.renames) };
34+
let mut visitor = SerdeMapVisitor::new(serializer, renames, self.context);
35+
self.event.record(&mut visitor);
36+
visitor.finish()
37+
}
38+
}
39+
40+
/// Implements `tracing_core::field::Visit` for some `serde::ser::SerializeMap`.
41+
#[derive(Debug)]
42+
pub struct SerdeMapVisitor<'a, S: SerializeMap, F, C> {
43+
serializer: S,
44+
renames: F,
45+
context: &'a C,
46+
state: Result<(), S::Error>,
47+
}
48+
49+
impl<'a, S, F, C> SerdeMapVisitor<'a, S, F, C>
50+
where
51+
S: SerializeMap,
52+
{
53+
/// Create a new map visitor.
54+
pub fn new(serializer: S, renames: F, context: &'a C) -> Self {
55+
Self {
56+
serializer,
57+
renames,
58+
context,
59+
state: Ok(()),
60+
}
61+
}
62+
63+
/// Completes serializing the visited object, returning `Ok(())` if all
64+
/// fields were serialized correctly, or `Error(S::Error)` if a field could
65+
/// not be serialized.
66+
pub fn finish(self) -> Result<S::Ok, S::Error> {
67+
self.state?;
68+
self.serializer.end()
69+
}
70+
}
71+
72+
impl<S, F, C> Visit for SerdeMapVisitor<'_, S, F, C>
73+
where
74+
S: SerializeMap,
75+
F: for<'a> Fn(&'a str, &'a C) -> &'a str + Send + Sync + 'static,
76+
{
77+
fn record_bool(&mut self, field: &Field, value: bool) {
78+
// If previous fields serialized successfully, continue serializing,
79+
// otherwise, short-circuit and do nothing.
80+
if self.state.is_ok() {
81+
self.state = self
82+
.serializer
83+
.serialize_entry((self.renames)(field.name(), self.context), &value);
84+
}
85+
}
86+
87+
fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
88+
if self.state.is_ok() {
89+
self.state = self.serializer.serialize_entry(
90+
(self.renames)(field.name(), self.context),
91+
&format_args!("{value:?}"),
92+
);
93+
}
94+
}
95+
96+
fn record_u64(&mut self, field: &Field, value: u64) {
97+
if self.state.is_ok() {
98+
self.state = self
99+
.serializer
100+
.serialize_entry((self.renames)(field.name(), self.context), &value);
101+
}
102+
}
103+
104+
fn record_i64(&mut self, field: &Field, value: i64) {
105+
if self.state.is_ok() {
106+
self.state = self
107+
.serializer
108+
.serialize_entry((self.renames)(field.name(), self.context), &value);
109+
}
110+
}
111+
112+
fn record_f64(&mut self, field: &Field, value: f64) {
113+
if self.state.is_ok() {
114+
self.state = self
115+
.serializer
116+
.serialize_entry((self.renames)(field.name(), self.context), &value);
117+
}
118+
}
119+
120+
fn record_str(&mut self, field: &Field, value: &str) {
121+
if self.state.is_ok() {
122+
self.state = self
123+
.serializer
124+
.serialize_entry((self.renames)(field.name(), self.context), &value);
125+
}
126+
}
127+
}

0 commit comments

Comments
 (0)