logforth_core/logger/
log_impl.rs1use std::io::Write;
16use std::sync::OnceLock;
17
18use crate::Append;
19use crate::Diagnostic;
20use crate::Error;
21use crate::Filter;
22use crate::filter::FilterResult;
23use crate::record::Metadata;
24use crate::record::Record;
25
26static DEFAULT_LOGGER: OnceLock<Logger> = OnceLock::new();
27
28pub fn default_logger() -> Option<&'static Logger> {
32 DEFAULT_LOGGER.get()
33}
34
35pub fn set_default_logger(logger: Logger) -> Result<(), Logger> {
40 DEFAULT_LOGGER.set(logger)
41}
42
43#[derive(Debug)]
45pub struct Logger {
46 dispatches: Vec<Dispatch>,
47}
48
49impl Logger {
50 pub(super) fn new(dispatches: Vec<Dispatch>) -> Self {
51 Self { dispatches }
52 }
53}
54
55impl Logger {
56 pub fn enabled(&self, metadata: &Metadata) -> bool {
58 self.dispatches
59 .iter()
60 .any(|dispatch| dispatch.enabled(metadata))
61 }
62
63 pub fn log(&self, record: &Record) {
65 for dispatch in &self.dispatches {
66 if let Err(err) = dispatch.log(record) {
67 handle_log_error(record, err);
68 }
69 }
70 }
71
72 pub fn flush(&self) {
74 for dispatch in &self.dispatches {
75 if let Err(err) = dispatch.flush() {
76 handle_flush_error(err);
77 }
78 }
79 }
80}
81
82#[derive(Debug)]
90pub(super) struct Dispatch {
91 filters: Vec<Box<dyn Filter>>,
92 diagnostics: Vec<Box<dyn Diagnostic>>,
93 appends: Vec<Box<dyn Append>>,
94}
95
96impl Dispatch {
97 pub(super) fn new(
98 filters: Vec<Box<dyn Filter>>,
99 diagnostics: Vec<Box<dyn Diagnostic>>,
100 appends: Vec<Box<dyn Append>>,
101 ) -> Self {
102 debug_assert!(
103 !appends.is_empty(),
104 "A Dispatch must have at least one filter"
105 );
106
107 Self {
108 filters,
109 diagnostics,
110 appends,
111 }
112 }
113
114 fn enabled(&self, metadata: &Metadata) -> bool {
115 let diagnostics = &self.diagnostics;
116
117 for filter in &self.filters {
118 match filter.enabled(metadata, diagnostics) {
119 FilterResult::Reject => return false,
120 FilterResult::Accept => return true,
121 FilterResult::Neutral => {}
122 }
123 }
124
125 true
126 }
127
128 fn log(&self, record: &Record) -> Result<(), Error> {
129 let diagnostics = &self.diagnostics;
130
131 for filter in &self.filters {
132 match filter.matches(record, diagnostics) {
133 FilterResult::Reject => return Ok(()),
134 FilterResult::Accept => break,
135 FilterResult::Neutral => {}
136 }
137 }
138
139 for append in &self.appends {
140 append.append(record, diagnostics)?;
141 }
142 Ok(())
143 }
144
145 fn flush(&self) -> Result<(), Error> {
146 for append in &self.appends {
147 append.flush()?;
148 }
149 Ok(())
150 }
151}
152
153fn handle_log_error(record: &Record, error: Error) {
154 let Err(fallback_error) = write!(
155 std::io::stderr(),
156 r###"
157Error perform logging.
158 Attempted to log: {args}
159 Record: {record:?}
160 Error: {error:?}
161"###,
162 args = record.args(),
163 record = record,
164 error = error,
165 ) else {
166 return;
167 };
168
169 panic!(
170 r###"
171Error performing stderr logging after error occurred during regular logging.
172 Attempted to log: {args}
173 Record: {record:?}
174 Error: {error:?}
175 Fallback error: {fallback_error}
176"###,
177 args = record.args(),
178 record = record,
179 error = error,
180 fallback_error = fallback_error,
181 );
182}
183
184fn handle_flush_error(error: Error) {
185 let Err(fallback_error) = write!(
186 std::io::stderr(),
187 r###"
188Error perform flush.
189 Error: {error:?}
190"###,
191 ) else {
192 return;
193 };
194
195 panic!(
196 r###"
197Error performing stderr logging after error occurred during regular flush.
198 Error: {error:?}
199 Fallback error: {fallback_error}
200"###,
201 );
202}