tracing_systemd/
systemd_layer.rs

1use std::collections::BTreeMap;
2
3/// Contains the FieldStorage struct and the SystemdVisitor struct
4mod helper_structs;
5
6mod impls;
7
8use crate::formatting::*;
9
10use helper_structs::*;
11#[cfg(feature = "sd-journal")]
12use sd_journal::*;
13
14///A configurable tracing-subscriber layer compatible with journald.
15///
16///The layer used to format and log events. Can be configured to log to stdout, or directly to journald using the `sd-journal` feature.
17///```rust  
18///let systemd_layer = SystemdLayer::new()
19///    .with_target(true)
20///    .use_level_prefix(false)
21///    .use_color(true);
22///```
23pub struct SystemdLayer {
24    #[cfg(feature = "colored")]
25    use_color: bool,
26
27    log_thread_id: bool,
28    span_separator: &'static str,
29    message_separator: &'static str,
30    level_separator: &'static str,
31    log_target: bool,
32    #[cfg(feature = "sd-journal")]
33    use_sd_journal: bool,
34    function_bracket_left: &'static str,
35    function_bracket_right: &'static str,
36    arguments_equality: &'static str,
37    arguments_separator: &'static str,
38    use_level_prefix: bool,
39    thread_id_prefix: &'static str,
40    thread_id_suffix: &'static str,
41}
42
43// Implementation of the Layer trait
44impl<S> tracing_subscriber::Layer<S> for SystemdLayer
45where
46    S: tracing::Subscriber,
47    S: for<'a> tracing_subscriber::registry::LookupSpan<'a>,
48{
49    fn on_event(&self, event: &tracing::Event<'_>, ctx: tracing_subscriber::layer::Context<'_, S>) {
50        let scope = ctx.event_scope(event).unwrap();
51        let mut spans = vec![];
52
53        for span in scope.from_root() {
54            let extensions = span.extensions();
55            let storage = extensions.get::<SystemdFieldStorage>().unwrap();
56            let data = &storage.0;
57            spans.push(serde_json::json!({
58                "target": event.metadata().target(),
59                "name": span.name(),
60                "level": event.metadata().level().to_string(),
61                "fields": data,
62            }));
63        }
64
65        let mut fields = BTreeMap::new();
66        let mut visitor = SystemdVisitor(&mut fields);
67        event.record(&mut visitor);
68
69        let output = serde_json::json!({
70            "target": event.metadata().target(),
71            "name": event.metadata().name(),
72            "level": event.metadata().level().to_string(),
73            "fields": fields,
74            "spans": spans,
75        });
76
77        let full_string = self.build_full_string(&output);
78
79        #[cfg(feature = "sd-journal")]
80        {
81            match self.get_use_sd_journal() {
82                true => {
83                    let level = journal_level_from_tracing_level(event.metadata().level());
84                    Journal::log_message(level, full_string).unwrap();
85                }
86
87                false => match self.get_use_level_prefix() {
88                    true => {
89                        let prefix = prefix_from_tracing_level(event.metadata().level());
90                        println!("{}{}", prefix, full_string);
91                    }
92                    false => {
93                        println!("{}", full_string);
94                    }
95                },
96            }
97        }
98
99        #[cfg(not(feature = "sd-journal"))]
100        {
101            match self.get_use_level_prefix() {
102                true => {
103                    let prefix = prefix_from_tracing_level(event.metadata().level());
104                    println!("{}{}", prefix, full_string)
105                }
106                false => {
107                    println!("{}", full_string);
108                }
109            }
110
111            println!("{}", full_string);
112        }
113    }
114
115    fn on_new_span(
116        &self,
117        attrs: &tracing::span::Attributes,
118        id: &tracing::span::Id,
119        ctx: tracing_subscriber::layer::Context<'_, S>,
120    ) {
121        let mut fields = BTreeMap::new();
122        let mut visitor = SystemdVisitor(&mut fields);
123        attrs.record(&mut visitor);
124
125        let storage = SystemdFieldStorage(fields);
126        let span = ctx.span(id).unwrap();
127        let mut extensions = span.extensions_mut();
128        extensions.insert(storage);
129    }
130}