Skip to content

Colors & Styling ​

Logly colors console output via tint.zig. Two rendering modes plus off:

zig
var config = logly.Config.default();
config.colorMode = .horizontal; // whole record in level color (default)
config.colorMode = .vertical;   // per-column colors (below)
config.colorMode = .none;       // plain text

Horizontal ​

One level color for the complete record (existing whole-line behavior).

text
[entire log record uses one level color]
2026-10-07 12:00:00 [INFO] Application started

Vertical ​

Independent colors per field. Unset columns render uncolored; level falls back to the resolved level color.

zig
config.columnColors.timestamp = logly.Color.Tint.color.ansi4.blue;
config.columnColors.message = logly.Color.Tint.color.ansi4.yellow;
text
[timestamp: blue] [level: green] [message: yellow]
2026-10-07 12:00:00 [INFO] Application started

Precedence: color/globalColorDisplay off wins first, then colorMode, then column colors, then level colors, then defaults. Multiline messages keep the color across lines with a trailing reset; every field reset prevents leakage into later output.

Format Color Policy ​

Serialization is always valid on its own; color is a presentation layer applied afterwards, never inside the data. All rendering goes through tint.zig — Logly keeps no second ANSI implementation.

FormatNo colorHorizontalVertical
text, logfmtplainwhole record in level colorper-field column colors
json, ndjsonplain valid JSONwhole rendered line wrappedJSON re-rendered with per-key colors
syslog, syslog3164plainwhole rendered line wrappedwhole rendered line wrapped
msgpackraw bytesunsupported (bytes stay raw)unsupported (bytes stay raw)
custom templateplainwhole-line wrapper-field spans

Stripping ANSI from any colored text/JSON/syslog output recovers the exact uncolored bytes. msgpack output never contains color under any setting.

Per-sink selection: set .color = true to force presentation color even when piped, .color = false to disable, or leave null for automatic behavior (colored on interactive terminals, plain otherwise). A text console plus a plain JSON file plus a binary network sink can share one record without interfering, because presentation is computed per sink from the same record.

Platform Support ​

PlatformColor SupportNotes
Linux✅ NativeWorks out of the box
macOS✅ NativeWorks out of the box
Windows 10+✅ Requires initCall Terminal.enableAnsiColors()
VS Code Terminal✅ FullWorks on all platforms
Windows Console⚠️ LegacyMay need VT processing enabled

Enabling Colors ​

Windows Setup ​

On Windows, you must enable ANSI color support at the start of your program:

zig
const logly = @import("logly");

pub fn main() !void {
    // Enable ANSI colors on Windows (no-op on Linux/macOS)
     _ = logly.Terminal.enableAnsiColors();
    
    // ... rest of your code
}

Check Color Support ​

zig
if (logly.Terminal.supportsAnsiColors()) {
    // Terminal supports colors
}

Whole-Line Coloring ​

Logly colors the entire log line (timestamp, level, and message), not just the level tag. This provides better visual scanning:

[2024-01-15 10:30:45] [INFO] Application started      <- Entire line white
[2024-01-15 10:30:46] [WARNING] Low disk space        <- Entire line yellow
[2024-01-15 10:30:47] [ERROR] Connection failed       <- Entire line red

Built-in Level Colors ​

