Commit 50822530d3

Lee Cannon <leecannon@leecannon.xyz>
2021-06-09 11:23:45
Provide method to set logging level per scope (#8584)
1 parent 5fa5fba
Changed files (2)
lib/std/log.zig
@@ -117,13 +117,30 @@ pub const level: Level = if (@hasDecl(root, "log_level"))
 else
     default_level;
 
+pub const ScopeLevel = struct {
+    scope: @Type(.EnumLiteral),
+    level: Level,
+};
+
+const scope_levels = if (@hasDecl(root, "scope_levels"))
+    root.scope_levels
+else
+    [0]ScopeLevel{};
+
 fn log(
     comptime message_level: Level,
     comptime scope: @Type(.EnumLiteral),
     comptime format: []const u8,
     args: anytype,
 ) void {
-    if (@enumToInt(message_level) <= @enumToInt(level)) {
+    const effective_log_level = blk: {
+        inline for (scope_levels) |scope_level| {
+            if (scope_level.scope == scope) break :blk scope_level.level;
+        }
+        break :blk level;
+    };
+
+    if (@enumToInt(message_level) <= @enumToInt(effective_log_level)) {
         if (@hasDecl(root, "log")) {
             root.log(message_level, scope, format, args);
         } else if (std.Target.current.os.tag == .freestanding) {
test/compare_output.zig
@@ -516,4 +516,87 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
 
         break :x tc;
     });
+
+    // It is required to override the log function in order to print to stdout instead of stderr
+    cases.add("std.log per scope log level override",
+        \\const std = @import("std");
+        \\
+        \\pub const log_level: std.log.Level = .debug;
+        \\
+        \\pub const scope_levels = [_]std.log.ScopeLevel{
+        \\    .{ .scope = .a, .level = .alert },
+        \\    .{ .scope = .c, .level = .emerg },
+        \\};
+        \\
+        \\const loga = std.log.scoped(.a);
+        \\const logb = std.log.scoped(.b);
+        \\const logc = std.log.scoped(.c);
+        \\
+        \\pub fn main() !void {
+        \\    loga.debug("", .{});
+        \\    logb.debug("", .{});
+        \\    logc.debug("", .{});
+        \\
+        \\    loga.info("", .{});
+        \\    logb.info("", .{});
+        \\    logc.info("", .{});
+        \\
+        \\    loga.notice("", .{});
+        \\    logb.notice("", .{});
+        \\    logc.notice("", .{});
+        \\
+        \\    loga.warn("", .{});
+        \\    logb.warn("", .{});
+        \\    logc.warn("", .{});
+        \\
+        \\    loga.err("", .{});
+        \\    logb.err("", .{});
+        \\    logc.err("", .{});
+        \\
+        \\    loga.crit("", .{});
+        \\    logb.crit("", .{});
+        \\    logc.crit("", .{});
+        \\
+        \\    loga.alert("", .{});
+        \\    logb.alert("", .{});
+        \\    logc.alert("", .{});
+        \\
+        \\    loga.emerg("", .{});
+        \\    logb.emerg("", .{});
+        \\    logc.emerg("", .{});
+        \\}
+        \\pub fn log(
+        \\    comptime level: std.log.Level,
+        \\    comptime scope: @TypeOf(.EnumLiteral),
+        \\    comptime format: []const u8,
+        \\    args: anytype,
+        \\) void {
+        \\    const level_txt = switch (level) {
+        \\        .emerg => "emergency",
+        \\        .alert => "alert",
+        \\        .crit => "critical",
+        \\        .err => "error",
+        \\        .warn => "warning",
+        \\        .notice => "notice",
+        \\        .info => "info",
+        \\        .debug => "debug",
+        \\    };
+        \\    const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
+        \\    const stdout = std.io.getStdOut().writer();
+        \\    nosuspend stdout.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return;
+        \\}
+    ,
+        \\debug(b): 
+        \\info(b): 
+        \\notice(b): 
+        \\warning(b): 
+        \\error(b): 
+        \\critical(b): 
+        \\alert(a): 
+        \\alert(b): 
+        \\emergency(a): 
+        \\emergency(b): 
+        \\emergency(c): 
+        \\
+    );
 }