# zlog Standard Library log wrapper. `zlog` provides adjusted `std.log` output and a pretty print function for easy overwriting of user defined types. > [!caution] > Only builds using the zig master version are tested to work. ## Usage The following snippet shows an example usage of `zlog` to change the default log format and add pretty printing to the user defined types: ```zig const Union = union { int: i32, boolean: bool, // copy and paste this function into your user defined types to enable pretty printing for these types pub fn format(value: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { try zlog.pretty_format(value, fmt, options, writer); } }; const TaggedUnion = union(enum) { one: i16, two: u32, three: []const u8, nothing, // copy and paste this function into your user defined types to enable pretty printing for these types pub fn format(value: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { try zlog.pretty_format(value, fmt, options, writer); } }; const Options = enum { a, b, c, // copy and paste this function into your user defined types to enable pretty printing for these types pub fn format(value: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { try zlog.pretty_format(value, fmt, options, writer); } }; const Struct = struct { a: usize = 42, b: bool = true, c: [5]u16 = .{ 1, 2, 3, 4, 5 }, d: []const u8 = "string", e: Options = .b, f: TaggedUnion = .{ .one = -5 }, // same function as above... pub fn format(value: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { try zlog.pretty_format(value, fmt, options, writer); } }; pub fn main() void { // 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 // the resulting output (default behavior of `std.log.defaultLog`) // some variables to log const int_var = 42; const array_var = [_]i32{ 1, 2, 3, 4 }; const string_var = "This is a test"; const option_var: Options = .a; const struct_var: Struct = .{}; const tagged_union: TaggedUnion = .{ .three = "Three", }; const void_tagged_union: TaggedUnion = .nothing; const uniun: Union = .{ .boolean = true }; // 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}); log.info("Info message \"{s}\"", .{string_var}); log.warn("Warning message {any}", .{option_var}); log.warn("Warning message {any}", .{void_tagged_union}); log.warn("Warning message {any}", .{uniun}); log.err("Error message {any}", .{struct_var}); log.err("Error message {any}", .{tagged_union}); } pub const std_options = zlog.std_options; const std = @import("std"); const zlog = @import("zlog"); ``` This will result in the following output: ``` [2025-07-17 19:41:43] [debug](main): Debug message 42 [2025-07-17 19:41:43] [info](main): Info message { 1, 2, 3, 4 } [2025-07-17 19:41:43] [info](main): Info message "This is a test" [2025-07-17 19:41:43] [warning](main): Warning message main.Options = enum { a, b, c, } = .a [2025-07-17 19:41:43] [warning](main): Warning message main.TaggedUnion = union(enum) { one: i16, two: u32, three: []const u8, nothing, } = .{ .nothing = void } [2025-07-17 19:41:43] [warning](main): Warning message main.Union = union { int: i32, boolean: bool, } = @7fffd1c71048 [2025-07-17 19:41:43] [error](main): Error message main.Struct = struct { .a = 42, .b = true, .c = []u16: { 1, 2, 3, 4, 5 }, .d = "string", .e = main.Options = enum { a, b, c, } = .b, .f = main.TaggedUnion = union(enum) { one: i16, two: u32, three: []const u8, nothing, } = .{ .one = -5 }, } [2025-07-17 19:41:43] [error](main): Error message main.TaggedUnion = union(enum) { one: i16, two: u32, three: []const u8, nothing, } = .{ .three = "Three" } ``` ## Customization 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. > [!caution] > 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! See this [issue](https://github.com/ziglang/zig/issues/14375) for more details. > For now you should instead leave this option as it is and pipe the corresponding stderr outputs to a logfile instead. ## Tips The following list shows some tips on how to use logging more effectively. These tips do not apply just to `zlog` (and not even only to zig code). - Use `errdefer` to directly print messages on failures in the same function they occur: ```zig // assume log is already defined before (with the corresponding scope) const port = port: { errdefer |err| log.err("failed to read the port number: {}", .{err}); var buf: [fmt.count("{}\n", .{maxInt(u16)})]u8 = undefined; const len = try process.stdout.?.readAll(&buf); break :port try fmt.parseInt(u16, buf[0 .. len -| 1], 10); }; ``` - When looking through the output of the log (i.e. written to disk by `program 2> log` when using the _stderr_ build option) the `log` file contains control code characters (*ansi*) for the colored outputs. You can still see them correctly with the following command `less -R log`.