flexi_logger/write_mode.rs
1use crate::ZERO_DURATION;
2use std::time::Duration;
3
4/// Default buffer capacity (8k), when buffering is used.
5pub const DEFAULT_BUFFER_CAPACITY: usize = 8 * 1024;
6
7/// Default flush interval (1s), when flushing is used.
8pub const DEFAULT_FLUSH_INTERVAL: Duration = Duration::from_secs(1);
9
10/// Default size of the message pool;
11/// a higher value could further reduce allocations during log file rotation and cleanup.
12#[cfg(feature = "async")]
13#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
14pub const DEFAULT_POOL_CAPA: usize = 50;
15
16/// Default capacity for the message buffers;
17/// a higher value reduces allocations when longer log lines are used.
18#[cfg(feature = "async")]
19#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
20pub const DEFAULT_MESSAGE_CAPA: usize = 200;
21
22/// Describes whether the log output should be written synchronously or asynchronously,
23/// and if and how I/O should be buffered and flushed.
24///
25/// Is used in [`Logger::write_mode`](struct.Logger.html#method.write_mode).
26///
27/// Buffering reduces the program's I/O overhead, and thus increases overall performance,
28/// which can become relevant if logging is used heavily.
29/// On the other hand, if logging is used with low frequency,
30/// buffering can defer the appearance of log lines significantly,
31/// so regular flushing is usually advisable with buffering.
32///
33/// **Note** that for all options except `Direct` you should keep the
34/// [`LoggerHandle`](struct.LoggerHandle.html) alive
35/// up to the very end of your program to ensure that all buffered log lines are flushed out
36/// (which happens automatically when the [`LoggerHandle`](struct.LoggerHandle.html) is dropped)
37/// before the program terminates.
38/// [See here for an example](code_examples/index.html#choose-the-write-mode).
39///
40/// **Note** further that flushing uses an extra thread (with minimal stack).
41///
42/// The console is a slow output device (at least on Windows).
43/// With `WriteMode::Async` it can happen that in phases with vast log output
44/// the log lines appear significantly later than they were written.
45/// Also, a final printing phase is possible at the end of the program when the logger handle
46/// is dropped (and all output is flushed automatically).
47///
48/// `WriteMode::Direct` (i.e. without buffering) is the slowest option with all output devices,
49/// showing that buffered I/O pays off.
50///
51/// Using `log_to_stdout()` and then redirecting the output to a file can make things faster,
52/// likely because the operating system's adds buffering,
53/// but is still significantly slower than writing to files directly.
54///
55#[derive(Copy, Clone, Debug, Eq, PartialEq)]
56pub enum WriteMode {
57 /// Do not buffer (default).
58 ///
59 /// Every log line is directly written to the output, without buffering.
60 /// This allows seeing new log lines in real time, and does not need additional threads.
61 Direct,
62
63 /// Do not buffer and support `cargo test`'s capture.
64 ///
65 /// Much like `Direct`, just a bit slower, and allows
66 /// `cargo test` to capture log output and print it only for failing tests.
67 SupportCapture,
68
69 /// Same as `BufferAndFlushWith` with default capacity ([`DEFAULT_BUFFER_CAPACITY`])
70 /// and default interval ([`DEFAULT_FLUSH_INTERVAL`]).
71 BufferAndFlush,
72
73 /// Buffer and flush with given buffer capacity and flush interval.
74 BufferAndFlushWith(
75 /// Buffer capacity.
76 usize,
77 /// Flush interval.
78 Duration,
79 ),
80
81 /// Same as `BufferDontFlushWith` with default capacity ([`DEFAULT_BUFFER_CAPACITY`]).
82 BufferDontFlush,
83
84 /// Buffer with given buffer capacity, but don't flush.
85 ///
86 /// This might be handy if you want to minimize I/O effort and don't want to create
87 /// the extra thread for flushing and don't care if log lines appear with delay.
88 BufferDontFlushWith(
89 /// Buffer capacity.
90 usize,
91 ),
92
93 /// Same as `AsyncWith`, using default values for all parameters.
94 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
95 #[cfg(feature = "async")]
96 Async,
97
98 /// Log lines are sent through an unbounded channel to an output thread, which
99 /// does the I/O, and, if `log_to_file()` is chosen, also the rotation and the cleanup.
100 ///
101 /// Uses buffered output to reduce overhead, and a bounded message pool to reduce allocations.
102 /// The log output is flushed regularly with the given interval.
103 ///
104 /// See [here](code_examples/index.html#choose-the-write-mode) for an example.
105 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
106 #[cfg(feature = "async")]
107 AsyncWith {
108 /// Capacity of the pool for the message buffers.
109 pool_capa: usize,
110 /// Capacity of an individual message buffer.
111 message_capa: usize,
112 /// The interval for flushing the output.
113 ///
114 /// With `Duration::ZERO` flushing is suppressed.
115 flush_interval: Duration,
116 },
117}
118impl WriteMode {
119 pub(crate) fn effective_write_mode(&self) -> EffectiveWriteMode {
120 match *self {
121 Self::Direct | Self::SupportCapture => EffectiveWriteMode::Direct,
122 Self::BufferDontFlush => {
123 EffectiveWriteMode::BufferDontFlushWith(DEFAULT_BUFFER_CAPACITY)
124 }
125 Self::BufferDontFlushWith(duration) => {
126 EffectiveWriteMode::BufferDontFlushWith(duration)
127 }
128 Self::BufferAndFlush => EffectiveWriteMode::BufferAndFlushWith(DEFAULT_BUFFER_CAPACITY),
129 Self::BufferAndFlushWith(bufsize, _duration) => {
130 EffectiveWriteMode::BufferAndFlushWith(bufsize)
131 }
132 #[cfg(feature = "async")]
133 Self::Async => EffectiveWriteMode::AsyncWith {
134 pool_capa: DEFAULT_POOL_CAPA,
135 message_capa: DEFAULT_MESSAGE_CAPA,
136 flush_interval: DEFAULT_FLUSH_INTERVAL,
137 },
138 #[cfg(feature = "async")]
139 Self::AsyncWith {
140 pool_capa,
141 message_capa,
142 flush_interval,
143 } => EffectiveWriteMode::AsyncWith {
144 pool_capa,
145 message_capa,
146 flush_interval,
147 },
148 }
149 }
150 pub(crate) fn without_flushing(&self) -> WriteMode {
151 match self {
152 Self::Direct
153 | Self::SupportCapture
154 | Self::BufferDontFlush
155 | Self::BufferDontFlushWith(_) => *self,
156 Self::BufferAndFlush => Self::BufferDontFlush,
157 Self::BufferAndFlushWith(bufsize, _) => Self::BufferDontFlushWith(*bufsize),
158 #[cfg(feature = "async")]
159 Self::Async => Self::AsyncWith {
160 pool_capa: DEFAULT_POOL_CAPA,
161 message_capa: DEFAULT_MESSAGE_CAPA,
162 flush_interval: ZERO_DURATION,
163 },
164 #[cfg(feature = "async")]
165 Self::AsyncWith {
166 pool_capa,
167 message_capa,
168 flush_interval: _,
169 } => Self::AsyncWith {
170 pool_capa: *pool_capa,
171 message_capa: *message_capa,
172 flush_interval: ZERO_DURATION,
173 },
174 }
175 }
176 pub(crate) fn buffersize(&self) -> Option<usize> {
177 match self.effective_write_mode() {
178 EffectiveWriteMode::Direct => None,
179 EffectiveWriteMode::BufferAndFlushWith(bufsize)
180 | EffectiveWriteMode::BufferDontFlushWith(bufsize) => Some(bufsize),
181 #[cfg(feature = "async")]
182 EffectiveWriteMode::AsyncWith {
183 pool_capa: _,
184 message_capa: _,
185 flush_interval: _,
186 } => None,
187 }
188 }
189 pub(crate) fn get_flush_interval(&self) -> Duration {
190 match self {
191 Self::Direct
192 | Self::SupportCapture
193 | Self::BufferDontFlush
194 | Self::BufferDontFlushWith(_) => ZERO_DURATION,
195 Self::BufferAndFlush => DEFAULT_FLUSH_INTERVAL,
196 #[cfg(feature = "async")]
197 Self::Async => DEFAULT_FLUSH_INTERVAL,
198 Self::BufferAndFlushWith(_, flush_interval) => *flush_interval,
199 #[cfg(feature = "async")]
200 Self::AsyncWith {
201 pool_capa: _,
202 message_capa: _,
203 flush_interval,
204 } => *flush_interval,
205 }
206 }
207}
208
209pub(crate) enum EffectiveWriteMode {
210 Direct,
211 BufferAndFlushWith(usize),
212 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
213 #[cfg(feature = "async")]
214 AsyncWith {
215 /// Capacity of the pool for the message buffers.
216 pool_capa: usize,
217 /// Capacity of an individual message buffer.
218 message_capa: usize,
219 /// The interval for flushing the output.
220 ///
221 /// With `Duration::ZERO` flushing is suppressed.
222 flush_interval: Duration,
223 },
224 BufferDontFlushWith(usize),
225}