A powerful, fast, and beautifully simple logging library for Zig applications. Built from the ground up to handle everything from quick debugging to production-scale logging with grace.
Currently in active development - check the CHANGELOG for the latest updates
Compatible with Zig 0.14 and 0.15.0-dev.877+0adcfd60f
After working with logging libraries across different languages, I found myself constantly missing features or fighting with overly complex APIs. nexlog was born from the simple idea that logging should be powerful when you need it, but never get in your way when you don't.
Whether you're debugging a quick script or building a distributed system that needs to track requests across services, nexlog scales with your needs.
Core Logging
- Multiple log levels with beautiful colored output
- Automatic source location tracking (file, line, function)
- Rich metadata support with timestamps and thread IDs
- Zero-overhead when logging is disabled
Advanced Features
- Context tracking for following requests across your application
- Structured logging with JSON, logfmt, and custom formats
- Automatic file rotation with configurable size limits
- Custom handlers for sending logs anywhere
- High-performance async mode for demanding applications
- Type-safe API with full Zig compile-time guarantees
Add nexlog to your build.zig.zon
file:
.{
.name = "my-project",
.version = "0.1.0",
.dependencies = .{
.nexlog = .{
.url = "git+https://github.com/chrischtel/nexlog/",
.hash = "...", // Run `zig fetch` to get the hash
},
},
}
Quick install:
zig fetch --save git+https://github.com/chrischtel/nexlog/
For development versions, append #develop
to the URL.
Get up and running in three lines:
const std = @import("std");
const nexlog = @import("nexlog");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Initialize logger with minimal configuration
const logger = try nexlog.Logger.init(allocator, .{});
defer logger.deinit();
// Start logging with automatic source location tracking
logger.info("Application starting", .{}, nexlog.here(@src()));
logger.debug("Initializing subsystems", .{}, nexlog.here(@src()));
logger.warn("Resource usage high", .{}, nexlog.here(@src()));
logger.info("Application shutdown complete", .{}, nexlog.here(@src()));
}
Track user requests as they flow through your application. Perfect for debugging distributed systems or complex request handling:
// Set request context once at the entry point
nexlog.setRequestContext("req-12345", "user_login");
defer nexlog.clearContext();
logger.info("Processing user login for {s}", .{user_id}, nexlog.hereWithContext(@src()));
// All subsequent logs automatically include request context
try authenticateUser(logger, user_id);
try loadUserProfile(logger, user_id);
logger.info("User login completed successfully", .{}, nexlog.hereWithContext(@src()));
When you need machine-readable logs for monitoring and analytics:
// Configure formatter for JSON output
const config = format.FormatConfig{
.structured_format = .json,
.include_timestamp_in_structured = true,
.include_level_in_structured = true,
};
var formatter = try format.Formatter.init(allocator, config);
defer formatter.deinit();
// Create structured fields for rich context
const fields = [_]format.StructuredField{
.{ .name = "user_id", .value = "12345", .attributes = null },
.{ .name = "request_duration_ms", .value = "150", .attributes = null },
.{ .name = "endpoint", .value = "/api/login", .attributes = null },
};
logger.info("API request completed", .{}, &fields);
Never worry about log files filling up your disk:
var builder = nexlog.LogBuilder.init();
try builder
.setMinLevel(.debug)
.enableFileLogging(true, "logs/app.log")
.setMaxFileSize(10 * 1024 * 1024) // 10MB per file
.setMaxRotatedFiles(5) // Keep 5 backup files
.enableRotation(true)
.build(allocator);
// Automatically creates: app.log, app.log.1, app.log.2, etc.
Send logs to external services, databases, or custom destinations:
pub const CustomHandler = struct {
allocator: std.mem.Allocator,
messages: std.ArrayList([]const u8),
pub fn init(allocator: std.mem.Allocator) !*@This() {
const handler = try allocator.create(@This());
handler.* = .{
.allocator = allocator,
.messages = std.ArrayList([]const u8).init(allocator),
};
return handler;
}
pub fn log(self: *@This(), level: LogLevel, message: []const u8, metadata: LogMetadata) !void {
// Custom logic: store, forward, filter, transform, etc.
const stored_message = try self.allocator.dupe(u8, message);
try self.messages.append(stored_message);
}
};
Recent benchmarks show nexlog handles high-throughput scenarios gracefully:
Scenario | Logs/Second | Notes |
---|---|---|
Simple console logging | 41,297 | Basic text output |
JSON structured logging | 26,790 | Full structured format |
Logfmt output | 39,284 | Key-value format |
Large payloads (100 fields) | 8,594 | Complex structured data |
Production integration | 5,878 | Full pipeline with handlers |
Run the benchmarks yourself:
zig build bench
Configure nexlog to fit your specific needs:
var builder = nexlog.LogBuilder.init();
try builder
.setMinLevel(.debug)
.enableColors(true)
.setBufferSize(8192)
.enableFileLogging(true, "logs/app.log")
.setMaxFileSize(5 * 1024 * 1024)
.setMaxRotatedFiles(3)
.enableRotation(true)
.enableAsyncMode(true)
.build(allocator);
The examples/
directory contains working code for every feature:
basic_usage.zig
- Start here for simple loggingcontext_tracking.zig
- Request tracking across functionsstructured_logging.zig
- JSON, logfmt, and custom formatsfile_rotation.zig
- Automatic file managementcustom_handler.zig
- Build your own log destinationsjson_logging.zig
- Optimized JSON outputbenchmark.zig
- Performance testing and optimizationtime_travel.zig
- Advanced debugging featuresvisualization.zig
- Log analysis and visualization
I welcome contributions of all kinds. Whether it's fixing bugs, adding features, improving documentation, or sharing how you use nexlog in your projects.
Before starting work on a major feature, please open an issue to discuss the approach. This helps ensure your effort aligns with the project's direction and avoids duplicate work.
nexlog is available under the MIT License. See the LICENSE file for the complete text.