hendriknielaender/zlog
🪵 structured logging library for zig
c64bb43a3e32c5c62c02058ad7247e072301708d
5647630d7bff969414a0edc24c03c30aff34b101
WARNING
Still work in progress.
zlog is a high-performance, extensible logging library for Zig, designed to offer both simplicity and power in logging for system-level applications. Inspired by the best features of modern loggers and tailored for the Zig ecosystem, zlog
brings structured, efficient, and flexible logging to your development toolkit.
build.zig.zon
:.{
.name = "my-project",
.version = "1.0.0",
.dependencies = .{
.zlog = .{
.url = "https://github.com/hendriknielaender/zlog/archive/<COMMIT>.tar.gz",
.hash = "<HASH>",
},
},
}
Note: libxev is automatically included as a peer dependency of zlog for async logging support.
build.zig
:const zlog_module = b.dependency("zlog", opts).module("zlog");
exe.root_module.addImport("zlog", zlog_module);
const std = @import("std");
const zlog = @import("zlog");
pub fn main() !void {
// High-performance sync logger
var logger = zlog.default();
// Simple logging with trace context
const trace_ctx = zlog.TraceContext.init(true);
logger.infoWithTrace("Service started", trace_ctx, &.{
zlog.field.string("version", "1.0.0"),
zlog.field.uint("port", 8080),
});
// Different field types
logger.info("User action", &.{
zlog.field.string("user", "alice"),
zlog.field.uint("user_id", 12345),
zlog.field.boolean("success", true),
zlog.field.float("duration_ms", 45.7),
});
}
For maximum throughput in high-load scenarios:
const std = @import("std");
const zlog = @import("zlog");
const xev = @import("xev"); // Available through zlog's peer dependencies
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
// Setup event loop
var loop = try xev.Loop.init(.{});
defer loop.deinit();
// Create async logger
const config = zlog.Config{
.async_mode = true,
.async_queue_size = 1024,
.batch_size = 32,
.enable_simd = true,
};
const stdout = std.io.getStdOut().writer();
var logger = try zlog.Logger(config).initAsync(stdout.any(), &loop, gpa.allocator());
defer logger.deinit();
const trace_ctx = zlog.TraceContext.init(true);
// Log messages per second
for (0..1_000_000) |i| {
logger.infoWithTrace("High throughput message", trace_ctx, &.{
zlog.field.uint("iteration", i),
zlog.field.string("service", "api"),
});
// Process event loop periodically
if (i % 1000 == 0) {
try loop.run(.no_wait);
}
}
// Final flush
try loop.run(.no_wait);
}
const Config = zlog.Config{
.level = .debug, // Minimum level to log
.max_fields = 64, // Maximum fields per message
.buffer_size = 8192, // Buffer size for formatting
.async_mode = true, // Enable async logging
.async_queue_size = 2048, // Async queue size
.batch_size = 64, // Batch size for async writes
.enable_simd = true, // Enable SIMD optimizations
};
var logger = zlog.Logger(Config).init(writer);
All field types are strongly typed and validated at compile time:
// String fields
zlog.field.string("service", "api")
// Integer fields
zlog.field.int("temperature", -10)
zlog.field.uint("request_id", 12345)
// Floating point
zlog.field.float("duration_ms", 123.45)
// Boolean
zlog.field.boolean("success", true)
// Null values
zlog.field.null_value("optional_data")
zlog provides a hybrid compile-time and runtime redaction system for sensitive data:
// Define sensitive fields at compile-time
var logger = zlog.loggerWithRedaction(.{
.redacted_fields = &.{ "password", "api_key", "ssn" },
});
// These fields will be automatically redacted with zero runtime cost
logger.info("User login", &.{
zlog.field.string("username", "alice"),
zlog.field.string("password", "secret123"), // Output: [REDACTED:string]
});
var redaction_config = zlog.RedactionConfig.init(allocator);
defer redaction_config.deinit();
try redaction_config.addKey("credit_card");
try redaction_config.addKey("phone");
var logger = zlog.Logger(.{}).initWithRedaction(writer, &redaction_config);
// Combine compile-time and runtime redaction
const SecureLogger = zlog.LoggerWithRedaction(.{}, .{
.redacted_fields = &.{ "password", "token" }, // Compile-time
});
var logger = SecureLogger.initWithRedaction(writer, &runtime_config);
logger.trace("Detailed trace", &.{}); // Lowest priority
logger.debug("Debug info", &.{});
logger.info("Information", &.{}); // Default level
logger.warn("Warning", &.{});
logger.err("Error occurred", &.{});
logger.fatal("Fatal error", &.{}); // Highest priority
Run comprehensive performance analysis:
# Run all benchmarks
zig build benchmarks
# Individual components (if needed)
zig build test
Full distributed tracing support with pre-formatted hex strings for maximum performance:
const trace_ctx = zlog.TraceContext.init(true);
logger.infoWithTrace("Request processed", trace_ctx, &.{
zlog.field.string("service", "api"),
zlog.field.uint("status_code", 200),
});
Output:
{"level":"INFO","msg":"Request processed","trace":"a1b2c3d4e5f67890a1b2c3d4e5f67890","span":"1234567890abcdef","ts":1640995200000,"tid":12345,"service":"api","status_code":200}
zlog provides full W3C Trace Context specification compliance:
// Create trace context
const trace_ctx = zlog.TraceContext.init(true);
// Child spans maintain trace correlation
const child_ctx = trace_ctx.createChild(true);
// Extract for compatibility with other systems
const short_id = zlog.extract_short_from_trace_id(trace_ctx.trace_id);
Pre-formatted hex strings eliminate per-log conversion overhead, crucial for ultra-high throughput scenarios.
We welcome contributions that maintain our safety and performance standards:
Read our contributing guide for detailed development process.
# Build library
zig build
# Format code
zig fmt src/ benchmarks/
zlog is MIT licensed.