-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Labels
enhancementNew feature or requestNew feature or request
Description
Overview
The FileHandler currently re-opens the log file on each flush, resulting in unnecessary syscalls and potential contention. This issue proposes mirroring the JsonHandler implementation by keeping a Mutex<BufWriter<File>> open for the lifetime of the handler, writing and flushing without reopening.
Current State
The FileHandler reopens the log file on every flush:
// crates/lambda-rs-logging/src/handler.rs:71-79
let mut file = OpenOptions::new()
.append(true)
.create(true)
.open(self.file.clone()) // Reopened on every flush
.unwrap();
file
.write_all(log_message.as_bytes())
.expect("Unable to write data");
This results in:
- Repeated
open()syscalls on every log flush - Potential file descriptor exhaustion under heavy logging
- Contention when multiple threads attempt to log simultaneously
- Unnecessary overhead compared to keeping a persistent file handle
In contrast, JsonHandler already maintains a persistent file handle wrapped in Mutex<BufWriter<File>>, demonstrating the preferred pattern.
Scope
Goals:
- Refactor
FileHandlerto keep the log file open for the handler's lifetime - Use
Mutex<BufWriter<File>>pattern consistent withJsonHandler - Reduce syscall overhead and improve logging throughput
- Maintain thread-safety for concurrent logging
Non-Goals:
- Log rotation (separate concern, can be built on top of this)
- Async file I/O
- Changing the public
FileHandlerAPI
Proposed API
No public API changes required. The refactoring is internal to FileHandler:
// crates/lambda-rs-logging/src/handler.rs
use std::fs::{File, OpenOptions};
use std::io::{BufWriter, Write};
use std::sync::Mutex;
pub struct FileHandler {
/// Persistent buffered file handle
writer: Mutex<BufWriter<File>>,
// ... other fields
}
impl FileHandler {
pub fn new(path: impl AsRef<Path>) -> std::io::Result<Self> {
let file = OpenOptions::new()
.create(true)
.append(true)
.open(path)?;
Ok(Self {
writer: Mutex::new(BufWriter::new(file)),
})
}
}
impl Handler for FileHandler {
fn handle(&self, record: &Record) {
let formatted = self.format(record);
if let Ok(mut writer) = self.writer.lock() {
let _ = writeln!(writer, "{}", formatted);
// Flush can be deferred or done periodically for better performance
}
}
fn flush(&self) {
if let Ok(mut writer) = self.writer.lock() {
let _ = writer.flush();
}
}
}
Acceptance Criteria
-
FileHandlerstores aMutex<BufWriter<File>>instead of reopening on each flush - File is opened once during
FileHandlerconstruction -
handle()method writes to the buffered writer without reopening -
flush()method flushes the buffered writer without reopening - Thread-safety maintained via
Mutex - Existing tests pass without modification
- Error handling for file operations is preserved or improved
Affected Crates
lambda-rs-logging
Notes
- Consider whether
flush()should be called after everyhandle()or batched for better performance - File handle will be held for the lifetime of the handler; document that log rotation requires handler recreation
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request