Just starting with zig I thought a trivial but real-world exercise would be adding dynamic log levels to std.log. I added a global level easily enough by filtering inside a custom logFn, but what if I want per-scope dynamic levels? I tried adding an array of ScopeLevels, but the compiler tells me it has to be const or comptime because of the @cosmic crescent(.EnumLiteral) param in the logFn. My understanding of comptime is still very vague, why is a global dynamic level acceptable but not an array of them?
#Adding dynamic log levels to std.log (aka another noob question about comptime)
1 messages · Page 1 of 1 (latest)
comptime message_level: std.log.Level,
comptime scope: @Type(.EnumLiteral),
comptime format: []const u8,
args: anytype,
) void {
// error: variable of type '[1]log.ScopeLevel' must be const or comptime
for (scoped_runtime_log_levels) |scope_level| {
if (scope_level.scope == scope) return @intFromEnum(message_level) <= @intFromEnum(scope_level.level);
}
// this works
if (@intFromEnum(message_level) > @intFromEnum(global_runtime_log_level)) {
return;
}
std.log.defaultLog(message_level, scope, format, args);
}
pub var global_runtime_log_level: std.log.Level = .warn;
pub var scoped_runtime_log_levels = [_]std.log.ScopeLevel {
.{ .scope = .customLog, .level = .debug },
};```
ultimately it's not practical anyway, since I don't think I have a reasonable way of altering scoped_runtime_log_levels at runtime. In which case the question becomes how else can I associate data with the scope type passed in as a parameter?
bumping up. I'm trying to create a simple CLI tool with --verbose flag, and being able to alter log-level in runtime is sort of a must-have. Have run into same issue as OP, any solutions yet?
What is the error you get?
Ah, I guess the @Type(.EnumLiteral) can't be used with runtime variables. In that case you'll have to use a different type for scope levels. Easiest would either be use a []const u8 for the scope and test against @tagName(scope) in the log function, or make an enum of all the scopes you use.
yeah, it's the runtime thing. a narrowed down code goes like this:
const std = @import("std");
pub const std_options = struct {
pub const log_level = .debug;
};
pub fn main() !void {
var opt = try simargs.parse(allocator, struct {
verbose: ?bool,
}, "[file]", null);
if (opt.args.verbose.?) {
std_options.log_level = .debug;
}
}
and then:
$ zig build run -- --verbose
src/main.zig:41:20: error: cannot assign to constant
std_options.log_level = .debug;
~~~~~~~~~~~^~~~~~~~~~
As far as I understand scopes, different log levels per scope would also have to be defined in std_options at comptime and as OP said, I don't seem to be able to create a global log_level variable, because enum literal needs to be const
So if I do anything like:
pub const log_level = .debug;
pub const logFn = myLogFn;
};
var global_log_level: @TypeOf(.enum_literal) = .info;
pub fn myLogFn(
comptime level: std.log.Level,
comptime scope: @TypeOf(.EnumLiteral),
comptime format: []const u8,
args: anytype,
) void {
if (@intFromEnum(level) < @intFromEnum(global_log_level)) {
return;
}
std.log.defaultLog(level, scope, format, args);
}```
i get:
$ zig build run -- --verbose
src/main.zig:12:23: error: variable of type '@TypeOf(.enum_literal)' must be const or comptime
var global_log_level: @TypeOf(.enum_literal) = .info;
^~~~~~~~~~~~~~~~~~~~~~```
I guess, from what you're saying the way to go would be to abandon the levels as defined in std.log and go with a custom enum of sorts