diff options
Diffstat (limited to 'src/debug_log.zig')
| -rw-r--r-- | src/debug_log.zig | 41 |
1 files changed, 19 insertions, 22 deletions
diff --git a/src/debug_log.zig b/src/debug_log.zig index 0adbe63..84a2ac8 100644 --- a/src/debug_log.zig +++ b/src/debug_log.zig @@ -1,18 +1,17 @@ -//! Debug-build log redirection. +//! Optional log redirection. //! -//! Debug builds emit a *lot* of `std.log.debug` traffic — most usefully the -//! raw JSON of every provider API request and response. Writing that to stderr -//! makes the interactive TUI unusable (every line scribbles over the frame). +//! `PANTO_DEBUG != 0` captures `std.log` traffic — most usefully the raw JSON +//! of every provider API request and response — to a per-session file. Writing +//! that to stderr makes the interactive TUI unusable. //! //! This module installs a custom `std.Options.logFn` (wired up via -//! `std_options` in `main.zig`). In **Debug** builds it routes the entire log -//! stream to a per-session file under +//! `std_options` in `main.zig`). When enabled it routes the entire log stream +//! to a per-session file under //! -//! ($PANTO_HOME | $XDG_DATA_HOME/panto | ~/.local/share/panto)/debug/<session-id>.log +//! ($XDG_DATA_HOME/panto | ~/.local/share/panto)/debug/<session-id>.log //! -//! and writes *nothing* to the terminal, leaving the TUI pristine. In any -//! other build mode it delegates to `std.log.defaultLog` (stderr, level-gated) -//! so release behavior is unchanged. +//! and writes nothing to the terminal. Otherwise it delegates to +//! `std.log.defaultLog`. //! //! The file is opened with `O_TRUNC`, so each session starts fresh; the file //! holds exactly one session's logs and never grows across runs. (A *new* @@ -26,19 +25,16 @@ //! approach already used by `tui_terminal.zig`. const std = @import("std"); -const builtin = @import("builtin"); const Io = std.Io; const Allocator = std.mem.Allocator; const panto_home = @import("panto_home.zig"); -/// True only in Debug builds; gates the file-redirect path at comptime. -const enabled = builtin.mode == .Debug; - /// A tiny atomic spinlock serializing writes. `logFn` can be called from any /// thread but has no `Io` handle, so `Io.Mutex` (which needs one) is out; /// contention is rare and each critical section is a single bounded write. var log_lock = std.atomic.Value(bool).init(false); +var capture_enabled = std.atomic.Value(bool).init(false); fn lockLog() void { while (log_lock.cmpxchgWeak(false, true, .acquire, .monotonic) != null) { @@ -58,19 +54,19 @@ var seq: u64 = 0; /// Buffer backing the per-call `Writer`. Guarded by `log_mutex`. var writer_buf: [16 * 1024]u8 = undefined; -/// Open the per-session debug log file and arm `logFn` to write to it. No-op -/// in non-Debug builds. Best-effort: any failure leaves `log_fd == -1`, and -/// `logFn` silently drops messages (debug logging must never break startup). +/// Open the per-session debug log file and arm `logFn` to write to it when +/// `PANTO_DEBUG != 0`. Best-effort: any failure leaves normal logging in place. /// /// Safe to call once, after the session id is known. `environ_map` is used to -/// resolve `$PANTO_HOME`; `io` is used only to create the `debug/` directory. +/// resolve the data home; `io` is used only to create the `debug/` directory. pub fn init( allocator: Allocator, io: Io, environ_map: *const std.process.Environ.Map, session_id: []const u8, ) void { - if (!enabled) return; + const debug = environ_map.get("PANTO_DEBUG") orelse return; + if (debug.len == 0 or std.mem.eql(u8, debug, "0")) return; var layout = panto_home.resolve(allocator, environ_map) catch return; defer layout.deinit(); @@ -96,17 +92,18 @@ pub fn init( defer unlockLog(); log_fd = fd; seq = 0; + capture_enabled.store(true, .release); } -/// Custom `std.Options.logFn`. Debug builds capture everything to the session -/// file (terminal stays clean); other builds use the stderr default. +/// Custom `std.Options.logFn`. `PANTO_DEBUG != 0` captures everything to the +/// session file; otherwise use the stderr default. pub fn logFn( comptime level: std.log.Level, comptime scope: @EnumLiteral(), comptime format: []const u8, args: anytype, ) void { - if (!enabled) { + if (!capture_enabled.load(.acquire)) { std.log.defaultLog(level, scope, format, args); return; } |
