@@ -21,6 +21,7 @@ use slog_term::{FullFormat as TextDrain, PlainDecorator, TermDecorator};
2121use std:: fs:: File ;
2222use std:: io;
2323use std:: io:: BufWriter ;
24+ use std:: os:: fd:: FromRawFd ;
2425use std:: panic:: RefUnwindSafe ;
2526use 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.
6570pub ( 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+
127136fn get_root_drain (
128137 _settings : & LoggingSettings ,
129138 base_drain : Arc < dyn SendSyncRefUnwindSafeDrain < Err = Never , Ok = ( ) > + ' static > ,
0 commit comments