tracing_logstash/
format.rs1use crate::fields::TryForEachField;
2use crate::span_recorder::{DefaultSpanRecorder, SpanRecorder};
3use crate::DisplayLevelFilter;
4use serde::ser::{SerializeMap, SerializeSeq};
5use serde::{Serialize, Serializer};
6use std::collections::HashSet;
7use tracing_core::{Event, Subscriber};
8use tracing_subscriber::layer::Context;
9use tracing_subscriber::registry::{LookupSpan, SpanRef};
10
11pub trait FormatSpan {
12 fn format_span<S, Span>(&self, serializer: S, span: &SpanRef<Span>) -> Result<S::Ok, S::Error>
13 where
14 S: Serializer,
15 Span: Subscriber + for<'lookup> LookupSpan<'lookup>;
16}
17
18pub trait FormatEvent {
19 type R: SpanRecorder + Send + Sync;
20 fn span_recorder(&self) -> Self::R;
21 fn format_event<S: Serializer, SS: Subscriber + for<'a> LookupSpan<'a>>(
22 &self,
23 serializer: S,
24 event: &Event<'_>,
25 ctx: Context<'_, SS>,
26 ) -> Result<S::Ok, S::Error>;
27}
28
29#[derive(Default)]
30pub struct DefaultSpanFormat {
31 display_location: bool,
32 display_fields: bool,
33}
34
35impl DefaultSpanFormat {
36 pub fn with_location(self, display_location: bool) -> Self {
37 Self {
38 display_location,
39 ..self
40 }
41 }
42 pub fn with_fields(self, display_fields: bool) -> Self {
43 Self {
44 display_fields,
45 ..self
46 }
47 }
48}
49
50const RESERVED_SPAN_FIELDS: [&str; 5] = ["name", "target", "level", "file", "line"];
51
52impl FormatSpan for DefaultSpanFormat {
53 fn format_span<S, Span>(&self, serializer: S, span: &SpanRef<Span>) -> Result<S::Ok, S::Error>
54 where
55 S: Serializer,
56 Span: Subscriber + for<'lookup> LookupSpan<'lookup>,
57 {
58 let mut s = serializer.serialize_map(None)?;
59 let metadata = span.metadata();
60 s.serialize_entry("name", span.name())?;
61 s.serialize_entry("target", metadata.target())?;
62 s.serialize_entry("level", metadata.level().as_str())?;
63 if self.display_location {
64 if let Some(file) = metadata.file() {
65 s.serialize_entry("file", file)?;
66 }
67 if let Some(line) = metadata.line() {
68 s.serialize_entry("line", &line)?;
69 }
70 }
71 if self.display_fields {
72 if let Some(fields) = span.extensions().get::<DefaultSpanRecorder>() {
73 write_extension_fields(&mut HashSet::from(RESERVED_SPAN_FIELDS), &mut s, fields)?;
74 }
75 }
76 s.end()
77 }
78}
79
80pub(crate) fn write_extension_fields<S: SerializeMap, R: TryForEachField>(
81 seen: &mut HashSet<&str>,
82 serialize_map: &mut S,
83 recorded: &R,
84) -> Result<(), S::Error> {
85 recorded.try_for_each(|name, value| {
86 if !value.is_unset() && seen.insert(name) {
87 serialize_map.serialize_entry(name, value)?;
88 }
89 Ok(())
90 })?;
91 Ok(())
92}
93
94pub(crate) struct SerializableSpan<'fmt_span, 'span, FmtSpan, Span>(
95 pub &'fmt_span FmtSpan,
96 pub &'span SpanRef<'fmt_span, Span>,
97)
98where
99 Span: for<'lookup> LookupSpan<'lookup>;
100
101impl<'a, 'b, FmtSpan, Span> Serialize for SerializableSpan<'a, 'b, FmtSpan, Span>
102where
103 FmtSpan: FormatSpan,
104 Span: Subscriber + for<'lookup> LookupSpan<'lookup>,
105{
106 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
107 where
108 S: Serializer,
109 {
110 self.0.format_span(serializer, self.1)
111 }
112}
113
114pub(crate) struct SerializableSpanList<'a, FS, Span>(
115 pub(crate) &'a FS,
116 pub(crate) &'a Event<'a>,
117 pub(crate) &'a Context<'a, Span>,
118 pub(crate) DisplayLevelFilter,
119)
120where
121 Span: for<'lookup> LookupSpan<'lookup>;
122
123impl<'a, FS, SS> Serialize for SerializableSpanList<'a, FS, SS>
124where
125 FS: FormatSpan,
126 SS: Subscriber + for<'lookup> LookupSpan<'lookup>,
127{
128 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
129 where
130 S: Serializer,
131 {
132 let mut s = serializer.serialize_seq(None)?;
133 if let Some(scope) = self.2.event_scope(self.1) {
134 for span in scope {
135 if self.3.is_enabled(self.1, span.metadata().level()) {
136 s.serialize_element(&SerializableSpan(self.0, &span))?;
137 }
138 }
139 }
140 s.end()
141 }
142}