mod: rem zlog dependency; stream line logging structure; do not write ansi control characters when logging to file
Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Failing after 1m21s

This commit is contained in:
2025-11-02 13:09:34 +01:00
parent bd33f9c8f9
commit 69da9265b8
6 changed files with 97 additions and 85 deletions

View File

@@ -46,6 +46,8 @@ const Struct = struct {
};
pub fn main() void {
// without explict scope (i.e. `.default` scope)
std.log.info("Without explicit scope or `.default` scope", .{});
// initialize zlog with the scope of `main`
const log = std.log.scoped(.main);
// NOTE the scope of `default` will result in no scoping being printed in
@@ -63,7 +65,7 @@ pub fn main() void {
const void_tagged_union: TaggedUnion = .nothing;
const uniun: Union = .{ .boolean = true };
// NOTE: Depending on the optimization target some of these log messages
// NOTE Depending on the optimization target some of these log messages
// will not show, which is inline with the behavior of `std.log`.
log.debug("Debug message {any}", .{int_var});
log.info("Info message {any}", .{array_var});
@@ -75,6 +77,7 @@ pub fn main() void {
log.err("Error message {any}", .{tagged_union});
}
// apply *zlog* logging options to `std` logger
pub const std_options = zlog.std_options;
const std = @import("std");

View File

@@ -5,18 +5,17 @@ fn logFn(
comptime format: []const u8,
args: anytype,
) void {
const prefix = if (scope == .default) ": " else "(\x1b[2m" ++ @tagName(scope) ++ "\x1b[0m): ";
// TODO this should only happen for messages that are written to *stderr* in files the escape codes are only annoying
const level_txt = switch (comptime message_level) {
.err => "[\x1b[38;5;9merror\x1b[0m]",
.warn => "[\x1b[38;5;11mwarning\x1b[0m]",
.info => "[\x1b[38;5;10minfo\x1b[0m]",
.debug => "[\x1b[38;5;12mdebug\x1b[0m]",
};
// TODO let user configure the format he wants to use for logging and use a pretty good default one?
const complete_format = level_txt ++ prefix ++ format ++ "\n";
var buf: [128]u8 = undefined;
if (comptime build_options.file.len > 0) {
const prefix = if (scope == .default) " " else "(" ++ @tagName(scope) ++ ") ";
const level_txt = switch (comptime message_level) {
.err => "[error]",
.warn => "[warning]",
.info => "[info]",
.debug => "[debug]",
};
// TODO let user configure the format he wants to use for logging and use a pretty good default one?
const complete_format = level_txt ++ prefix ++ format ++ "\n";
// TODO use common logging format, such that in integrates well with other logging frameworks
// (i.e. golang's logger, log4j, etc.)
const fd = std.posix.open(build_options.file, .{
@@ -28,32 +27,63 @@ fn logFn(
var buffer = std.fs.File.Writer.init(.{ .handle = fd }, &buf);
var writer = &buffer.interface;
defer writer.flush() catch {};
defer writer.flush() catch unreachable;
log_writing(writer, complete_format, args);
log_writing(writer, complete_format, false, args);
}
if (comptime build_options.stderr) {
const prefix = if (scope == .default) " " else "(\x1b[2m" ++ @tagName(scope) ++ "\x1b[0m) ";
const level_txt = switch (comptime message_level) {
.err => "[\x1b[38;5;9merror\x1b[0m]",
.warn => "[\x1b[38;5;11mwarning\x1b[0m]",
.info => "[\x1b[38;5;10minfo\x1b[0m]",
.debug => "[\x1b[38;5;12mdebug\x1b[0m]",
};
const complete_format = level_txt ++ prefix ++ format ++ "\n";
var buffer = stderr().writer(&buf);
var writer = &buffer.interface;
defer writer.flush() catch {};
defer writer.flush() catch unreachable;
std.debug.lockStdErr();
defer std.debug.unlockStdErr();
log_writing(writer, complete_format, args);
log_writing(writer, complete_format, true, args);
}
}
inline fn log_writing(writer: *std.Io.Writer, comptime format: []const u8, args: anytype) void {
inline fn log_writing(writer: *std.Io.Writer, comptime format: []const u8, comptime ansi: bool, args: anytype) void {
nosuspend {
if (build_options.timestamp) log_timestamp(writer);
if (build_options.timestamp) log_timestamp(writer, ansi);
writer.print(format, args) catch return;
}
}
inline fn log_timestamp(writer: anytype) void {
writer.print("[\x1b[1m{any}\x1b[0m] ", .{ztime.DateTime.now()}) catch return;
/// Prepend the current timestamp in the following format:
/// `<year>/<month>/<day> <hour>:<minute>:<sec> `
///
/// NOTE all information are displayed using numbers
inline fn log_timestamp(writer: anytype, comptime ansi: bool) void {
const time = std.posix.clock_gettime(.REALTIME) catch @panic("Cannot request timestamp");
const epoch_secs: std.time.epoch.EpochSeconds = .{ .secs = @intCast(time.sec) };
const day_secs = epoch_secs.getDaySeconds();
const year_and_day = epoch_secs.getEpochDay().calculateYearDay();
const month_and_day = year_and_day.calculateMonthDay();
writer.print(
if (comptime ansi)
"\x1b[1m{d}/{d:0>2}/{d:0>2} {d:0>2}:{d:0>2}:{d:0>2}\x1b[0m "
else
"{d}/{d:0>2}/{d:0>2} {d:0>2}:{d:0>2}:{d:0>2} ",
.{
year_and_day.year,
month_and_day.month.numeric(),
month_and_day.day_index + 1,
day_secs.getHoursIntoDay(),
day_secs.getMinutesIntoHour(),
day_secs.getSecondsIntoMinute(),
},
) catch return;
}
pub fn pretty_format(object: anytype, comptime format: []const u8, options: fmt.FormatOptions, writer: anytype) !void {
@@ -197,4 +227,3 @@ const stderr = fs.File.stderr;
const log = std.log;
const fmt = std.fmt;
const build_options = @import("build_options");
const ztime = if (build_options.timestamp) @import("ztime") else null;