Skip to main content

subscriber

Function subscriber 

Source
pub fn subscriber<W>(
    filter: EnvFilter,
    writer: W,
) -> impl Subscriber + Send + Sync + 'static
where W: for<'w> MakeWriter<'w> + Send + Sync + 'static,
Expand description

The subscriber init installs, writing to writer under filter.

It is the one place the log’s format is decided: no target, no colour, and every field redacted. init hands it stderr; a test hands it a file and reads back what was written.

use std::sync::{Arc, Mutex};
use majordomus_cli::logging;
use tracing_subscriber::EnvFilter;

let written = Arc::new(Mutex::new(Vec::new()));
let sink = written.clone();
let to_memory = move || Sink(sink.clone());
// assembled at run time, so that no committed file carries a credential's shape
let token = format!("{}{}", "ghp_", "a".repeat(24));
let log = logging::subscriber(EnvFilter::new("info"), to_memory);
tracing::subscriber::with_default(log, || {
    tracing::info!(token = token.as_str(), "pushing with {token}");
});
let text = String::from_utf8(written.lock().unwrap().clone()).unwrap();
assert!(!text.contains(&token), "{text}");
assert!(text.contains("pushing with [redacted:github-token]"), "{text}");
assert!(text.contains(r#"token="[redacted:github-token]""#), "{text}");

struct Sink(Arc<Mutex<Vec<u8>>>);
impl std::io::Write for Sink {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.0.lock().unwrap().extend_from_slice(buf);
        Ok(buf.len())
    }
    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}