LevelPriorityANSI CodeColorPreview
TRACE536Cyan\x1b[36m
DEBUG1034Blue\x1b[34m
INFO2037White\x1b[37m
SUCCESS2532Green\x1b[32m
WARNING3033Yellow\x1b[33m
ERROR4031Red\x1b[31m
FAIL4535Magenta\x1b[35m
CRITICAL5091Bright Red\x1b[91m

ANSI Color Code Reference ​

Basic Colors (Foreground) ​

CodeColor
30Black
31Red
32Green
33Yellow
34Blue
35Magenta
36Cyan
37White

Bright Colors (Foreground) ​

CodeColor
90Bright Black (Gray)
91Bright Red
92Bright Green
93Bright Yellow
94Bright Blue
95Bright Magenta
96Bright Cyan
97Bright White

Background Colors ​

CodeColor
40Black Background
41Red Background
42Green Background
43Yellow Background
44Blue Background
45Magenta Background
46Cyan Background
47White Background

Text Styles ​

CodeStyle
0Reset
1Bold
2Dim
3Italic
4Underline
5Blink
7Reverse
8Hidden
9Strikethrough

Combining Codes ​

Combine multiple codes with semicolons:

ExampleDescription
"31"Red text
"31;1"Bold red text
"31;4"Underlined red text
"31;1;4"Bold underlined red
"97;41"White text on red background
"36;1"Bold cyan
"33;7"Yellow reverse (yellow background, black text)

Custom Level Colors ​

Create custom log levels with your own colors:

zig
const logly = @import("logly");

pub fn main() !void {
     _ = logly.Terminal.enableAnsiColors();
    
    var gpa = std.heap.DebugAllocator(.{}){};
    const allocator = gpa.allocator();
    
    const logger = try logly.Logger.init(allocator);
    defer logger.deinit();
    
    // Add custom levels with custom colors
    try logger.addCustomLevel("AUDIT", 35, "35");        // Magenta
    try logger.addCustomLevel("NOTICE", 22, "36;1");     // Bold Cyan
    try logger.addCustomLevel("ALERT", 48, "91;1");      // Bold Bright Red
    try logger.addCustomLevel("SECURITY", 55, "97;41"); // White on Red BG
    try logger.addCustomLevel("METRIC", 15, "32;1");     // Bold Green
    
    // Use custom levels
    try logger.custom("AUDIT", "User login event", @src());
    try logger.custom("NOTICE", "Important notice", @src());
    try logger.custom("ALERT", "High CPU usage detected", @src());
    try logger.custom("SECURITY", "Unauthorized access attempt", @src());
    try logger.customf("METRIC", "Response time: {d}ms", .{42}, @src());
}

Enhanced Color Options (v0.1.8) ​

Level Colors ​

Each log level has a default tint color. Level.defaultColor() returns a tint Color value; render it to an SGR sequence when writing output:

zig
const Level = logly.Level;

// Default color as a tint Color value.
const traceColor = Level.trace.defaultColor();

// Render to an escape sequence for output.
const seq = logly.Color.sequence(traceColor, .trueColor);
// seq.slice() gives e.g. "\x1b[36m" for trace.

tint Colors ​

All terminal colors come from tint.zig via logly.Color:

zig
const tint = logly.Color.Tint;

// Named ANSI colors.
const red = tint.color.ansi4.red;
const brightRed = tint.color.ansi4.brightRed;

// 256-color palette.
const orange = tint.color.ansi256.index(208);

// RGB colors.
const coral = tint.color.rgb(255, 127, 80);

// Render any color to a sequence.
const seq = logly.Color.sequence(red, .trueColor);

Parse user-supplied text (names, #rrggbb, or SGR params) with logly.Color.parse:

zig
const magenta = logly.Color.parse("magenta").?;
const custom = logly.Color.parse("38;5;196").?;

Theme Presets ​

Logly includes multiple color theme presets built on tint colors:

zig
const Formatter = logly.Formatter;

// Use preset themes (each field is a tint Color).
const defaultTheme = Formatter.Theme{};           // Standard colors
const brightTheme = Formatter.Theme.bright();     // Bright colors
const dimTheme = Formatter.Theme.dim();           // Dim colors
const minimalTheme = Formatter.Theme.minimal();   // Subtle grays
const neonTheme = Formatter.Theme.neon();         // Vivid 256-colors
const pastelTheme = Formatter.Theme.pastel();     // Soft colors
const darkTheme = Formatter.Theme.dark();         // Dark terminal optimized
const lightTheme = Formatter.Theme.light();       // Light terminal optimized

// Apply theme to formatter
var formatter = Formatter.init(allocator);
formatter.setTheme(Formatter.Theme.neon());

Custom Themes ​

Define per-level tint colors directly:

zig
const Theme = logly.Formatter.Theme;
const custom = Theme{
    .trace = logly.Color.parse("cyan").?,
    .err = logly.Color.Tint.color.rgb(255, 80, 80),
};
formatter.setTheme(custom);

Advanced CustomLevel Options ​

Create custom levels with full tint color control:

zig
const CustomLevel = logly.CustomLevel;

// Basic custom level with a tint color
const audit = CustomLevel.init("AUDIT", 35, logly.Color.parse("cyan").?);

// Styled custom level (explicit tint style)
const styled = CustomLevel.initStyled("STYLED", 45, .{
    .foreground = logly.Color.Tint.color.red,
    .underline = true,
});

// With background color
const alert = CustomLevel.initWithBackground(
    "ALERT", 50,
    logly.Color.Tint.color.ansi4.brightWhite,
    logly.Color.Tint.color.ansi4.red,
);

Color Configuration ​

Global Color Control ​

zig
var config = logly.Config.default();

// Master switch - disables colors everywhere
config.globalColorDisplay = false;
logger.configure(config);

// Re-enable colors
config.globalColorDisplay = true;
config.color = true;
logger.configure(config);

Per-Sink Color Control ​

zig
// Console sink with colors (default)
 _ = try logger.addSink(.{
    .color = true,  // Explicitly enable colors
});

// File sink without colors (default for files)
 _ = try logger.addSink(.{
    .path = "logs/app.log",
    .color = null,  // Auto-detect: false for files
});

// File sink WITH colors (for terminals that read log files)
 _ = try logger.addSink(.{
    .path = "logs/colored.log",
    .color = true,  // Force colors in file
});

Colors in Different Output Formats ​

Console Output (Default) ​

Colors are enabled by default for console output:

zig
try logger.info("White text");      // \x1b[37m...\x1b[0m
try logger.warning("Yellow text");  // \x1b[33m...\x1b[0m
try logger.err("Red text");         // \x1b[31m...\x1b[0m

JSON Output Is Never Colored ​

Serialization formats never contain ANSI sequences, even with colors enabled — color is a presentation concern for human-readable text only:

zig
var config = logly.Config.default();
config.format = .json;
config.color = true; // Has no effect on JSON output
logger.configure(config);

try logger.info("Plain JSON object, no escape codes");

Color applies to text and logfmt output. json, ndjson, syslog, syslog3164, and msgpack output is always plain.

File Output ​

By default, file sinks disable colors. To enable:

zig
 _ = try logger.addSink(.{
    .path = "logs/colored.log",
    .color = true,  // Enable ANSI codes in file
});

Note: Files with ANSI codes will display correctly in:

  • cat command on Linux/macOS
  • less -R command
  • VS Code with ANSI color extensions
  • Modern terminal emulators

Custom Format Strings with Colors ​

Custom format strings also support colors:

zig
var config = logly.Config.default();
config.logFormat = "{time} | {level} | {message}";
config.color = true;
logger.configure(config);

// Output: \x1b[33m2024-01-15 10:30:45 | WARNING | Message\x1b[0m
try logger.warning("Formatted warning");

Disabling Colors ​

For Production/Log Aggregation ​

zig
// Disable colors globally
var config = logly.Config.default();
config.color = false;
config.globalColorDisplay = false;
logger.configure(config);

For Specific Sinks ​

zig
// JSON file without colors (for log aggregation)
 _ = try logger.addSink(.{
    .path = "logs/app.json",
    .format = .json,
    .color = false,  // No ANSI codes
});

Complete Example ​

zig
const std = @import("std");
const logly = @import("logly");

pub fn main() !void {
    // Enable Windows ANSI support
     _ = logly.Terminal.enableAnsiColors();
    
    var gpa = std.heap.DebugAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();
    
    const logger = try logly.Logger.init(allocator);
    defer logger.deinit();
    
      // Add custom colored levels (tint colors)
      try logger.addCustomLevel("AUDIT", 35, logly.Color.parse("magenta").?);
      try logger.addCustomLevel("NOTICE", 22, logly.Color.parse("cyan").?);
      try logger.addCustomLevel("HIGHLIGHT", 52, logly.Color.parse("yellow").?);
    
    // Standard levels (all colored)
    try logger.trace("Cyan trace message");
    try logger.debug("Blue debug message");
    try logger.info("White info message");
    try logger.success("Green success message");
    try logger.warning("Yellow warning message");
    try logger.err("Red error message");
    try logger.fail("Magenta fail message");
    try logger.critical("Bright red critical message");
    
    // Custom levels
    try logger.custom("AUDIT", "Magenta audit message");
    try logger.custom("NOTICE", "Bold cyan notice");
    try logger.custom("HIGHLIGHT", "Yellow reverse highlight");
    
    // Add file sink with colors
     _ = try logger.addSink(.{
        .path = "logs/colored.log",
        .color = true,
    });
    
    // Add JSON sink without colors
     _ = try logger.addSink(.{
        .path = "logs/app.json",
        .format = .json,
        .color = false,
    });
    
    try logger.info("This goes to console (colored) and both files");
}

Structured formats and presentation ​

Color never corrupts serialized data. For json, ndjson, syslog, and syslog3164 the record is serialized first and color is applied around the result, so stripping ANSI recovers the exact document — PRI, timestamp, hostname, and structured data included.

FormatNo colorHorizontalVerticalCustom / level colors
textyesyesyesyes
logfmtyesyesyesyes
jsonyesyesyesyes
ndjsonyesyesyesyes
syslog / syslog3164yesyeswhole-recordyes
msgpackyespresentation onlypresentation onlypresentation only

A JSON file sink writes a single array document ([, records, ]), so a colored record is wrapped inside the array and the file stays valid JSON.

msgpack is never colored. Binary payloads stay byte-exact: no ANSI, no trailing newline, and length-prefixed framing is preserved.

Color is per sink ​

Each sink decides independently whether to present color, so enabling console color never injects ANSI into a file or network sink.

TargetDefaultHow to enable
ConsoleAutoColored when stdout is a TTY; plain when piped, redirected, or in CI
FileOffcolor = true
NetworkOffcolor = true
MessagePackNeverNot supported
zig
_ = try logger.addSink(.{ .name = "console", .color = true });
_ = try logger.addSink(.{ .path = "logs/app.log", .color = false });
_ = try logger.addSink(.{ .path = "logs/app.json", .format = .json, .color = false });

Async logging ​

Async mode queues the uncolored serialized record together with its resolved level color. Presentation is applied per sink at write time, which means background workers cannot push console color into files or network sinks, and ANSI sequences cannot interleave between records from different workers.

See Async for the queue and worker model.

Released under the MIT License.