1use crate::fail;
2use crate::printer::{PrettyPrinter, TestCapturePrinter};
3use crate::processor::{Processor, Sink};
4use crate::tag::{NoTag, Tag, TagParser};
5use crate::tree::{self, FieldSet, Tree};
6#[cfg(feature = "chrono")]
7use chrono::Utc;
8use std::fmt;
9use std::io::{self, Write};
10use std::time::Instant;
11use tracing::field::{Field, Visit};
12use tracing::span::{Attributes, Id};
13use tracing::{Event, Subscriber};
14use tracing_subscriber::layer::{Context, Layer, SubscriberExt};
15use tracing_subscriber::registry::{LookupSpan, Registry, SpanRef};
16use tracing_subscriber::util::SubscriberInitExt;
17use tracing_subscriber::util::TryInitError;
18#[cfg(feature = "uuid")]
19use uuid::Uuid;
20#[cfg(feature = "uuid")]
21pub(crate) mod id;
22
23pub(crate) struct OpenedSpan {
24 span: tree::Span,
25 start: Instant,
26}
27
28impl OpenedSpan {
29 fn new<S>(attrs: &Attributes, _ctx: &Context<S>) -> Self
30 where
31 S: Subscriber + for<'a> LookupSpan<'a>,
32 {
33 let mut fields = FieldSet::default();
34 #[cfg(feature = "uuid")]
35 let mut maybe_uuid = None;
36
37 attrs.record(&mut |field: &Field, value: &dyn fmt::Debug| {
38 #[cfg(feature = "uuid")]
39 if field.name() == "uuid" && maybe_uuid.is_none() {
40 const LENGTH: usize = 45;
41 let mut buf = [0u8; LENGTH];
42 let mut remaining = &mut buf[..];
43
44 if let Ok(()) = write!(remaining, "{:?}", value) {
45 let len = LENGTH - remaining.len();
46 if let Some(parsed) = id::try_parse(&buf[..len]) {
47 maybe_uuid = Some(parsed);
48 }
49 }
50 return;
51 }
52
53 let value = format!("{:?}", value);
54 fields.push(tree::Field::new(field.name(), value));
55 });
56
57 let shared = tree::Shared {
58 #[cfg(feature = "chrono")]
59 timestamp: Utc::now(),
60 level: *attrs.metadata().level(),
61 fields,
62 #[cfg(feature = "uuid")]
63 uuid: maybe_uuid.unwrap_or_else(|| match _ctx.lookup_current() {
64 Some(parent) => parent
65 .extensions()
66 .get::<OpenedSpan>()
67 .expect(fail::OPENED_SPAN_NOT_IN_EXTENSIONS)
68 .span
69 .uuid(),
70 None => Uuid::new_v4(),
71 }),
72 };
73
74 OpenedSpan {
75 span: tree::Span::new(shared, attrs.metadata().name()),
76 start: Instant::now(),
77 }
78 }
79
80 fn enter(&mut self) {
81 self.start = Instant::now();
82 }
83
84 fn exit(&mut self) {
85 self.span.total_duration += self.start.elapsed();
86 }
87
88 fn close(self) -> tree::Span {
89 self.span
90 }
91
92 fn record_event(&mut self, event: tree::Event) {
93 #[cfg(feature = "uuid")]
94 let event = {
95 let mut event = event;
96 event.shared.uuid = self.span.uuid();
97 event
98 };
99
100 self.span.nodes.push(Tree::Event(event));
101 }
102
103 fn record_span(&mut self, span: tree::Span) {
104 self.span.inner_duration += span.total_duration();
105 self.span.nodes.push(Tree::Span(span));
106 }
107
108 #[cfg(feature = "uuid")]
109 pub(crate) fn uuid(&self) -> Uuid {
110 self.span.uuid()
111 }
112}
113
114#[derive(Clone, Debug)]
117pub struct ForestLayer<P, T> {
118 processor: P,
119 tag: T,
120}
121
122impl<P: Processor, T: TagParser> ForestLayer<P, T> {
123 pub fn new(processor: P, tag: T) -> Self {
125 ForestLayer { processor, tag }
126 }
127}
128
129impl<P: Processor> From<P> for ForestLayer<P, NoTag> {
130 fn from(processor: P) -> Self {
131 ForestLayer::new(processor, NoTag)
132 }
133}
134
135impl ForestLayer<Sink, NoTag> {
136 pub fn sink() -> Self {
138 ForestLayer::from(Sink)
139 }
140}
141
142impl Default for ForestLayer<PrettyPrinter, NoTag> {
143 fn default() -> Self {
144 ForestLayer {
145 processor: PrettyPrinter::new(),
146 tag: NoTag,
147 }
148 }
149}
150
151impl<P, T, S> Layer<S> for ForestLayer<P, T>
152where
153 P: Processor,
154 T: TagParser,
155 S: Subscriber + for<'a> LookupSpan<'a>,
156{
157 fn on_new_span(&self, attrs: &Attributes, id: &Id, ctx: Context<S>) {
158 let span = ctx.span(id).expect(fail::SPAN_NOT_IN_CONTEXT);
159 let opened = OpenedSpan::new(attrs, &ctx);
160
161 let mut extensions = span.extensions_mut();
162 extensions.insert(opened);
163 }
164
165 fn on_event(&self, event: &Event, ctx: Context<S>) {
166 struct Visitor {
167 message: Option<String>,
168 fields: FieldSet,
169 immediate: bool,
170 }
171
172 impl Visit for Visitor {
173 fn record_bool(&mut self, field: &Field, value: bool) {
174 match field.name() {
175 "immediate" => self.immediate |= value,
176 _ => self.record_debug(field, &value),
177 }
178 }
179
180 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
181 let value = format!("{:?}", value);
182 match field.name() {
183 "message" if self.message.is_none() => self.message = Some(value),
184 key => self.fields.push(tree::Field::new(key, value)),
185 }
186 }
187 }
188
189 let mut visitor = Visitor {
190 message: None,
191 fields: FieldSet::default(),
192 immediate: false,
193 };
194
195 event.record(&mut visitor);
196
197 let shared = tree::Shared {
198 #[cfg(feature = "uuid")]
199 uuid: Uuid::nil(),
200 #[cfg(feature = "chrono")]
201 timestamp: Utc::now(),
202 level: *event.metadata().level(),
203 fields: visitor.fields,
204 };
205
206 let tree_event = tree::Event {
207 shared,
208 message: visitor.message,
209 tag: self.tag.parse(event),
210 };
211
212 let current_span = ctx.event_span(event);
213
214 if visitor.immediate {
215 write_immediate(&tree_event, current_span.as_ref()).expect("writing urgent failed");
216 }
217
218 match current_span.as_ref() {
219 Some(parent) => parent
220 .extensions_mut()
221 .get_mut::<OpenedSpan>()
222 .expect(fail::OPENED_SPAN_NOT_IN_EXTENSIONS)
223 .record_event(tree_event),
224 None => self
225 .processor
226 .process(Tree::Event(tree_event))
227 .expect(fail::PROCESSING_ERROR),
228 }
229 }
230
231 fn on_enter(&self, id: &Id, ctx: Context<S>) {
232 ctx.span(id)
233 .expect(fail::SPAN_NOT_IN_CONTEXT)
234 .extensions_mut()
235 .get_mut::<OpenedSpan>()
236 .expect(fail::OPENED_SPAN_NOT_IN_EXTENSIONS)
237 .enter();
238 }
239
240 fn on_exit(&self, id: &Id, ctx: Context<S>) {
241 ctx.span(id)
242 .expect(fail::SPAN_NOT_IN_CONTEXT)
243 .extensions_mut()
244 .get_mut::<OpenedSpan>()
245 .expect(fail::OPENED_SPAN_NOT_IN_EXTENSIONS)
246 .exit();
247 }
248
249 fn on_close(&self, id: Id, ctx: Context<S>) {
250 let span_ref = ctx.span(&id).expect(fail::SPAN_NOT_IN_CONTEXT);
251
252 let mut span = span_ref
253 .extensions_mut()
254 .remove::<OpenedSpan>()
255 .expect(fail::OPENED_SPAN_NOT_IN_EXTENSIONS)
256 .close();
257
258 if span.total_duration < span.inner_duration {
266 span.total_duration = span.inner_duration;
267 }
268
269 match span_ref.parent() {
270 Some(parent) => parent
271 .extensions_mut()
272 .get_mut::<OpenedSpan>()
273 .expect(fail::OPENED_SPAN_NOT_IN_EXTENSIONS)
274 .record_span(span),
275 None => self
276 .processor
277 .process(Tree::Span(span))
278 .expect(fail::PROCESSING_ERROR),
279 }
280 }
281}
282
283fn write_immediate<S>(event: &tree::Event, current: Option<&SpanRef<S>>) -> io::Result<()>
284where
285 S: for<'a> LookupSpan<'a>,
286{
287 #[cfg(feature = "smallvec")]
289 let mut writer = smallvec::SmallVec::<[u8; 256]>::new();
290 #[cfg(not(feature = "smallvec"))]
291 let mut writer = Vec::with_capacity(256);
292
293 #[cfg(feature = "uuid")]
294 if let Some(span) = current {
295 let uuid = span
296 .extensions()
297 .get::<OpenedSpan>()
298 .expect(fail::OPENED_SPAN_NOT_IN_EXTENSIONS)
299 .span
300 .uuid();
301 write!(writer, "{} ", uuid)?;
302 }
303
304 #[cfg(feature = "chrono")]
305 write!(writer, "{} ", event.timestamp().to_rfc3339())?;
306
307 write!(writer, "{:<8} ", event.level())?;
308
309 let tag = event.tag().unwrap_or_else(|| Tag::from(event.level()));
310
311 write!(writer, "{icon} IMMEDIATE {icon} ", icon = tag.icon())?;
312
313 if let Some(span) = current {
314 for ancestor in span.scope().from_root() {
315 write!(writer, "{} > ", ancestor.name())?;
316 }
317 }
318
319 if let Some(message) = event.message() {
322 write!(writer, "{}", message)?;
323 }
324
325 for field in event.fields().iter() {
326 write!(writer, " | {}: {}", field.key(), field.value())?;
327 }
328
329 writeln!(writer)?;
330
331 io::stderr().write_all(&writer)
332}
333
334pub fn init() {
361 Registry::default().with(ForestLayer::default()).init();
362}
363
364pub fn test_init() -> Result<(), TryInitError> {
384 Registry::default()
385 .with(ForestLayer::new(TestCapturePrinter::new(), NoTag))
386 .try_init()
387}