Geal / rust-syslog

Send syslog messages from Rust
MIT License
110 stars 55 forks source link

stream logs never get flushed #69

Closed Roguelazer closed 3 months ago

Roguelazer commented 2 years ago

Since #30, TcpStream and UdpStream use a BufWriter, which gets flushed in the flush() method in the Log trait impl. However, this method never actually is called in the normal use of the log crate (e.g., log!() and friends never call it). This means a program which logs less than one BufWriter worth of data (8KB) will never actually emit any of those messages, and the last few messages logged are always lost.

This can be easily demonstrated with the following program, which (if run on a system where /dev/log is a stream-mode domain socket) will never log anything:

fn main() {
    syslog::init_unix(syslog::Facility::LOG_USER, log::LevelFilter::Info);
    log::info!("test");
}

Explicitly calling flush does, of course, work:

fn main() {
    syslog::init_unix(syslog::Facility::LOG_USER, log::LevelFilter::Info);
    log::info!("test");
    log::logger().flush();
}

The following patch fixes this, at the cost of doing rather a lot more system calls under load:

diff --git a/src/lib.rs b/src/lib.rs
index 2971142..cb04df3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -175,6 +175,7 @@ impl Write for LoggerBackend {
                 socket
                     .write(&message[..])
                     .and_then(|sz| socket.write(&null).map(|_| sz))
+                    .and_then(|sz| socket.flush().map(|_| sz))
             }
             LoggerBackend::Udp(ref socket, ref addr) => socket.send_to(&message[..], addr),
             LoggerBackend::Tcp(ref mut socket) => socket.write(&message[..]),
@@ -198,6 +199,7 @@ impl Write for LoggerBackend {
                 socket
                     .write_fmt(args)
                     .and_then(|_| socket.write(&null).map(|_| ()))
+                    .and_then(|sz| socket.flush().map(|_| sz))
             }
             LoggerBackend::Udp(ref socket, ref addr) => {
                 let message = fmt::format(args);

Normally I run syslog in datagram mode, so I've never run into this before.

ghost commented 1 year ago

I ran into the same error when I tried using log macros over TCP. Messages were never sent. Changing to UDP solved the problem. If TCP is going to be a supported protocol, every message needs to be flushed or valuable data can be dropped. This issue is over a year old and needs to be addressed.

xenago commented 1 year ago

I concur and can reproduce this issue - UDP is working fine but not TCP.

usvyatsky commented 7 months ago

TCP is hardly useable without this fix.

facetious commented 5 months ago

@Geal The PR resolving this issue has been sitting open for a couple years. Can it get some direction on a path forward if it's not acceptable to merge?