Advanced Customizations Guide ​
This guide covers Logly's advanced customization features that allow you to tailor logging behavior to your specific needs.
Global Logs Root Path ​
The logs root path feature allows you to specify a single root directory where all log files will be stored, making it easy to manage logs from multiple sinks.
Configuration ​
var config = logly.Config.default();
config.logs_root_path = "./logs"; // All file sinks will be stored in ./logs
const logger = try logly.Logger.initWithConfig(allocator, config);
// Adding sinks with relative paths
_ = try logger.addSink(logly.SinkConfig.file("application.log"));
_ = try logger.addSink(logly.SinkConfig.file("errors.log"));
_ = try logger.addSink(logly.SinkConfig.file("debug.log"));Behavior ​
- Automatic Directory Creation: If the root path doesn't exist, it will be automatically created
- Path Resolution: File sink paths are automatically prepended with the root path
- Non-intrusive: If directory creation fails, logging continues without interruption
- Optional: If
logs_root_pathis not set, file sinks use absolute or relative paths as specified
Example Output ​
./logs/
├── application.log
├── errors.log
└── debug.logFormat Structure Customization ​
Customize how log messages are formatted and structured using FormatStructureConfig.
Configuration ​
var config = logly.Config.default();
config.format_structure = .{
.message_prefix = ">>> ", // Add prefix to each message
.message_suffix = " <<<", // Add suffix to each message
.field_separator = " | ", // Separator between fields
.enable_nesting = true, // Enable hierarchical formatting
.nesting_indent = " ", // Indentation for nested fields
.include_empty_fields = false, // Skip null/empty fields
.placeholder_open = "{", // Custom placeholder syntax
.placeholder_close = "}",
};
const logger = try logly.Logger.initWithConfig(allocator, config);Available Options ​
| Option | Purpose | Example |
|---|---|---|
message_prefix | Text prepended to messages | ">>> " |
message_suffix | Text appended to messages | " <<<" |
field_separator | Separator between log fields | " | " |
enable_nesting | Support nested/hierarchical logs | true |
nesting_indent | Indentation for nested items | " " (2 spaces) |
include_empty_fields | Include null fields in output | false |
placeholder_open/close | Custom placeholder syntax | "[[", "]]" |
Per-Level Color Customization ​
Define custom ANSI colors for each log level independently.
Configuration ​
var config = logly.Config.default();
config.level_colors = .{
.trace_color = "\x1b[36m", // Cyan
.debug_color = "\x1b[35m", // Magenta
.info_color = "\x1b[34m", // Blue
.success_color = "\x1b[32m", // Green
.warning_color = "\x1b[33m", // Yellow
.error_color = "\x1b[31m", // Red
.fail_color = "\x1b[31;1m", // Bold Red
.critical_color = "\x1b[1;31m", // Bold Red
.use_rgb = false, // Standard ANSI (not RGB)
.support_background = false, // Text colors only
.reset_code = "\x1b[0m", // Reset to default
};
const logger = try logly.Logger.initWithConfig(allocator, config);Common ANSI Color Codes ​
Standard Colors (8-color mode):
"\x1b[30m"- Black"\x1b[31m"- Red"\x1b[32m"- Green"\x1b[33m"- Yellow"\x1b[34m"- Blue"\x1b[35m"- Magenta"\x1b[36m"- Cyan"\x1b[37m"- White
Bright Colors (16-color mode):
"\x1b[90m"- Bright Black"\x1b[91m"- Bright Red"\x1b[92m"- Bright Green"\x1b[93m"- Bright Yellow"\x1b[94m"- Bright Blue"\x1b[95m"- Bright Magenta"\x1b[96m"- Bright Cyan"\x1b[97m"- Bright White
Styles:
"\x1b[1;31m"- Bold Red"\x1b[2;31m"- Dim Red"\x1b[4;31m"- Underline Red"\x1b[5;31m"- Blinking Red"\x1b[7;31m"- Inverted Red
Highlighters and Alerts ​
Configure pattern matching and alerting for specific log messages.
Configuration ​
var config = logly.Config.default();
config.highlighters = .{
.enabled = true,
.alert_on_match = true,
.alert_min_severity = .warning,
.log_matches = true,
.max_matches_per_message = 10,
};
const logger = try logly.Logger.initWithConfig(allocator, config);Options ​
| Option | Purpose |
|---|---|
enabled | Enable/disable highlighter system |
alert_on_match | Trigger alerts when patterns match |
alert_min_severity | Minimum severity to trigger alerts |
log_matches | Log pattern matches as separate records |
patterns | Array of HighlightPattern structures |
max_matches_per_message | Max patterns to match per message |
Pattern Definition ​
pub const HighlightPattern = struct {
name: []const u8, // Pattern identifier
pattern: []const u8, // Text or regex to match
is_regex: bool = false, // Is this a regex pattern?
highlight_color: []const u8, // Color for highlights
severity: AlertSeverity, // Severity level
metadata: ?[]const u8 = null, // Custom metadata
};Alert Severity Levels ​
pub const AlertSeverity = enum {
trace,
debug,
info,
success,
warning,
err,
fail,
critical,
};Diagnostics Custom Path ​
Store system diagnostics in a separate file from regular logs.
Configuration ​
var config = logly.Config.default();
config.diagnostics_output_path = "./logs/diagnostics.log";
config.logs_root_path = "./logs";
config.emit_system_diagnostics_on_init = true;
const logger = try logly.Logger.initWithConfig(allocator, config);Behavior ​
- Diagnostics are emitted at logger initialization if configured
- Structured context fields (
diag.os,diag.cpu, etc.) are available for custom formatting - Use the standard
logSystemDiagnostics()method to emit on demand
Available Diagnostics Fields ​
When using custom log formats, these fields are available:
{diag.os}- Operating system name (windows, linux, macos){diag.arch}- Architecture (x86_64, aarch64, etc.){diag.cpu}- CPU model name{diag.cores}- Number of logical cores{diag.ram_total_mb}- Total RAM in megabytes{diag.ram_avail_mb}- Available RAM in megabytes
Example with Custom Format ​
var config = logly.Config.default();
config.log_format = "[{level}] {message} | CPU={diag.cpu} ({diag.cores} cores)";
config.emit_system_diagnostics_on_init = true;
const logger = try logly.Logger.initWithConfig(allocator, config);
try logger.logSystemDiagnostics(@src());
// Output:
// [INFO] [DIAGNOSTICS] os=windows arch=x86_64 cpu=rocketlake cores=16 ... |
// CPU=rocketlake (16 cores)Complete Example ​
Here's a comprehensive example combining all customization features:
const std = @import("std");
const logly = @import("logly");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var config = logly.Config.default();
// Global root path
config.logs_root_path = "./logs";
// Format structure
config.format_structure = .{
.message_prefix = "[APP] ",
.field_separator = " | ",
.enable_nesting = true,
};
// Custom colors
config.level_colors = .{
.info_color = "\x1b[34m", // Blue
.warning_color = "\x1b[33m", // Yellow
.error_color = "\x1b[31m", // Red
};
// Highlighters
config.highlighters = .{
.enabled = true,
.alert_on_match = true,
.log_matches = true,
};
// Diagnostics
config.emit_system_diagnostics_on_init = true;
const logger = try logly.Logger.initWithConfig(allocator, config);
defer logger.deinit();
// Add sinks (automatically use logs_root_path)
_ = try logger.addSink(logly.SinkConfig.file("application.log"));
_ = try logger.addSink(logly.SinkConfig.file("errors.log"));
// Log messages
try logger.info("Application started", @src());
try logger.warning("Resource usage high", @src());
try logger.err("Connection failed", @src());
// Emit diagnostics
try logger.logSystemDiagnostics(@src());
}Combining with Other Features ​
All customization features work seamlessly with Logly's other capabilities:
- Thread Pool: Customizations apply to all threaded log writes
- Async Logging: Format customizations work with buffered output
- Rotation: Logs are rotated within the configured root path
- Compression: Compressed files are stored in the root path
- Filtering: Color and format customizations apply to filtered logs
- JSON Output: Customizations don't affect JSON structure
Performance Considerations ​
- Format Structure: Minimal overhead; applies at formatting stage
- Colors: ANSI codes add small amounts to output size
- Highlighters: Pattern matching has O(n) complexity per message
- Root Path: Single directory creation at logger init, no runtime overhead
