logging without logger, better public API
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
.{
|
||||
.name = .faller,
|
||||
.version = "0.2.1",
|
||||
.version = "0.3.1",
|
||||
.minimum_zig_version = "0.15.1",
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
|
||||
124
src/root.zig
124
src/root.zig
@@ -1,3 +1,21 @@
|
||||
//! A tag based Logger. Example:
|
||||
//!
|
||||
//! ```zig
|
||||
//! log(.foo, "Anonymous log", .{});
|
||||
//!
|
||||
//! const module_log = scope(.module);
|
||||
//! module_log.log(.debug, "Hello {s}!", .{"World"});
|
||||
//!
|
||||
//! const sub_module_log = module_log.scope(.bar);
|
||||
//! sub_module_log.log(.perf, "Operation took {} ns", .{5});
|
||||
//! ```
|
||||
//!
|
||||
//! Output:
|
||||
//! ```
|
||||
//! foo: Anonymous log
|
||||
//! module|debug: Hello World!
|
||||
//! module|bar|perf: Operation took 5 ns
|
||||
//! ```
|
||||
const std = @import("std");
|
||||
const root = @import("root");
|
||||
const builtin = @import("builtin");
|
||||
@@ -20,51 +38,86 @@ pub const Options = struct {
|
||||
/// tags is present it **isn't** logged. May overwrite `tags_enabled`.
|
||||
tags_disabled: []const @Type(.enum_literal) = &.{},
|
||||
buffer_size: u64 = 64,
|
||||
disabled_in_test: bool = true,
|
||||
disabled_in_test: bool = false,
|
||||
};
|
||||
|
||||
pub const empty_logger = Logger{ .base_tags = &.{} };
|
||||
/// A Logger with prefixes.
|
||||
pub const Logger = struct {
|
||||
base_tags: []const @Type(.enum_literal),
|
||||
|
||||
/// A tag based Logger. Examples:
|
||||
///
|
||||
/// ```zig
|
||||
/// pub const module_log = Logger{ .base_tags = &.{.module} };
|
||||
/// module_log.log(.debug, "Hello {s}!", .{"World"});
|
||||
///
|
||||
/// pub const sub_module_log = module_log.scope(.bar);
|
||||
/// sub_module_log.log(.perf, "Operation took {} ns", .{time_ns});
|
||||
/// ```
|
||||
pub const Logger = @This();
|
||||
/// Creates a new logger with an additional tag prefix.
|
||||
pub fn scope(comptime logger: Logger, comptime tag: @Type(.enum_literal)) Logger {
|
||||
return .{
|
||||
.base_tags = logger.base_tags ++ [_]@Type(.enum_literal){tag},
|
||||
};
|
||||
}
|
||||
|
||||
base_tags: []const @Type(.enum_literal),
|
||||
/// Log with one additional `tag`. Checks whether the log is enabled.
|
||||
pub fn log(
|
||||
comptime logger: Logger,
|
||||
comptime tag: @Type(.enum_literal),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
logger.logTags(&.{tag}, format, args);
|
||||
}
|
||||
|
||||
/// Creates a new logger with an extended tag prefix.
|
||||
pub fn scope(comptime logger: Logger, comptime tag: @TypeOf(.enum_literal)) Logger {
|
||||
/// Log with multiple `tags`. Checks whether the log is enabled.
|
||||
pub fn logTags(
|
||||
comptime logger: Logger,
|
||||
comptime tags: []const @Type(.enum_literal),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
if (builtin.is_test and options.disabled_in_test) return;
|
||||
const all_tags = logger.base_tags ++ tags;
|
||||
options.function(all_tags, format, args);
|
||||
}
|
||||
};
|
||||
|
||||
/// Creates a new logger with a tag prefix.
|
||||
pub fn scope(comptime tag: @TypeOf(.enum_literal)) Logger {
|
||||
return .{
|
||||
.base_tags = logger.base_tags ++ [_]@Type(.enum_literal){tag},
|
||||
.base_tags = &[_]@Type(.enum_literal){tag},
|
||||
};
|
||||
}
|
||||
|
||||
/// Log with one `tag`. Checks whether the log is enabled.
|
||||
pub fn log(
|
||||
comptime logger: Logger,
|
||||
comptime tag: @Type(.enum_literal),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
logger.logTags(&.{tag}, format, args);
|
||||
logTags(&.{tag}, format, args);
|
||||
}
|
||||
|
||||
/// Log with multiple `tags`. Checks whether the log is enabled.
|
||||
pub fn logTags(
|
||||
comptime logger: Logger,
|
||||
comptime tags: []const @Type(.enum_literal),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
if (builtin.is_test and options.disabled_in_test) return;
|
||||
const all_tags = comptime logger.base_tags ++ tags;
|
||||
options.function(all_tags, format, args);
|
||||
options.function(tags, format, args);
|
||||
}
|
||||
|
||||
/// Checks whether the log is enabled for a specific combination of `tags`. Depends on the `options`
|
||||
/// set.
|
||||
pub fn logEnabled(comptime tags: []const @Type(.enum_literal)) bool {
|
||||
// If `tags` has at least one in `options.tags_disabled` then we never log.
|
||||
if (options.tags_disabled.len > 0) {
|
||||
if (intersect(tags, options.tags_disabled)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If `tags` has at least one in `options.tags_enabled` then we should log.
|
||||
if (options.tags_enabled.len > 0) {
|
||||
return intersect(tags, options.tags_enabled);
|
||||
}
|
||||
|
||||
// If neither is set then we just log everything.
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Return `false` if `as` and `bs` have no common member. Else return `true`.
|
||||
@@ -79,25 +132,6 @@ fn intersect(comptime as: []const @Type(.enum_literal), comptime bs: []const @Ty
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Checks whether the log is enabled for a specific combination of `tags`. Depends on the `options`
|
||||
/// set.
|
||||
pub fn logEnabled(comptime tags: []const @Type(.enum_literal)) bool {
|
||||
// If `tags` has at least one in `options.tags_disabled` then we never log.
|
||||
if (options.tags_disabled.len > 0) {
|
||||
if (comptime intersect(tags, options.tags_disabled)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If `tags` has at least one in `options.tags_enabled` then we should log.
|
||||
if (options.tags_enabled.len > 0) {
|
||||
return comptime intersect(tags, options.tags_enabled);
|
||||
}
|
||||
|
||||
// If neither is set then we just log everything.
|
||||
return true;
|
||||
}
|
||||
|
||||
fn defaultLogFunction(
|
||||
comptime tags: []const @Type(.enum_literal),
|
||||
comptime format: []const u8,
|
||||
@@ -117,3 +151,13 @@ fn defaultLogFunction(
|
||||
defer std.debug.unlockStderrWriter();
|
||||
nosuspend stderr.print(prefix ++ ": " ++ format ++ "\n", args) catch return;
|
||||
}
|
||||
|
||||
test {
|
||||
log(.foo, "Anonymous log", .{});
|
||||
|
||||
const module_log = scope(.module);
|
||||
module_log.log(.debug, "Hello {s}!", .{"World"});
|
||||
|
||||
const sub_module_log = module_log.scope(.bar);
|
||||
sub_module_log.log(.perf, "Operation took {} ns", .{5});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user