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