const std = @import("std"); const config = @import("config.zig"); var mutex: std.atomic.Mutex = .unlocked; pub fn debug(comptime fmt: []const u8, args: anytype) void { write(.debug, "debug", fmt, args); } pub fn info(comptime fmt: []const u8, args: anytype) void { write(.info, "info", fmt, args); } pub fn err(comptime fmt: []const u8, args: anytype) void { write(.err, "error", fmt, args); } fn write(level: config.LogLevel, comptime label: []const u8, comptime fmt: []const u8, args: anytype) void { if (!config.logEnabled(level)) return; var buf: [2048]u8 = undefined; const message = std.fmt.bufPrint(&buf, label ++ " " ++ fmt, args) catch blk: { const prefix = label ++ " "; @memcpy(buf[0..prefix.len], prefix); const suffix = "log message too large\n"; @memcpy(buf[prefix.len..][0..suffix.len], suffix); break :blk buf[0 .. prefix.len + suffix.len]; }; while (!mutex.tryLock()) std.Thread.yield() catch {}; defer mutex.unlock(); writeAllStderr(message); } fn writeAllStderr(message: []const u8) void { var remaining = message; while (remaining.len > 0) { const written = std.c.write(std.posix.STDERR_FILENO, remaining.ptr, remaining.len); if (written <= 0) return; remaining = remaining[@intCast(written)..]; } }