Coverage Report

Created: 2025-07-11 07:02

/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
}