Skip to content

Commit 251d193

Browse files
aberglund-cfinikulin
authored andcommitted
Use BufWriter wrapped fd 1 instead of line buffered io::Stdout for Terminal+JSON. This helps avoid unnecessary flushing.
1 parent 8d78ffc commit 251d193

File tree

1 file changed

+17
-8
lines changed
  • foundations/src/telemetry/log

1 file changed

+17
-8
lines changed

foundations/src/telemetry/log/init.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use slog_term::{FullFormat as TextDrain, PlainDecorator, TermDecorator};
2121
use std::fs::File;
2222
use std::io;
2323
use std::io::BufWriter;
24+
use std::os::fd::FromRawFd;
2425
use std::panic::RefUnwindSafe;
2526
use std::sync::Arc;
2627

@@ -61,6 +62,10 @@ impl LogHarness {
6162
}
6263
}
6364

65+
// Buffer output up to 4KiB. For JSON output, flush will be called for each record,
66+
// even if the buffer isn't full.
67+
const BUF_SIZE: usize = 4096;
68+
6469
// NOTE: Does nothing if logging has already been initialized in this process.
6570
pub(crate) fn init(service_info: &ServiceInfo, settings: &LoggingSettings) -> BootstrapResult<()> {
6671
// Already initialized
@@ -71,20 +76,16 @@ pub(crate) fn init(service_info: &ServiceInfo, settings: &LoggingSettings) -> Bo
7176
// NOTE: OXY-178, default is 128 (https://docs.rs/slog-async/2.7.0/src/slog_async/lib.rs.html#251)
7277
const CHANNEL_SIZE: usize = 1024;
7378

74-
// buffer json log lines up to 4kb characters. `set_flush` is enabled on the `JsonDrain` below
75-
// so messages less than 4k will still be written even if the buffer isn't full.
76-
const BUF_SIZE: usize = 4096;
77-
78-
let base_drain = match (&settings.output, &settings.format) {
79+
let async_drain = match (&settings.output, &settings.format) {
7980
(LogOutput::Terminal, LogFormat::Text) => {
8081
let drain = TextDrain::new(TermDecorator::new().stdout().build())
8182
.build()
8283
.fuse();
8384
AsyncDrain::new(drain).chan_size(CHANNEL_SIZE).build()
8485
}
8586
(LogOutput::Terminal, LogFormat::Json) => {
86-
let buf = BufWriter::with_capacity(BUF_SIZE, io::stdout());
87-
let drain = build_json_log_drain(buf);
87+
let stdout_writer = stdout_writer_without_line_buffering();
88+
let drain = build_json_log_drain(stdout_writer);
8889
AsyncDrain::new(drain).chan_size(CHANNEL_SIZE).build()
8990
}
9091
(LogOutput::File(file), LogFormat::Text) => {
@@ -100,7 +101,7 @@ pub(crate) fn init(service_info: &ServiceInfo, settings: &LoggingSettings) -> Bo
100101
}
101102
};
102103

103-
let root_drain = get_root_drain(settings, Arc::new(base_drain.fuse()));
104+
let root_drain = get_root_drain(settings, Arc::new(async_drain.fuse()));
104105
let root_kv = slog::o!(
105106
"module" => FnValue(|record| {
106107
format!("{}:{}", record.module(), record.line())
@@ -124,6 +125,14 @@ pub(crate) fn init(service_info: &ServiceInfo, settings: &LoggingSettings) -> Bo
124125
Ok(())
125126
}
126127

128+
/// Opens fd 1 directly and wraps with a [`BufWriter`] with [`BUF_SIZE`] capacity.
129+
///
130+
/// [`io::Stdout`] uses a [`io::LineWriter`] which may cause unnecessary flushing.
131+
fn stdout_writer_without_line_buffering() -> BufWriter<File> {
132+
let stdout = unsafe { File::from_raw_fd(1) };
133+
BufWriter::with_capacity(BUF_SIZE, stdout)
134+
}
135+
127136
fn get_root_drain(
128137
_settings: &LoggingSettings,
129138
base_drain: Arc<dyn SendSyncRefUnwindSafeDrain<Err = Never, Ok = ()> + 'static>,

0 commit comments

Comments
 (0)