Skip to content

Commit 2d7517a

Browse files
committed
log: consolidate modules, add stderr/ISO8601/microsecond timestamps
Major restructuring of the logging module: - Consolidate 20+ separate files into 6 focused modules: record.zig (Scope, Level, Attr, Record, comptime checks), filter.zig (LevelFilter, ScopeFilter, EnvFilter), diagnostic.zig (StaticDiagnostic, ThreadLocalDiagnostic), layout.zig (TextLayout, JsonLayout, LogfmtLayout), append.zig (WriterAppend, AsyncAppend, RollingFileWriter, OpenTelemetryAppend), dispatch.zig (Dispatch, Dispatcher, AnyDispatcher, Logger) - Extract RingBuffer to top-level src/ring_buffer.zig - Switch default output from stdout to stderr (Unix convention) - Replace global g_stderr variable with stateless stderrWriter() - Fix FlushableWriter.fromFlushable dangling pointer for async use - Format timestamps as ISO 8601 UTC with microsecond precision (e.g. 2024-08-11T22:44:57.172105Z) - Add 3 global dispatcher builders: console, file, combined - Update log_smoke example to exercise all builders and layouts
1 parent 6bb0149 commit 2d7517a

28 files changed

+5456
-2143
lines changed

build.zig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,20 @@ pub fn build(b: *std.Build) void {
149149
module_bls.linkLibrary(dep_blst.artifact("blst"));
150150
b.modules.put(b.dupe("bls"), module_bls) catch @panic("OOM");
151151

152+
const module_ring_buffer = b.createModule(.{
153+
.root_source_file = b.path("src/ring_buffer.zig"),
154+
.target = target,
155+
.optimize = optimize,
156+
});
157+
b.modules.put(b.dupe("ring_buffer"), module_ring_buffer) catch @panic("OOM");
158+
152159
const module_log = b.createModule(.{
153160
.root_source_file = b.path("src/log/root.zig"),
154161
.target = target,
155162
.optimize = optimize,
163+
.imports = &.{
164+
.{ .name = "ring_buffer", .module = module_ring_buffer },
165+
},
156166
});
157167
b.modules.put(b.dupe("log"), module_log) catch @panic("OOM");
158168

examples/log_smoke.zig

Lines changed: 136 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//! Log integration smoke example.
22
//!
3-
//! Demonstrates both the V2 structured Logger API and the std.log bridge.
3+
//! Demonstrates the V2 structured Logger API, std.log bridge,
4+
//! all three async builder configs, and all three layout formats.
45
//!
56
//! Run:
67
//! zig build run:log_smoke
78
//!
8-
//! Expected output format (per line):
9-
//! <unix-ms> <level> (<scope>): <message> key=value ...
9+
//! Expected output: structured log lines on stderr from each dispatcher/layout.
1010

1111
const std = @import("std");
1212
const log_mod = @import("log");
@@ -16,22 +16,138 @@ pub const std_options = log_mod.std_options;
1616

1717
const Logger = log_mod.Logger;
1818
const Attr = log_mod.Attr;
19+
const Dispatch = log_mod.Dispatch;
20+
const Dispatcher = log_mod.Dispatcher;
21+
const LevelFilter = log_mod.LevelFilter;
22+
const FlushableWriter = log_mod.FlushableWriter;
23+
const WriterAppend = log_mod.WriterAppend;
24+
const TextLayout = log_mod.TextLayout;
25+
const JsonLayout = log_mod.JsonLayout;
26+
const LogfmtLayout = log_mod.LogfmtLayout;
1927

20-
pub fn main() void {
21-
// std.log bridge — existing code keeps working
22-
const std_log = std.log.scoped(.smoke);
23-
std_log.err("std.log bridge err", .{});
24-
std_log.warn("std.log bridge warn", .{});
25-
std_log.info("std.log bridge info", .{});
26-
27-
// V2 structured Logger API
28-
const log = Logger(4).init(.smoke, log_mod.getGlobalDispatcher());
29-
log.err("structured err", .{ .code = @as(u64, 500) });
30-
log.warn("structured warn", .{});
31-
log.info("block applied", .{ .slot = @as(u64, 42) });
32-
log.debug("debug detail", .{ .flag = true });
33-
34-
// Child logger with pre-bound attributes
35-
const child = log.with(&[_]Attr{Attr.str("module", "fc")});
36-
child.info("child log", .{ .epoch = @as(u64, 7) });
28+
/// Helper: emit a standard set of log lines through `log`.
29+
fn emitSample(log: anytype) void {
30+
log.err("error msg", .{ .code = @as(u64, 500) });
31+
log.warn("warn msg", .{});
32+
log.info("info msg", .{ .slot = @as(u64, 42) });
33+
log.debug("debug msg", .{ .flag = true });
34+
}
35+
36+
pub fn main() !void {
37+
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
38+
defer _ = gpa.deinit();
39+
const allocator = gpa.allocator();
40+
41+
// ── 1. Default (sync stderr, TextLayout) ─────────────────
42+
43+
std.debug.print("\n=== 1. Default (sync stderr, TextLayout) ===\n", .{});
44+
{
45+
const std_log = std.log.scoped(.smoke);
46+
std_log.err("std.log bridge err", .{});
47+
std_log.info("std.log bridge info", .{});
48+
49+
const log = Logger(4).init(.smoke, log_mod.getGlobalDispatcher());
50+
emitSample(log);
51+
52+
const child = log.with(&[_]Attr{Attr.str("module", "fc")});
53+
child.info("child log", .{ .epoch = @as(u64, 7) });
54+
}
55+
56+
// ── 2. Console builder (async stderr, TextLayout) ────────
57+
58+
std.debug.print("\n=== 2. Console builder (async stderr, TextLayout) ===\n", .{});
59+
{
60+
try log_mod.initConsoleDispatcher(allocator, .{ .min_level = .debug });
61+
defer log_mod.deinitGlobalDispatcher();
62+
63+
const log = Logger(4).init(.smoke, log_mod.getGlobalDispatcher());
64+
emitSample(log);
65+
log_mod.flushGlobalDispatcher();
66+
}
67+
68+
// ── 3. File builder (async rolling file, TextLayout) ─────
69+
70+
std.debug.print("\n=== 3. File builder (async rolling file, TextLayout) ===\n", .{});
71+
{
72+
try log_mod.initFileDispatcher(allocator, .{
73+
.min_level = .debug,
74+
.dir = std.fs.cwd(),
75+
.base_name = "smoke.log",
76+
.rolling = .{ .rotation = .never, .max_bytes = 1024 * 1024 },
77+
});
78+
defer log_mod.deinitGlobalDispatcher();
79+
80+
const log = Logger(4).init(.smoke, log_mod.getGlobalDispatcher());
81+
emitSample(log);
82+
log_mod.flushGlobalDispatcher();
83+
std.debug.print(" → wrote smoke.log\n", .{});
84+
}
85+
86+
// ── 4. Combined builder (async stderr + file, TextLayout) ─
87+
88+
std.debug.print("\n=== 4. Combined builder (async stderr + file, TextLayout) ===\n", .{});
89+
{
90+
try log_mod.initCombinedDispatcher(allocator, .{
91+
.min_level = .debug,
92+
.dir = std.fs.cwd(),
93+
.base_name = "smoke_combined.log",
94+
.rolling = .{ .rotation = .never, .max_bytes = 1024 * 1024 },
95+
});
96+
defer log_mod.deinitGlobalDispatcher();
97+
98+
const log = Logger(4).init(.smoke, log_mod.getGlobalDispatcher());
99+
emitSample(log);
100+
log_mod.flushGlobalDispatcher();
101+
std.debug.print(" → wrote smoke_combined.log\n", .{});
102+
}
103+
104+
// ── 5. Custom pipeline — JsonLayout (sync stderr) ────────
105+
106+
std.debug.print("\n=== 5. JsonLayout (sync stderr) ===\n", .{});
107+
{
108+
const WA = WriterAppend(JsonLayout);
109+
const D = Dispatch(struct { LevelFilter }, struct {}, struct { WA });
110+
const Disp = Dispatcher(struct {D});
111+
112+
var dispatcher = Disp{
113+
.dispatches = .{
114+
D{
115+
.filters = .{ LevelFilter.init(.debug) },
116+
.diagnostics = .{},
117+
.appenders = .{ WA.init(allocator, JsonLayout{}, FlushableWriter.stderrWriter()) },
118+
},
119+
},
120+
};
121+
122+
const log = Logger(4).init(.smoke, dispatcher.any());
123+
emitSample(log);
124+
}
125+
126+
// ── 6. Custom pipeline — LogfmtLayout (sync stderr) ──────
127+
128+
std.debug.print("\n=== 6. LogfmtLayout (sync stderr) ===\n", .{});
129+
{
130+
const WA = WriterAppend(LogfmtLayout);
131+
const D = Dispatch(struct { LevelFilter }, struct {}, struct { WA });
132+
const Disp = Dispatcher(struct {D});
133+
134+
var dispatcher = Disp{
135+
.dispatches = .{
136+
D{
137+
.filters = .{ LevelFilter.init(.debug) },
138+
.diagnostics = .{},
139+
.appenders = .{ WA.init(allocator, LogfmtLayout{}, FlushableWriter.stderrWriter()) },
140+
},
141+
},
142+
};
143+
144+
const log = Logger(4).init(.smoke, dispatcher.any());
145+
emitSample(log);
146+
}
147+
148+
// cleanup generated files
149+
std.fs.cwd().deleteFile("smoke.log") catch {};
150+
std.fs.cwd().deleteFile("smoke_combined.log") catch {};
151+
152+
std.debug.print("\n=== All 6 configurations OK ===\n", .{});
37153
}

src/log/AsyncAppend.zig

Lines changed: 0 additions & 172 deletions
This file was deleted.

0 commit comments

Comments
 (0)