1use std::collections::HashMap;
2
3use serde_json::json;
4use tracing_core::Subscriber;
5use tracing_subscriber::{Layer, registry::LookupSpan};
6
7use crate::{TimestampFormat, storage::JsonStorage};
8
9type FieldFilter = Box<dyn Fn(&str) -> bool + Send + Sync>;
10
11pub struct JsonFormattingLayer {
12 pub(crate) level_name: &'static str,
13 pub(crate) level_value_casing: crate::Casing,
14 pub(crate) message_name: &'static str,
15 pub(crate) target_name: &'static str,
16 pub(crate) timestamp_name: &'static str,
17 pub(crate) timestamp_format: crate::TimestampFormat,
18 pub(crate) line_numbers: bool,
19 pub(crate) file_names: bool,
20 pub(crate) flatten_fields: bool,
21 pub(crate) flatten_spans: bool,
22 pub(crate) field_filter: Option<FieldFilter>,
23}
24
25impl Default for JsonFormattingLayer {
26 fn default() -> Self {
27 Self {
28 level_name: "level",
29 level_value_casing: crate::Casing::default(),
30 message_name: "message",
31 target_name: "target",
32 timestamp_name: "timestamp",
33 timestamp_format: crate::TimestampFormat::default(),
34 line_numbers: false,
35 file_names: false,
36 flatten_fields: true,
37 flatten_spans: true,
38 field_filter: None,
39 }
40 }
41}
42
43impl JsonFormattingLayer {
44 fn insert_fields<'k: 'v, 'v>(
45 &self,
46 source: impl Iterator<Item = (&'v &'k str, &'v serde_json::Value)>,
47 dest: &mut HashMap<&'k str, serde_json::Value>,
48 ) {
49 for (&k, v) in source {
50 if let Some(ref f) = self.field_filter
51 && !f(k)
52 {
53 continue;
54 }
55 let key = if k == "message" { self.message_name } else { k };
56 dest.insert(key, v.clone());
57 }
58 }
59}
60
61impl<S> Layer<S> for JsonFormattingLayer
62where
63 S: Subscriber + for<'a> LookupSpan<'a>,
64{
65 fn on_new_span(
66 &self,
67 attrs: &tracing_core::span::Attributes<'_>,
68 id: &tracing_core::span::Id,
69 ctx: tracing_subscriber::layer::Context<'_, S>,
70 ) {
71 let span = ctx.span(id).expect("Span not found, this is a bug");
72
73 let mut visitor = JsonStorage::default();
75
76 attrs.record(&mut visitor);
79
80 let mut extensions = span.extensions_mut();
82 extensions.insert(visitor);
83 }
84
85 fn on_record(
86 &self,
87 span: &tracing_core::span::Id,
88 values: &tracing_core::span::Record<'_>,
89 ctx: tracing_subscriber::layer::Context<'_, S>,
90 ) {
91 let span = ctx.span(span).expect("Span not found, this is a bug");
92
93 let mut extensions = span.extensions_mut();
97 let visitor = extensions
98 .get_mut::<JsonStorage>()
99 .expect("Visitor not found on 'record', this is a bug");
100 values.record(visitor);
102 }
103
104 fn on_event(
105 &self,
106 event: &tracing_core::Event<'_>,
107 _ctx: tracing_subscriber::layer::Context<'_, S>,
108 ) {
109 let mut visitor = crate::storage::JsonStorage::default();
111 event.record(&mut visitor);
112
113 let mut root: HashMap<&str, serde_json::Value> = HashMap::new();
114
115 let level = event.metadata().level();
117 let level_str = match self.level_value_casing {
118 crate::Casing::Lowercase => match *level {
119 tracing_core::Level::TRACE => "trace",
120 tracing_core::Level::DEBUG => "debug",
121 tracing_core::Level::INFO => "info",
122 tracing_core::Level::WARN => "warn",
123 tracing_core::Level::ERROR => "error",
124 },
125 crate::Casing::Uppercase => match *level {
126 tracing_core::Level::TRACE => "TRACE",
127 tracing_core::Level::DEBUG => "DEBUG",
128 tracing_core::Level::INFO => "INFO",
129 tracing_core::Level::WARN => "WARN",
130 tracing_core::Level::ERROR => "ERROR",
131 },
132 };
133 root.insert(self.level_name, json!(level_str));
134
135 root.insert(self.target_name, json!(event.metadata().target()));
137
138 let timestamp = match &self.timestamp_format {
140 TimestampFormat::Unix | TimestampFormat::UnixMillis => {
141 json!(self.timestamp_format.format_number(&chrono::Utc::now()))
142 }
143 TimestampFormat::Rfc3339 | TimestampFormat::Rfc3339Nanos => {
144 json!(self.timestamp_format.format_string(&chrono::Utc::now()))
145 }
146 TimestampFormat::Custom(_) => {
147 json!(self.timestamp_format.format_string(&chrono::Utc::now()))
148 }
149 };
150 root.insert(self.timestamp_name, timestamp);
151
152 if self.file_names && event.metadata().file().is_some() {
153 root.insert("file", json!(event.metadata().file().expect("is some")));
154 }
155
156 if self.line_numbers && event.metadata().line().is_some() {
157 root.insert("line", json!(event.metadata().line().expect("is some")));
158 }
159
160 if self.flatten_fields {
162 self.insert_fields(visitor.values().iter(), &mut root);
163 } else {
164 let mut fields = HashMap::new();
165 self.insert_fields(visitor.values().iter(), &mut fields);
166 root.insert("fields", json!(fields));
167 }
168
169 let mut spans = vec![];
171 if let Some(leaf_span) = _ctx.lookup_current() {
172 for span in leaf_span.scope().from_root() {
173 let mut fields = HashMap::new();
174 let ext = span.extensions();
175 let visitor = ext.get::<crate::storage::JsonStorage>();
176 if let Some(visitor) = visitor {
177 self.insert_fields(visitor.values().iter(), &mut fields);
178 }
179 if !fields.is_empty() {
180 spans.push(fields);
181 }
182 }
183 }
184
185 if !spans.is_empty() {
186 if self.flatten_spans {
187 for fields in &spans {
188 self.insert_fields(fields.iter(), &mut root);
189 }
190 } else {
191 root.insert("spans", json!(spans));
192 }
193 }
194
195 let output = serde_json::to_string(&root).unwrap();
196 println!("{}", output);
197 }
198}