From 7889a6ec7a409a578ab177e28cfbc11327bb1fb5 Mon Sep 17 00:00:00 2001 From: Yves Biener Date: Thu, 29 Aug 2024 16:36:58 +0200 Subject: [PATCH] mod(options): build options to log to stderr and/or a file NOTE: file logging will not work correctly yet due to opening files appending using the std is currently not implemented (as of zig version 0.13.0)! --- README.md | 1 + build.zig | 4 ++++ src/zlog.zig | 56 ++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index ffc7fa3..a864630 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ This will result in the following output: For more details about the output customization see the configuration options of the `zlog` module. Following options are available: - _timestamp_ (default: `true`): Prepend the current timestamp before each log message. +- _stderr_ (default: `true`): Print log messages to stderr. **NOTE**: Currently not working as log output is not appended and only the last log message will be in the resulting log file! This is a not-yet-implemented feature of the standard library of zig 0.13.0! See this [issue](https://github.com/ziglang/zig/issues/14375) for more details. ## Tips diff --git a/build.zig b/build.zig index 2e8f7e5..37ebbc5 100644 --- a/build.zig +++ b/build.zig @@ -6,9 +6,13 @@ const std = @import("std"); pub fn build(b: *std.Build) void { // build options to customize the log message formating const include_timestamp = b.option(bool, "timestamp", "Enable inclusion of timestamps in log messages (default: true)") orelse true; + const stderr = b.option(bool, "stderr", "Print all log messages to stderr (default: true)") orelse true; + const file = b.option([]const u8, "file", "Print all log messages to the provided file.") orelse ""; const options = b.addOptions(); options.addOption(bool, "timestamp", include_timestamp); + options.addOption(bool, "stderr", stderr); + options.addOption([]const u8, "file", file); const options_module = options.createModule(); diff --git a/src/zlog.zig b/src/zlog.zig index 01122a1..b33c928 100644 --- a/src/zlog.zig +++ b/src/zlog.zig @@ -15,26 +15,52 @@ fn logFn( ) void { // TODO: provide build time configuration to allow tweaking corresponding output // - change output file for writing messages to (default `stderr`) + // write into own file for each level? const level_txt = comptime message_level.asText(); const prefix = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): "; - const stderr = std.io.getStdErr().writer(); - var bw = std.io.bufferedWriter(stderr); - const writer = bw.writer(); + const fmt = level_txt ++ prefix ++ format ++ "\n"; + if (comptime build_options.file.len != 0) blk: { + // NOTE: with zig 0.13.0 there is currently no way to open files to append (except to use libc or talk directly to posix, which this lib should not have to do) + const file = std.fs.openFileAbsolute(build_options.file, .{ + .mode = .read_write, + }) catch std.fs.createFileAbsolute(build_options.file, .{ + .truncate = false, + }) catch break :blk; + defer file.close(); - std.debug.lockStdErr(); - defer std.debug.unlockStdErr(); - nosuspend { - if (build_options.timestamp) { - const curtime = c_time.time(null); - const tm = c_time.localtime(&curtime); + var buffer = std.io.bufferedWriter(file.writer()); + defer buffer.flush() catch {}; - var buf: [32]u8 = undefined; - _ = c_time.strftime(@ptrCast(&buf), 32, "%F %R", tm); - writer.print("[{s}] ", .{buf}) catch return; - } - writer.print(level_txt ++ prefix ++ format ++ "\n", args) catch return; - bw.flush() catch return; + const writer = buffer.writer(); + log_writing(writer, fmt, args); } + + if (comptime build_options.stderr) { + var buffer = std.io.bufferedWriter(std.io.getStdErr().writer()); + defer buffer.flush() catch {}; + + std.debug.lockStdErr(); + defer std.debug.unlockStdErr(); + + const writer = buffer.writer(); + log_writing(writer, fmt, args); + } +} + +fn log_writing(writer: anytype, comptime fmt: []const u8, args: anytype) void { + nosuspend { + if (build_options.timestamp) log_timestamp(writer); + writer.print(fmt, args) catch return; + } +} + +fn log_timestamp(writer: anytype) void { + const curtime = c_time.time(null); + const tm = c_time.localtime(&curtime); + + var buffer: [32]u8 = undefined; + _ = c_time.strftime(@ptrCast(&buffer), 32, "%F %R", tm); + writer.print("[{s}] ", .{buffer}) catch return; } pub fn pretty_format(object: anytype, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {