-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Introduce std.log #5348
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce std.log #5348
Conversation
lib/std/log.zig
Outdated
/// log.default_level. | ||
pub const level: Level = if (@hasDecl(root, "log_level")) root.log_level else default_level; | ||
|
||
fn log(comptime message_level: Level, comptime format: []const u8, args: var) void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fn log(comptime message_level: Level, comptime format: []const u8, args: var) void { | |
pub fn log(comptime message_level: Level, comptime format: []const u8, args: var) void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that making this public would violate the "Only one obvious way to do things" bullet point of the zig zen. I prefer
std.log.warn("message", .{});
over
std.log.log(.warn, "message", {});
personally so I'm inclined to keep this as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub fn log
will support custom level if Level
become non-exhaustive enum.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Frankly I'm not a fan of allowing custom log levels when using std.log
. It is imo unnecessary complexity and will reduce compatibility between libraries and programs which is the whole point of a unified std.log
interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lack of flexibility forces developers to reinvent their own wheels.
Inspired by other libraries (in C++, Rust, Nim): pub const Level = enum(u32) {
none, //or off, disabled, etc.
trace,
debug,
info,
notice,
warn,
err,
fatal,
_, //for custom level
}; |
These levels come from the syslog protocol and is only a
|
Also would be nice supports the log function in structs if it's declared. |
@data-man I'm not quite clear on what you're picturing here. Maybe you could give an example? |
@ifreund |
@data-man this already leverages |
No. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest we also have a "component"/"facility" comptime argument.
I've been considering adding a I don't plan on adding additional log levels as I think the current 4 are sufficient and keeping this count low will simplify filtering and make choices about what level to use easier. |
I think removing the panic from |
@ifreund info("Enter the Matrix", .{}); //Should be printed "[info] Enter the Matrix"?
warn("Enter the ", .{"Matrix"}); //Should be printed "[warning] Enter the Matrix"?
err("{} the {}", .{"Enter", "Matrix"}); //Should be printed "[error] Enter the Matrix"? |
That's up to the user to implement. For example pub fn log(comptime level: std.log.Level, comptime format: []const u8, args: var) void {
const prefix = switch (level) {
.info => "[INFO] ",
.warn => "[WARN] ",
.err => "[ERROR] ",
.silent => return,
};
const held = std.debug.getStderrMutex().acquire();
defer held.release();
const stderr = std.debug.getStderrStream();
nosuspend stderr.print(prefix ++ format, args) catch return;
} I expect that most non-trivial programs will define If we opt to go with a more "batteries included" approach then something like this example could be made default, perhaps with some pretty colors if run from a tty. |
Sure.
If my previous example is inserted into the standard library, the user will see three identical messages. |
I don't see why you'd need a enum: just take a |
I would advise following the syslog protocol levels I quoted earlier: they are pervasive across all logging systems. Sure it's hard to know when to use ALERT vs CRIT vs ERR.... but that's already a choice people make elsewhere. |
I added a scope parameter in the form of an enum literal. I think that this gives the right amount of flexibility while still allowing for simple filtering with a switch statement. This now depends on #5203. You can also test by applying this simple patch diff --git a/src/ir.cpp b/src/ir.cpp
index 6bd4e9b80..0bd44ee1f 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -25464,10 +25464,11 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
ZigType *child_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "child", 0);
return get_any_frame_type(ira->codegen, child_type);
}
+ case ZigTypeIdEnumLiteral:
+ return ira->codegen->builtin_types.entry_enum_literal;
case ZigTypeIdErrorSet:
case ZigTypeIdEnum:
case ZigTypeIdFnFrame:
- case ZigTypeIdEnumLiteral:
ir_add_error(ira, source_instr, buf_sprintf(
"TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId)));
return ira->codegen->invalid_inst_gen->value->type; Still thinking about whether we want to follow the syslog protocol or keep things simple. The simplicity is appealing for smaller projects, though the added granularity of the syslog levels would certainly be useful at scale. I know that zig is intended to work well with massive code bases, so perhaps that is the way to go. It also has the advantage of being widely used and familiar already. |
//! // Won't be printed as it gets filtered out by our log function | ||
//! std.log.warn(.lib_that_logs_too_much, "Added 1 + 1\n", .{}); | ||
//! } | ||
//! ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn't sure how example code should be formatted in doc comments, so I just defaulted to some markdown backticks
After spending some time thinking on this, I've decided that @daurnimator is right and we should use the syslog logging levels. I've implement them in this new commit and tweaked the rest of the code accordingly. The example the toplevel doc comment has also been updated. I will edit the PR description with the new commit message. |
Deprecated |
this implements a modified version of the logging interface proposed here: ziglang/zig#5348
std.log provides 8 log levels and corresponding logging functions. It allows the user to override the logging "backend" by defining root.log and to override the default log level by defining root.log_level. Logging functions accept a scope parameter which allows the implementer of the logging "backend" to filter logging by library as well as level. Using the standardized syslog [1] log levels ensures that std.log will be flexible enough to work for as many use-cases as possible. If we were to stick with only 3/4 log levels, std.log would be insufficient for large and/or complex projects such as a kernel or display server. [1]: https://tools.ietf.org/html/rfc5424#section-6.2.1
Rebased to resolve conflicts. |
Note: this currently depends on |
std.log provides 8 log levels and corresponding logging functions. It
allows the user to override the logging "backend" by defining root.log
and to override the default log level by defining root.log_level.
Logging functions accept a scope parameter which allows the implementer
of the logging "backend" to filter logging by library as well as level.
Using the standardized syslog 1 log levels ensures that std.log will
be flexible enough to work for as many use-cases as possible. If we were
to stick with only 3/4 log levels, std.log would be insufficient for
large and/or complex projects such as a kernel or display server.
TODO:
std.log
std.debug.warn
std.debug.warn
(perhaps in a follow-up PR)Will close #2586