/rust/registry/src/index.crates.io-6f17d22bba15001f/flexi_logger-0.27.4/src/util.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use crate::logger::ErrorChannel; |
2 | | use crate::{DeferredNow, FormatFunction}; |
3 | | use log::Record; |
4 | | use std::cell::RefCell; |
5 | | use std::io::Write; |
6 | | use std::path::Path; |
7 | | use std::sync::RwLock; |
8 | | |
9 | | #[cfg(test)] |
10 | | use std::io::Cursor; |
11 | | #[cfg(test)] |
12 | | use std::sync::{Arc, Mutex}; |
13 | | |
14 | | #[cfg(feature = "async")] |
15 | | pub(crate) const ASYNC_FLUSH: &[u8] = b"F"; |
16 | | #[cfg(feature = "async")] |
17 | | pub(crate) const ASYNC_SHUTDOWN: &[u8] = b"S"; |
18 | | |
19 | | #[derive(Copy, Clone, Debug)] |
20 | | pub(crate) enum ErrorCode { |
21 | | Write, |
22 | | Flush, |
23 | | Format, |
24 | | LogFile, |
25 | | #[cfg(feature = "specfile")] |
26 | | LogSpecFile, |
27 | | Poison, |
28 | | #[cfg(target_family = "unix")] |
29 | | Symlink, |
30 | | WriterSpec, |
31 | | } |
32 | | impl ErrorCode { |
33 | 0 | fn as_index(self) -> &'static str { |
34 | 0 | match self { |
35 | 0 | Self::Write => "write", |
36 | 0 | Self::Flush => "flush", |
37 | 0 | Self::Format => "format", |
38 | 0 | Self::LogFile => "logfile", |
39 | | #[cfg(feature = "specfile")] |
40 | | Self::LogSpecFile => "logspecfile", |
41 | 0 | Self::Poison => "poison", |
42 | | #[cfg(target_family = "unix")] |
43 | 0 | Self::Symlink => "symlink", |
44 | 0 | Self::WriterSpec => "writerspec", |
45 | | } |
46 | 0 | } |
47 | | } |
48 | | |
49 | 0 | pub(crate) fn eprint_err(error_code: ErrorCode, msg: &str, err: &dyn std::error::Error) { |
50 | 0 | let s = format!( |
51 | 0 | "[flexi_logger][ERRCODE::{code:?}] {msg}, caused by {err:?}\n \ |
52 | 0 | See https://docs.rs/flexi_logger/latest/flexi_logger/error_info/index.html#{code_lc}", |
53 | 0 | msg = msg, |
54 | 0 | err = err, |
55 | 0 | code = error_code, |
56 | 0 | code_lc = error_code.as_index(), |
57 | 0 | ); |
58 | 0 | try_to_write(&s); |
59 | 0 | } |
60 | | |
61 | 0 | pub(crate) fn eprint_msg(error_code: ErrorCode, msg: &str) { |
62 | 0 | let s = format!( |
63 | 0 | "[flexi_logger][ERRCODE::{code:?}] {msg}\n \ |
64 | 0 | See https://docs.rs/flexi_logger/latest/flexi_logger/error_info/index.html#{code_lc}", |
65 | 0 | msg = msg, |
66 | 0 | code = error_code, |
67 | 0 | code_lc = error_code.as_index(), |
68 | 0 | ); |
69 | 0 | try_to_write(&s); |
70 | 0 | } |
71 | | |
72 | | lazy_static::lazy_static! { |
73 | | pub(crate) static ref ERROR_CHANNEL: RwLock<ErrorChannel> = RwLock::new(ErrorChannel::default()); |
74 | | } |
75 | | |
76 | 0 | pub(crate) fn set_error_channel(channel: ErrorChannel) { |
77 | 0 | match ERROR_CHANNEL.write() { |
78 | 0 | Ok(mut guard) => { |
79 | 0 | *guard = channel; |
80 | 0 | } |
81 | 0 | Err(e) => { |
82 | 0 | eprint_err(ErrorCode::Poison, "Error channel cannot be set", &e); |
83 | 0 | } |
84 | | } |
85 | 0 | } |
86 | | |
87 | 0 | fn try_to_write(s: &str) { |
88 | 0 | match &*(ERROR_CHANNEL.read().unwrap()) { |
89 | 0 | ErrorChannel::StdErr => { |
90 | 0 | eprintln!("{s}"); |
91 | 0 | } |
92 | 0 | ErrorChannel::StdOut => { |
93 | 0 | println!("{s}"); |
94 | 0 | } |
95 | 0 | ErrorChannel::File(path) => try_to_write_to_file(s, path).unwrap_or_else(|e| { |
96 | 0 | eprintln!("{s}"); |
97 | 0 | eprintln!("Can't open error output file, caused by: {e}"); |
98 | 0 | }), |
99 | 0 | ErrorChannel::DevNull => {} |
100 | | } |
101 | 0 | } |
102 | | |
103 | 0 | fn try_to_write_to_file(s: &str, path: &Path) -> Result<(), std::io::Error> { |
104 | 0 | let mut file = std::fs::OpenOptions::new() |
105 | 0 | .create(true) |
106 | 0 | .append(true) |
107 | 0 | .open(path)?; |
108 | 0 | writeln!(file, "{s}")?; |
109 | 0 | file.flush() |
110 | 0 | } |
111 | | |
112 | 0 | pub(crate) fn io_err(s: &'static str) -> std::io::Error { |
113 | 0 | std::io::Error::new(std::io::ErrorKind::Other, s) |
114 | 0 | } |
115 | | |
116 | | // Thread-local buffer |
117 | 0 | pub(crate) fn buffer_with<F>(f: F) |
118 | 0 | where |
119 | 0 | F: FnOnce(&RefCell<Vec<u8>>), |
120 | 0 | { |
121 | 0 | thread_local! { |
122 | 0 | static BUFFER: RefCell<Vec<u8>> = RefCell::new(Vec::with_capacity(200)); |
123 | 0 | } |
124 | 0 | BUFFER.with(f); |
125 | 0 | } Unexecuted instantiation: flexi_logger::util::buffer_with::<flexi_logger::util::write_buffered::{closure#0}> Unexecuted instantiation: flexi_logger::util::buffer_with::<<flexi_logger::writers::file_log_writer::state_handle::StateHandle>::write::{closure#0}> |
126 | | |
127 | | // Use the thread-local buffer for formatting before writing into the given writer |
128 | 0 | pub(crate) fn write_buffered( |
129 | 0 | format_function: FormatFunction, |
130 | 0 | now: &mut DeferredNow, |
131 | 0 | record: &Record, |
132 | 0 | w: &mut dyn Write, |
133 | 0 | #[cfg(test)] o_validation_buffer: Option<&Arc<Mutex<Cursor<Vec<u8>>>>>, |
134 | 0 | ) -> Result<(), std::io::Error> { |
135 | 0 | let mut result: Result<(), std::io::Error> = Ok(()); |
136 | 0 |
|
137 | 0 | buffer_with(|tl_buf| match tl_buf.try_borrow_mut() { |
138 | 0 | Ok(mut buffer) => { |
139 | 0 | (format_function)(&mut *buffer, now, record) |
140 | 0 | .unwrap_or_else(|e| eprint_err(ErrorCode::Format, "formatting failed", &e)); |
141 | 0 | buffer |
142 | 0 | .write_all(b"\n") |
143 | 0 | .unwrap_or_else(|e| eprint_err(ErrorCode::Write, "writing failed", &e)); |
144 | 0 |
|
145 | 0 | result = w.write_all(&buffer).map_err(|e| { |
146 | 0 | eprint_err(ErrorCode::Write, "writing failed", &e); |
147 | 0 | e |
148 | 0 | }); |
149 | 0 |
|
150 | 0 | #[cfg(test)] |
151 | 0 | if let Some(valbuf) = o_validation_buffer { |
152 | 0 | valbuf.lock().unwrap().write_all(&buffer).ok(); |
153 | 0 | } |
154 | 0 | buffer.clear(); |
155 | 0 | } |
156 | 0 | Err(_e) => { |
157 | 0 | // We arrive here in the rare cases of recursive logging |
158 | 0 | // (e.g. log calls in Debug or Display implementations) |
159 | 0 | // we print the inner calls, in chronological order, before finally the |
160 | 0 | // outer most message is printed |
161 | 0 | let mut tmp_buf = Vec::<u8>::with_capacity(200); |
162 | 0 | (format_function)(&mut tmp_buf, now, record) |
163 | 0 | .unwrap_or_else(|e| eprint_err(ErrorCode::Format, "formatting failed", &e)); |
164 | 0 | tmp_buf |
165 | 0 | .write_all(b"\n") |
166 | 0 | .unwrap_or_else(|e| eprint_err(ErrorCode::Write, "writing failed", &e)); |
167 | 0 |
|
168 | 0 | result = w.write_all(&tmp_buf).map_err(|e| { |
169 | 0 | eprint_err(ErrorCode::Write, "writing failed", &e); |
170 | 0 | e |
171 | 0 | }); |
172 | 0 |
|
173 | 0 | #[cfg(test)] |
174 | 0 | if let Some(valbuf) = o_validation_buffer { |
175 | 0 | valbuf.lock().unwrap().write_all(&tmp_buf).ok(); |
176 | 0 | } |
177 | 0 | } |
178 | 0 | }); |
179 | 0 | result |
180 | 0 | } |