Skip to content

Commit

Permalink
add ability to encode logs as JSON (in addition to the existing logfm…
Browse files Browse the repository at this point in the history
…t support)
  • Loading branch information
karlseguin committed Dec 28, 2023
1 parent eb10e62 commit e3cfd26
Show file tree
Hide file tree
Showing 10 changed files with 1,910 additions and 416 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
F=
.PHONY: t
t:
zig build test --summary all
TEST_FILTER="${F}" zig build test -freference-trace --summary all
1 change: 1 addition & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub fn build(b: *std.Build) !void {
.root_source_file = .{ .path = "src/logz.zig" },
.target = target,
.optimize = optimize,
.test_runner = "test_runner.zig",
});
const run_test = b.addRunArtifact(lib_test);
run_test.has_side_effects = true;
Expand Down
22 changes: 18 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Structured Logging for Zig

logz is an opinionated structured logger that outputs to stdout using the logfmt format. It aims to minimize runtime memory allocation by using a pool of pre-allocated loggers.
logz is an opinionated structured logger that outputs to stdout using logfmt or JSON. It aims to minimize runtime memory allocation by using a pool of pre-allocated loggers.

# Installation
This library supports native Zig module (introduced in 0.11). Add a "logz" dependency to your `build.zig.zon`.
Expand Down Expand Up @@ -135,11 +135,13 @@ pub const Config = struct {
// Where to write the output: can be either .stdout or .stderr
output: Output = .stdout,
encoding: Encoding = .kv, // or .json
};
```

### Timestamp and Level
When using the `debug`, `info`, `warn`, `err` or `fatal` functions, logs will always begin with `@ts=$MILLISECONDS_SINCE_JAN1_1970_UTC @l=$LEVEL`, such as: `@ts=1679473882025 @l=INFO`.
When using the `debug`, `info`, `warn`, `err` or `fatal` functions, logs will always begin with `@ts=$MILLISECONDS_SINCE_JAN1_1970_UTC @l=$LEVEL`, such as: `@ts=1679473882025 @l=INFO`. With JSON encoding, the object will always have the `"@ts"` and `"@l"` fields.

### Logger Life cycle
The logger is implicitly returned to the pool when `log`, `logTo` or `tryLog` is called. In rare cases where `log`, `logTo` or `tryLog` are not called, the logger must be explicitly released using its `release()` function:
Expand All @@ -148,6 +150,8 @@ The logger is implicitly returned to the pool when `log`, `logTo` or `tryLog` is
// This is a contrived example to show explicit release
var l = logz.info();
_ = l.string("key", "value");
// actually, on second thought, I don't want to log anything
l.release();
```

Expand Down Expand Up @@ -205,7 +209,7 @@ pub fn main() !void {
### Prefixes
A pool can be configured with a prefix by setting the `prefix` field of the configuration. When set, all log entries generated by loggers of this pool will contain the prefix.

The prefix is written as-is, with no escape and no enforcement of being a key=value.
The prefix is written as-is.

```zig
// prefix can be anything []const u8. It doesn't have to be a key=value
Expand All @@ -218,8 +222,18 @@ p.info().boolean("tea", true).log();

The above will generate a log line: `keemun @ts=TIMESTAMP @l=INFO tea=Y"`

When using `.json` encoding, your prefix must begin the object:

```zig:
var p = try logz.Pool.init(allocator, .{.prefix = "=={"});
defer p.deinit();
p.info().boolean("tea", true).log();
```
The above will generate a log line: `=={"@ts":TIMESTAMP, "@l":"INFO", "tea":true}`

### Multi-Use Logger
Rather than having a logger automatically returned to the pool when `.log()` or `tryLog()` are called, it is possible to flag the logger for "multi-use". In such cases, the logger must be explicitly returned to the pool using `logger.release()`. This can be enabled by calling `multiuse` on the logger. Important, and the reason this feature exists, is logs by the same logger will share the same attributes up to the point where multiuse was called:
Rather than having a logger automatically returned to the pool when `.log()` or `tryLog()` are called, it is possible to flag the logger for "multi-use". In such cases, the logger must be explicitly returned to the pool using `logger.release()`. This can be enabled by calling `multiuse` on the logger. Logs created by the logger will share the same attributes up to the point where multiuse was called:

```zig
var logger = logz.logger().string("request_id", request_id).multiuse();
Expand Down
6 changes: 6 additions & 0 deletions src/config.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@ pub const Config = struct {
level: logz.Level = .Info,
prefix: ?[]const u8 = null,
output: Output = .stdout,
encoding: Encoding = .logfmt,

const Output = enum {
stdout,
stderr,
};

const Encoding = enum {
json,
logfmt,
};
};
Loading

0 comments on commit e3cfd26

Please sign in to comment.