summaryrefslogtreecommitdiff
path: root/src/debug_log.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/debug_log.zig')
-rw-r--r--src/debug_log.zig41
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;
}