Skip to main content

auths_telemetry/sinks/
stdout.rs

1//! Synchronous stdout telemetry sink.
2//!
3//! Writes newline-delimited JSON directly to a `Write` impl under a mutex.
4//! Blocking I/O here is intentional — telemetry writes are rare relative to
5//! application throughput. Callers that need non-blocking MPSC buffering
6//! should build a `TokioMpscSink` in their binary crate and pass it to
7//! `init_telemetry_with_sink`.
8
9use std::io::{BufWriter, Write};
10use std::sync::Mutex;
11
12use crate::ports::EventSink;
13
14/// Telemetry sink that writes newline-delimited JSON to any `Write` impl.
15///
16/// Thread-safe via `Mutex`. Suitable for stdout, files, or in-memory buffers.
17pub struct WriterSink<W: Write + Send> {
18    writer: Mutex<BufWriter<W>>,
19}
20
21impl<W: Write + Send> WriterSink<W> {
22    /// Create a sink wrapping `writer`.
23    pub fn new(writer: W) -> Self {
24        Self {
25            writer: Mutex::new(BufWriter::new(writer)),
26        }
27    }
28}
29
30/// Construct a `WriterSink` that writes to stdout.
31pub fn new_stdout_sink() -> WriterSink<std::io::Stdout> {
32    WriterSink::new(std::io::stdout())
33}
34
35impl<W: Write + Send + Sync + 'static> EventSink for WriterSink<W> {
36    fn emit(&self, payload: &str) {
37        if let Ok(mut w) = self.writer.lock() {
38            let _ = writeln!(w, "{payload}");
39            let _ = w.flush();
40        }
41    }
42
43    fn flush(&self) {
44        if let Ok(mut w) = self.writer.lock() {
45            let _ = w.flush();
46        }
47    }
48}