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