Skip to content

Commit db0e13b

Browse files
committed
Fix endless loop if a single log message is bigger than buffer_writer's overall limit
1 parent a509420 commit db0e13b

File tree

4 files changed

+50
-38
lines changed

4 files changed

+50
-38
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this
66
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.30.1] - 2025-04-02
9+
10+
Fix endless loop if a single log message is bigger than `buffer_writer`'s overall limit.
11+
812
## [0.30.0] - 2025-04-01
913

1014
Added non-default feature 'buffer_writer', which adds an in-memory log target with limited size and FIFO-logic.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "flexi_logger"
3-
version = "0.30.0"
3+
version = "0.30.1"
44
authors = ["emabee <[email protected]>"]
55
categories = ["development-tools::debugging"]
66
description = """

src/logger.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ impl Logger {
233233
/// The buffer has a maximum size (counting the bytes of the buffered message Strings)
234234
/// and drops the oldest messages when needed to observe the limit.
235235
///
236+
/// Once filled, the buffer will always contain at least the latest message,
237+
/// even if this message is bigger than the limit.
238+
///
236239
/// The buffer content can be retrieved with [`LoggerHandle::update_snapshot`].
237240
///
238241
/// # Errors

src/writers/buffer_writer.rs

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::{
1212
time::Instant,
1313
};
1414

15-
/// Allows logging to a memory buffer with limited size.
15+
// Allows logging to a memory buffer with limited size.
1616
pub struct BufferWriter {
1717
state: Arc<Mutex<State>>,
1818
}
@@ -24,29 +24,6 @@ struct State {
2424
format: FormatFunction,
2525
}
2626

27-
/// Allows getting the current content of the memory buffer.
28-
#[derive(Clone)]
29-
pub struct Snapshot {
30-
/// The latest snapshot of the memory buffer.
31-
pub text: String,
32-
last_update: Instant,
33-
}
34-
impl Snapshot {
35-
/// Constructor.
36-
#[must_use]
37-
pub fn new() -> Self {
38-
Self {
39-
text: String::new(),
40-
last_update: Instant::now(),
41-
}
42-
}
43-
}
44-
impl Default for Snapshot {
45-
fn default() -> Self {
46-
Self::new()
47-
}
48-
}
49-
5027
impl BufferWriter {
5128
/// Create a new instance.
5229
pub fn new(max_size: usize, format: FormatFunction) -> Self {
@@ -61,7 +38,7 @@ impl BufferWriter {
6138
}
6239
}
6340

64-
fn lock_inner(&self) -> Result<std::sync::MutexGuard<'_, State>, std::io::Error> {
41+
fn lock_state(&self) -> Result<std::sync::MutexGuard<'_, State>, std::io::Error> {
6542
self.state
6643
.lock()
6744
.map_err(|e| std::io::Error::other(e.to_string()))
@@ -77,41 +54,46 @@ impl BufferWriter {
7754
///
7855
/// `FlexiLoggerError::Poison` if some mutex is poisoned.
7956
pub fn update_snapshot(&self, snapshot: &mut Snapshot) -> Result<bool, FlexiLoggerError> {
80-
let inner = self.lock_inner()?;
81-
if snapshot.last_update == inner.last_update {
57+
let state = self.lock_state()?;
58+
if snapshot.last_update == state.last_update {
8259
Ok(false)
8360
} else {
8461
snapshot.text.clear();
85-
for bufline in &inner.buffer {
62+
for bufline in &state.buffer {
8663
snapshot.text.push_str(bufline);
8764
snapshot.text.push('\n');
8865
}
89-
snapshot.last_update = inner.last_update;
66+
snapshot.last_update = state.last_update;
9067
Ok(true)
9168
}
9269
}
9370
}
9471
impl LogWriter for BufferWriter {
9572
fn write(&self, now: &mut DeferredNow, record: &Record) -> std::io::Result<()> {
96-
let mut inner = self.lock_inner()?;
73+
let mut state = self.lock_state()?;
9774

9875
let mut logline = Vec::<u8>::with_capacity(80);
99-
(inner.format)(&mut logline, now, record).inspect_err(|e| {
76+
(state.format)(&mut logline, now, record).inspect_err(|e| {
10077
eprint_err(ErrorCode::Format, "formatting failed", &e);
10178
})?;
10279

10380
if !logline.is_empty() {
104-
while inner.size + logline.len() > inner.max_size {
105-
if let Some(line) = inner.buffer.pop_front() {
106-
inner.size -= line.len();
81+
if logline.len() > state.max_size {
82+
state.buffer.clear();
83+
state.size = 0;
84+
} else {
85+
while state.size + logline.len() > state.max_size {
86+
if let Some(line) = state.buffer.pop_front() {
87+
state.size -= line.len();
88+
}
10789
}
10890
}
10991

110-
(inner)
92+
(state)
11193
.buffer
11294
.push_back(String::from_utf8_lossy(&logline).to_string());
113-
inner.size += logline.len();
114-
inner.last_update = Instant::now();
95+
state.size += logline.len();
96+
state.last_update = Instant::now();
11597
}
11698
Ok(())
11799
}
@@ -121,3 +103,26 @@ impl LogWriter for BufferWriter {
121103
Ok(())
122104
}
123105
}
106+
107+
/// Allows getting the current content of the memory buffer.
108+
#[derive(Clone)]
109+
pub struct Snapshot {
110+
/// The latest snapshot of the memory buffer.
111+
pub text: String,
112+
last_update: Instant,
113+
}
114+
impl Snapshot {
115+
/// Constructor.
116+
#[must_use]
117+
pub fn new() -> Self {
118+
Self {
119+
text: String::new(),
120+
last_update: Instant::now(),
121+
}
122+
}
123+
}
124+
impl Default for Snapshot {
125+
fn default() -> Self {
126+
Self::new()
127+
}
128+
}

0 commit comments

Comments
 (0)