provide_telemetry/
logger.rs1use std::collections::BTreeMap;
7use std::sync::{Arc, LazyLock, Mutex, OnceLock};
8
9use serde_json::Value;
10
11use crate::context::get_context;
12use crate::tracer::get_trace_context;
13
14const MAX_FALLBACK_EVENTS: usize = 1000;
15
16#[derive(Clone, Debug, PartialEq)]
17pub struct LogEvent {
18 pub level: String,
19 pub target: String,
20 pub message: String,
21 pub context: BTreeMap<String, Value>,
22 pub trace_id: Option<String>,
23 pub span_id: Option<String>,
24}
25
26#[derive(Clone, Debug, PartialEq, Eq)]
27pub struct Logger {
28 target: String,
29}
30
31#[derive(Clone, Debug, PartialEq, Eq)]
32pub struct NullLogger {
33 target: String,
34}
35
36#[derive(Clone, Debug)]
37pub struct BufferLogger {
38 target: String,
39 events: Arc<Mutex<Vec<LogEvent>>>,
40}
41
42static EVENTS: OnceLock<Mutex<Vec<LogEvent>>> = OnceLock::new();
43
44fn events() -> &'static Mutex<Vec<LogEvent>> {
45 EVENTS.get_or_init(|| Mutex::new(Vec::new()))
46}
47
48pub static logger: LazyLock<Logger> = LazyLock::new(|| Logger::new(None));
49
50fn new_event(target: &str, level: &str, message: &str) -> LogEvent {
51 let trace = get_trace_context();
52 LogEvent {
53 level: level.to_string(),
54 target: target.to_string(),
55 message: message.to_string(),
56 context: get_context(),
57 trace_id: trace.get("trace_id").and_then(Clone::clone),
58 span_id: trace.get("span_id").and_then(Clone::clone),
59 }
60}
61
62impl Logger {
63 pub fn new(target: Option<&str>) -> Self {
64 Self {
65 target: target.unwrap_or("provide.telemetry").to_string(),
66 }
67 }
68
69 pub fn target(&self) -> &str {
70 &self.target
71 }
72
73 pub fn debug(&self, message: &str) {
74 self.log("DEBUG", message);
75 }
76
77 pub fn info(&self, message: &str) {
78 self.log("INFO", message);
79 }
80
81 pub fn warn(&self, message: &str) {
82 self.log("WARN", message);
83 }
84
85 pub fn error(&self, message: &str) {
86 self.log("ERROR", message);
87 }
88
89 pub fn log(&self, level: &str, message: &str) {
90 let event = new_event(&self.target, level, message);
91 let mut buf = events().lock().expect("logger event lock poisoned");
92 if buf.len() < MAX_FALLBACK_EVENTS {
93 buf.push(event);
94 }
95 }
96
97 pub fn drain_events_for_tests() -> Vec<LogEvent> {
98 std::mem::take(&mut *events().lock().expect("logger event lock poisoned"))
99 }
100}
101
102impl NullLogger {
103 pub fn new(target: Option<&str>) -> Self {
104 Self {
105 target: target.unwrap_or("provide.telemetry").to_string(),
106 }
107 }
108
109 pub fn target(&self) -> &str {
110 &self.target
111 }
112
113 pub fn debug(&self, _message: &str) {}
114
115 pub fn info(&self, _message: &str) {}
116
117 pub fn warn(&self, _message: &str) {}
118
119 pub fn error(&self, _message: &str) {}
120}
121
122impl BufferLogger {
123 pub fn new(target: Option<&str>) -> Self {
124 Self {
125 target: target.unwrap_or("provide.telemetry").to_string(),
126 events: Arc::new(Mutex::new(Vec::new())),
127 }
128 }
129
130 pub fn target(&self) -> &str {
131 &self.target
132 }
133
134 pub fn debug(&self, message: &str) {
135 self.log("DEBUG", message);
136 }
137
138 pub fn info(&self, message: &str) {
139 self.log("INFO", message);
140 }
141
142 pub fn warn(&self, message: &str) {
143 self.log("WARN", message);
144 }
145
146 pub fn error(&self, message: &str) {
147 self.log("ERROR", message);
148 }
149
150 pub fn log(&self, level: &str, message: &str) {
151 self.events
152 .lock()
153 .expect("buffer logger event lock poisoned")
154 .push(new_event(&self.target, level, message));
155 }
156
157 pub fn drain(&self) -> Vec<LogEvent> {
158 std::mem::take(
159 &mut *self
160 .events
161 .lock()
162 .expect("buffer logger event lock poisoned"),
163 )
164 }
165}
166
167pub fn get_logger(name: Option<&str>) -> Logger {
168 Logger::new(name)
169}
170
171pub fn null_logger(name: Option<&str>) -> NullLogger {
172 NullLogger::new(name)
173}
174
175pub fn buffer_logger(name: Option<&str>) -> BufferLogger {
176 BufferLogger::new(name)
177}