santh-tracing 0.2.0

Consistent tracing setup for CLI tools - stderr/JSON/file sinks, a secret-redacting writer, and operation spans
Documentation
//! Gap: the default file sink does not redact secrets. Redaction is opt-in via
//! [`RedactingWriter`]; a tool that configures `file_sink` without wrapping the
//! writer writes secrets to its log in the clear. The safe-by-default behavior
//! would be for the configured sink to redact unconditionally, so no tool can
//! leak a secret to its own logs by forgetting to wrap the writer.
//!
//! This test encodes that desired behavior and is `#[ignore]`d until the
//! default sink redacts. When that lands, drop the `#[ignore]` and this turns
//! green. Tracking: default-sink redaction (see CHANGELOG).

use santh_tracing::{InitConfig, LogLevel};

#[test]
#[ignore = "default sink does not yet redact; redaction is opt-in via RedactingWriter. Tracking: default-sink redaction"]
fn default_file_sink_redacts_secrets() {
    let dir = std::env::temp_dir().join("santh_tracing_gap_default_redaction");
    std::fs::create_dir_all(&dir).expect("create temp dir");
    let log = dir.join("gap.log");
    let _ = std::fs::remove_file(&log);

    let _guard = InitConfig::new("gap_tool", LogLevel::Info)
        .file_sink(&log)
        .expect("open log file")
        .init();

    santh_tracing::tracing::info!(
        "leaked token=ghp_0123456789abcdefghijklmnopqrstuvwxyzABCD"
    );

    let contents = std::fs::read_to_string(&log).unwrap_or_default();
    // DESIRED (not yet true): the secret never reaches the sink in the clear.
    assert!(
        !contents.contains("ghp_0123456789"),
        "secret leaked to default sink: {contents}"
    );
    assert!(
        contents.contains("[REDACTED]"),
        "expected redaction marker in sink output: {contents}"
    );
}