ski/trace.rs
1//! Opt-in stderr diagnostics for the fail-open hot paths.
2//!
3//! `hook`/`observe`/`session-start` swallow every error by design (README:
4//! "fail-open everywhere") so a ranking problem never blocks a prompt. That
5//! contract has a cost: when injection silently stops, there is normally
6//! nothing to debug with — the hook just goes quiet forever with no trace of
7//! why. [`debug`] prints the swallowed error to stderr, but only when
8//! `SKI_DEBUG` is set, so the default (quiet) behavior is unchanged and a
9//! user who suspects something is wrong has a way to find out what.
10
11/// Whether `SKI_DEBUG` is set (any value, including empty).
12pub fn enabled() -> bool {
13 std::env::var_os("SKI_DEBUG").is_some()
14}
15
16/// Print `ski: {context}: {err}` to stderr iff `SKI_DEBUG` is set. No-op
17/// otherwise. `context` should read as a fragment ("hook decide failed").
18pub fn debug(context: &str, err: &impl std::fmt::Display) {
19 if enabled() {
20 eprintln!("ski: {context}: {err}");
21 }
22}
23
24#[cfg(test)]
25mod tests {
26 use super::*;
27
28 #[test]
29 fn enabled_reflects_env_var() {
30 // SKI_DEBUG is read at call time with no caching, so tests can toggle
31 // it freely — but other tests run in the same process may also read/
32 // write it, so only assert the presence check itself is correct given
33 // an explicit value, not the ambient default.
34 std::env::set_var("SKI_DEBUG", "1");
35 assert!(enabled());
36 std::env::remove_var("SKI_DEBUG");
37 assert!(!enabled());
38 }
39}