Compare commits
12 Commits
a6453733f3
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b7d84d6f6 | |||
| 109aee806d | |||
| fa61b79252 | |||
| 57cfca97cb | |||
| 42f5f94fb4 | |||
| 4099617646 | |||
| f489c96de2 | |||
| 6efcfcded9 | |||
| 2dea92dcd9 | |||
| d39a834f4e | |||
| f78a8eaf1a | |||
| 372738e03e |
21
README.md
21
README.md
@@ -1,3 +1,24 @@
|
|||||||
# faller
|
# faller
|
||||||
|
|
||||||
Small logging library.
|
Small logging library.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Run:
|
||||||
|
```bash
|
||||||
|
zig fetch --save git+https://git.pascalzittlau.de/pzittlau/faller.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Then put this in `build.zig`:
|
||||||
|
```zig
|
||||||
|
const faller = b.dependency("faller", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
// Other options
|
||||||
|
});
|
||||||
|
mod.addImport("faller", faller.module("faller"));
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Apache 2.0
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
pub fn build(b: *std.Build) void {
|
pub fn build(b: *std.Build) void {
|
||||||
const optimize = b.standardOptimizeOption(.{ .preferred_optimize_mode = .ReleaseSafe });
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
|
|
||||||
const faller = b.addModule("faller", .{
|
const faller = b.addModule("faller", .{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.{
|
.{
|
||||||
.name = .faller,
|
.name = .faller,
|
||||||
.version = "0.1.0",
|
.version = "0.3.1",
|
||||||
.minimum_zig_version = "0.15.1",
|
.minimum_zig_version = "0.15.1",
|
||||||
.paths = .{
|
.paths = .{
|
||||||
"build.zig",
|
"build.zig",
|
||||||
|
|||||||
131
src/root.zig
131
src/root.zig
@@ -1,22 +1,36 @@
|
|||||||
|
//! 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 std = @import("std");
|
||||||
const root = @import("root");
|
const root = @import("root");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
pub const options: Options = if (@hasDecl(root, "faller_options")) root.faller_options else .{};
|
pub const options: Options = if (@hasDecl(root, "faller_options")) root.faller_options else .{};
|
||||||
|
|
||||||
/// The base logger to create scopes from. Or just use `Logger` directly.
|
|
||||||
pub const logger = Logger(&.{});
|
|
||||||
|
|
||||||
pub const Options = struct {
|
pub const Options = struct {
|
||||||
|
/// If more specialised ways to log are required replace this function.
|
||||||
|
/// This could be useful for logging to different things than `stderr` or for specifying whether
|
||||||
|
/// we should log with environment variables or `and`-based queries.
|
||||||
function: fn (
|
function: fn (
|
||||||
comptime []const @Type(.enum_literal),
|
comptime []const @Type(.enum_literal),
|
||||||
comptime []const u8,
|
comptime []const u8,
|
||||||
anytype,
|
anytype,
|
||||||
) void = defaultLogFunction,
|
) void = defaultLogFunction,
|
||||||
/// If more specialised ways to determine whether something should be logged are required,
|
|
||||||
/// replace this function.
|
|
||||||
/// This could be useful for instance for specifying it with environment variables or
|
|
||||||
/// `and`-based queries.
|
|
||||||
enabled: fn (comptime []const @Type(.enum_literal)) bool = logEnabled,
|
|
||||||
/// If there is at least one tag given this acts like a whitelist. Meaning if **any** of the
|
/// If there is at least one tag given this acts like a whitelist. Meaning if **any** of the
|
||||||
/// tags is present it is logged. May be overwritten by `tags_disabled`.
|
/// tags is present it is logged. May be overwritten by `tags_disabled`.
|
||||||
tags_enabled: []const @Type(.enum_literal) = &.{},
|
tags_enabled: []const @Type(.enum_literal) = &.{},
|
||||||
@@ -24,13 +38,48 @@ pub const Options = struct {
|
|||||||
/// tags is present it **isn't** logged. May overwrite `tags_enabled`.
|
/// tags is present it **isn't** logged. May overwrite `tags_enabled`.
|
||||||
tags_disabled: []const @Type(.enum_literal) = &.{},
|
tags_disabled: []const @Type(.enum_literal) = &.{},
|
||||||
buffer_size: u64 = 64,
|
buffer_size: u64 = 64,
|
||||||
|
disabled_in_test: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn Logger(comptime base_tags: []const @Type(.enum_literal)) type {
|
/// A Logger with prefixes.
|
||||||
return struct {
|
pub const Logger = struct {
|
||||||
/// Creates a new logger with an extended tag prefix.
|
base_tags: []const @Type(.enum_literal),
|
||||||
pub fn scope(comptime tag: @Type(.enum_literal)) type {
|
|
||||||
return Logger(base_tags ++ [_]@Type(.enum_literal){tag});
|
/// 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},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 = &[_]@Type(.enum_literal){tag},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Log with one `tag`. Checks whether the log is enabled.
|
/// Log with one `tag`. Checks whether the log is enabled.
|
||||||
@@ -48,12 +97,27 @@ pub fn Logger(comptime base_tags: []const @Type(.enum_literal)) type {
|
|||||||
comptime format: []const u8,
|
comptime format: []const u8,
|
||||||
args: anytype,
|
args: anytype,
|
||||||
) void {
|
) void {
|
||||||
const all_tags = comptime base_tags ++ tags;
|
if (builtin.is_test and options.disabled_in_test) return;
|
||||||
if (!options.enabled(all_tags)) return;
|
options.function(tags, format, args);
|
||||||
|
|
||||||
options.function(all_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`.
|
/// Return `false` if `as` and `bs` have no common member. Else return `true`.
|
||||||
@@ -68,32 +132,13 @@ fn intersect(comptime as: []const @Type(.enum_literal), comptime bs: []const @Ty
|
|||||||
return false;
|
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 {
|
|
||||||
comptime {
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn defaultLogFunction(
|
fn defaultLogFunction(
|
||||||
comptime tags: []const @Type(.enum_literal),
|
comptime tags: []const @Type(.enum_literal),
|
||||||
comptime format: []const u8,
|
comptime format: []const u8,
|
||||||
args: anytype,
|
args: anytype,
|
||||||
) void {
|
) void {
|
||||||
if (tags.len == 0) @compileError("Need at least one tag for logging.");
|
if (tags.len == 0) @compileError("Need at least one tag for logging.");
|
||||||
|
if (comptime !logEnabled(tags)) return;
|
||||||
|
|
||||||
comptime var prefix: []const u8 = "";
|
comptime var prefix: []const u8 = "";
|
||||||
comptime for (tags) |tag| {
|
comptime for (tags) |tag| {
|
||||||
@@ -106,3 +151,13 @@ fn defaultLogFunction(
|
|||||||
defer std.debug.unlockStderrWriter();
|
defer std.debug.unlockStderrWriter();
|
||||||
nosuspend stderr.print(prefix ++ ": " ++ format ++ "\n", args) catch return;
|
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