---
url: /logly.zig/api/logger.md
description: >-
  Complete API reference for Logly.zig Logger struct. Covers initialization, log
  methods, sink management, filtering, sampling, redaction, metrics, and
  distributed tracing APIs.
---

# Logger API

The `Logger` struct is the central component of the Logly library, orchestrating all logging operations, sink management, configuration, and enterprise features like filtering, sampling, redaction, metrics, and distributed tracing.

## Quick Reference: Method Aliases

### Sink Management Aliases

| Full Method | Alias(es) | Description |
|-------------|-----------|-------------|
| `addSink()` | `add()` | Add a new sink |
| `removeSink()` | `remove()` | Remove a sink by ID |
| `removeAllSinks()` | `removeAll()`, `clear()` | Remove all sinks |
| `getSinkCount()` | `count()`, `sinkCount()` | Get number of sinks |
| `enableSink()` | `enable()` | Enable a sink by ID |
| `disableSink()` | `disable()` | Disable a sink by ID |
| `getSink()` | `sink()` | Get sink by ID |

### Logging Level Aliases

| Full Method | Alias(es) | Level | Description |
|-------------|-----------|-------|-------------|
| `trace()` | - | TRACE | Verbose debugging |
| `debug()` | - | DEBUG | Debug information |
| `info()` | - | INFO | General information |
| `notice()` | `note()` | NOTICE | Important notices |
| `success()` | - | SUCCESS | Success messages |
| `warning()` | `warn()` | WARNING | Warning messages |
| `err()` | `@"error"()` | ERROR | Error messages |
| `fail()` | `failure()` | FAIL | Failure messages |
| `critical()` | `crit()` | CRITICAL | Critical errors |
| `fatal()` | `panic()` | FATAL | Fatal errors |

### Formatted Logging Aliases

| Full Method | Alias(es) | Description |
|-------------|-----------|-------------|
| `tracef()` | - | Formatted TRACE log |
| `debugf()` | - | Formatted DEBUG log |
| `infof()` | - | Formatted INFO log |
| `noticef()` | `notef()` | Formatted NOTICE log |
| `successf()` | - | Formatted SUCCESS log |
| `warningf()` | `warnf()` | Formatted WARNING log |
| `errf()` | `errorf()` | Formatted ERROR log |
| `failf()` | `failuref()` | Formatted FAIL log |
| `criticalf()` | `critf()` | Formatted CRITICAL log |
| `fatalf()` | `panicf()` | Formatted FATAL log |
| `customf()` | - | Formatted custom level log |

### Lifecycle Aliases

| Full Method | Alias(es) | Description |
|-------------|-----------|-------------|
| `init()` | `create()` | Initialize logger |
| `deinit()` | `destroy()` | Deinitialize logger |

### Other Aliases

| Full Method | Alias(es) | Description |
|-------------|-----------|-------------|
| `getStats()` | `stats()` | Get logger statistics |
| `getRecordCount()` | `recordCount()` | Get total record count |
| `getUptime()` | `uptime()` | Get logger uptime in seconds |
| `scoped()` | - | Create scoped logger |
| `ctx()` | `context()` | Get context logger |
| `with()` | - | Get persistent context logger |

## Lifecycle Methods

### `init(allocator: std.mem.Allocator) !*Logger`

Initializes a new `Logger` instance with default configuration.

* **allocator**: The memory allocator used for internal structures.
* **Returns**: A pointer to the initialized `Logger` or an error.

### `initWithConfig(allocator: std.mem.Allocator, config: Config) !*Logger`

Initializes a new `Logger` instance with a specific configuration preset. If `config.io` is set, that I/O handle is used; otherwise, it defaults to `logly.defaultIo()`.

* **allocator**: The memory allocator used for internal structures.
* **config**: The configuration to use (e.g., `ConfigPresets.production()`).
* **Returns**: A pointer to the initialized `Logger` or an error.

### `initWithIo(allocator: std.mem.Allocator, io_handle: std.Io, config: Config) !*Logger`

Initializes a new `Logger` instance with an explicit `std.Io` handle and configuration preset.

* **allocator**: The memory allocator used for internal structures.
* **io_handle**: The explicit `std.Io` handle to use for all I/O operations.
* **config**: The configuration to use.
* **Returns**: A pointer to the initialized `Logger` or an error.

### Allocator Strategy

`Logger.init(...)` and `Logger.initWithConfig(...)` accept any allocator implementing `std.mem.Allocator`.

* Use `std.heap.DebugAllocator` for robust general-purpose ownership and leak detection.

```zig
var gpa = std.heap.DebugAllocator(.{}){};
defer _ = gpa.deinit();

const logger = try logly.Logger.initWithConfig(gpa.allocator(), logly.Config.default());
defer logger.deinit();
```

### `deinit() void`

Deinitializes the logger, freeing all allocated resources including sinks, context maps, custom levels, and enterprise components.

### `configure(config: Config) void`

Updates the global configuration of the logger in a thread-safe manner.

## Distributed Logging

### `withTrace(traceId: []const u8, spanId: ?[]const u8) DistributedLogger`

Creates a lightweight `DistributedLogger` handle that wraps the main logger but automatically injects the specified trace context into every log message. This is the preferred way to handle distributed tracing in concurrent environments (like request handlers).

```zig
// In a request handler
const reqLogger = logger.withTrace(header_trace_id, header_span_id);
try reqLogger.info("Processing request", null);
// Result: { "trace_id": "...", "span_id": "...", "message": "Processing request" }
```

### `withTraceparent(traceparent: []const u8) !DistributedLogger`

Parses an incoming W3C `traceparent` header and returns a request-scoped `DistributedLogger`.

* Returns `LoggerError.InvalidTraceparent` if the header is malformed.

```zig
const incoming = "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01";
const reqLogger = try logger.withTraceparent(incoming);
try reqLogger.info("Continuing distributed trace", null);
```

### `setTraceContextFromTraceparent(traceparent: []const u8) !void`

Parses a W3C `traceparent` header and sets logger global trace context.

* Returns `LoggerError.InvalidTraceparent` for invalid values.
* Useful when using legacy/global trace context APIs.

### `getTraceparentHeader(allocator: std.mem.Allocator) !?[]u8`

Formats the current global logger trace context as a W3C `traceparent` header string.

* Returns `null` when trace context is incomplete.
* Returned string must be freed by the caller.

### `setTraceContext(traceId: []const u8, spanId: ?[]const u8) !void`

**Legacy**. Sets the global trace context for the logger. This affects *all* subsequent logs from this logger instance. Not recommended for multi-threaded applications where different threads handle different requests.

### `clearTraceContext() void`

**Legacy**. Clears the global trace context.

## Callbacks

The `Logger` supports several callbacks for monitoring and extending behavior. These are set directly on the `Logger` instance fields.

### `onRecordLogged: ?*const fn (Level, []const u8, *const Record) void`

Invoked when a record is successfully logged.

* **Parameters**: `level`, `message`, `record`

### `onRecordFiltered: ?*const fn ([]const u8, *const Record) void`

Invoked when a record is filtered/dropped before output (e.g., by level or filter).

* **Parameters**: `reason`, `record`

### `onSinkError: ?*const fn ([]const u8, []const u8) void`

Invoked when a sink encounters an error.

* **Parameters**: `sinkName`, `errorMsg`

### `onLoggerInitialized: ?*const fn (*const LoggerStats) void`

Invoked when the logger is initialized.

* **Parameters**: `logger_stats`

### `onLoggerDestroyed: ?*const fn (*const LoggerStats) void`

Invoked when the logger is destroyed.

* **Parameters**: `final_stats`

### LoggerStats

The `LoggerStats` struct provides comprehensive statistics for logging operations with cross-platform atomic counters:

```zig
pub const LoggerStats = struct {
    /// Total number of records successfully logged.
    totalRecordsLogged: std.atomic.Value(Constants.AtomicUnsigned),
    /// Number of records filtered/dropped before output.
    recordsFiltered: std.atomic.Value(Constants.AtomicUnsigned),
    /// Number of sink write errors encountered.
    sinkErrors: std.atomic.Value(Constants.AtomicUnsigned),
    /// Number of currently active sinks.
    activeSinks: std.atomic.Value(u32),
    /// Total bytes written across all sinks.
    bytesWritten: std.atomic.Value(Constants.AtomicUnsigned),

    /// Calculate records per second (requires elapsed seconds).
    pub fn recordsPerSecond(self: *const LoggerStats, elapsedSeconds: f64) f64;

    /// Calculate average bytes per record.
    pub fn avgBytesPerRecord(self: *const LoggerStats) f64;

    /// Calculate filter rate (0.0 - 1.0).
    pub fn filterRate(self: *const LoggerStats) f64;

    /// Calculate sink error rate (0.0 - 1.0).
    pub fn sinkErrorRate(self: *const LoggerStats) f64;

    /// Returns true if any records were filtered.
    pub fn hasFiltered(self: *const LoggerStats) bool;

    /// Returns true if any sink errors occurred.
    pub fn hasSinkErrors(self: *const LoggerStats) bool;

    /// Returns total records logged as u64.
    pub fn getTotalLogged(self: *const LoggerStats) u64;

    /// Returns filtered records count as u64.
    pub fn getFiltered(self: *const LoggerStats) u64;

    /// Returns sink errors count as u64.
    pub fn getSinkErrors(self: *const LoggerStats) u64;

    /// Returns bytes written as u64.
    pub fn getBytesWritten(self: *const LoggerStats) u64;

    /// Returns active sinks count as u32.
    pub fn getActiveSinks(self: *const LoggerStats) u32;

    /// Calculate bytes per second (requires elapsed time in ms).
    pub fn bytesPerSecond(self: *const LoggerStats, elapsedMs: i64) f64;
};
```

**Usage Example:**

```zig
const stats = logger.getStats();

// Basic stats
std.debug.print("Total logged: {d}\n", .{stats.getTotalLogged()});
std.debug.print("Bytes written: {d}\n", .{stats.getBytesWritten()});

// Rate calculations
std.debug.print("Filter rate: {d:.2}%\n", .{stats.filterRate() * 100});
std.debug.print("Error rate: {d:.2}%\n", .{stats.sinkErrorRate() * 100});

// State checks
if (stats.hasSinkErrors()) {
    std.debug.print("Sink errors detected!\n", .{});
}

// Throughput (with elapsed time)
const elapsedMs = std.time.milliTimestamp() - startTime;
std.debug.print("Throughput: {d:.2} bytes/sec\n", .{stats.bytesPerSecond(elapsedMs)});
```

### `logCallback: ?*const fn (*const Record) anyerror!void`

A generic callback invoked for every log record. Can be used for custom processing or integration with other systems.

## Sink Management

### `addSink(config: SinkConfig) !usize`

Adds a new output sink (e.g., console, file) with the specified configuration.

* **Returns**: The unique ID of the added sink.
* **Alias**: `add()`

```zig
// Both are equivalent
 _ = try logger.addSink(.{ .path = "app.log" });
 _ = try logger.add(.{ .path = "app.log" });
```

### `removeSink(id: usize) void`

Removes a sink by its ID.

* **Alias**: `remove()`

### `removeAllSinks() usize`

Removes all sinks and returns the count of removed sinks.

* **Aliases**: `removeAll()`, `clear()`

### `enableSink(id: usize) void`

Enables a specific sink by its ID, allowing it to process log records.

### `disableSink(id: usize) void`

Disables a specific sink by its ID, preventing it from processing log records.

### `getSinkCount() usize`

Returns the current number of sinks.

* **Aliases**: `count()`, `sinkCount()`

### `enableAsync() void`

Enables async logging if an async logger is configured. This allows log records to be processed asynchronously in the background.

### `disableAsync() void`

Disables async logging if an async logger is configured. Forces synchronous processing of log records.

### `isAsyncEnabled() bool`

Returns `true` if async logging is enabled and running, `false` otherwise.

### `enableAutoFlush() void`

Enables automatic flushing of all sinks after every log operation. Ensures immediate output visibility but may impact performance.

### `disableAutoFlush() void`

Disables automatic flushing. Sinks will only flush when their buffers are full or when manually flushed.

### `isAutoFlushEnabled() bool`

Returns `true` if auto-flush is enabled, `false` otherwise.

## Context Management

### `bind(key: []const u8, value: std.json.Value) !void`

Binds a structured context variable to the logger. These variables are included in every log record (especially useful for JSON output).

```zig
try logger.bind("user_id", .{ .string = "usr_12345" });
try logger.bind("request_id", .{ .string = "req_abc" });
```

### `unbind(key: []const u8) void`

Removes a previously bound context variable.

### `clearBindings() void`

Removes all bound context variables.

## Enterprise Features

### Filtering

#### `setFilter(filter: *Filter) void`

Sets a filter for rule-based log filtering. Allows filtering by level, message patterns, modules, and more.

```zig
var filter = logly.Filter.init(allocator);
defer filter.deinit();
try filter.addMinLevel(.warning);
logger.setFilter(&filter);
```

### Sampling

#### `setSampler(sampler: *Sampler) void`

Sets a sampler for log sampling and rate limiting. Useful for high-volume logging scenarios.

```zig
var sampler = logly.Sampler.init(allocator, logly.SamplerPresets.sample10Percent());
defer sampler.deinit();
logger.setSampler(&sampler);
```

### Redaction

#### `setRedactor(redactor: *Redactor) void`

Sets a redactor for sensitive data masking in log messages.

```zig
var redactor = logly.Redactor.init(allocator);
defer redactor.deinit();
try redactor.addPattern("password", .keyword, "password", "[REDACTED]");
logger.setRedactor(&redactor);
```

### Metrics

#### `enableMetrics() void`

Enables metrics collection for logging performance monitoring.

```zig
logger.enableMetrics();
```

#### `getMetrics() ?Metrics.Snapshot`

Returns a snapshot of current logging metrics, or null if metrics are not enabled.

```zig
if (logger.getMetrics()) |metrics| {
    std.debug.print("Total records: {}\n", .{metrics.totalRecords});
    std.debug.print("Errors: {}\n", .{metrics.errorCount});
}
```

## Distributed Tracing

### `withTrace(traceId: []const u8, spanId: ?[]const u8) DistributedLogger`

Creates a request-scoped `DistributedLogger` without mutating global logger context.

```zig
const reqLogger = logger.withTrace("4bf92f3577b34da6a3ce929d0e0e4736", "00f067aa0ba902b7");
try reqLogger.info("Incoming request", @src());
```

### `withTraceparent(traceparent: []const u8) !DistributedLogger`

Builds a request-scoped distributed logger directly from an incoming W3C `traceparent` header.

```zig
const incoming = "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01";
const reqLogger = try logger.withTraceparent(incoming);
```

Returns `LoggerError.InvalidTraceparent` on malformed input.

### `setTraceContext(traceId: []const u8, spanId: ?[]const u8) !void`

Sets the trace context for distributed tracing. All subsequent log records will include these IDs.

```zig
try logger.setTraceContext("trace-abc-123", "span-xyz-789");
```

### `setTraceContextFromTraceparent(traceparent: []const u8) !void`

Parses and applies a W3C `traceparent` header to global logger trace context.

```zig
const incoming = "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01";
try logger.setTraceContextFromTraceparent(incoming);
```

### `getTraceparentHeader(allocator: std.mem.Allocator) !?[]u8`

Returns current global context as a W3C `traceparent` header.

```zig
if (try logger.getTraceparentHeader(allocator)) |header| {
    defer allocator.free(header);
    // Forward header to downstream services
}
```

### `setCorrelationId(correlationId: []const u8) !void`

Sets a correlation ID for request correlation across services.

```zig
try logger.setCorrelationId("corr-12345");
```

### `clearTraceContext() void`

Clears all trace context (traceId, spanId, correlationId).

### `startSpan(name: []const u8) !SpanContext`

Creates a new span for tracing. The span automatically generates a span ID and tracks duration.

```zig
const span = try logger.startSpan("database_query");
defer span.end(null) catch {};

// Your operation here
try logger.info("Executing query");
```

### `DistributedLogger.child(childSpanId: []const u8) DistributedLogger`

Returns a child distributed logger that reuses the same `traceId` and replaces `spanId`.

```zig
const child = reqLogger.child("7a085853722dc6d2");
try child.debug("Nested operation", @src());
```

### `DistributedLogger.inModule(module: []const u8) DistributedLogger`

Returns a distributed logger bound to a specific module name for module-level filtering/routing.

```zig
const db = reqLogger.inModule("database.query");
try db.info("Executing SQL", @src());
```

## Module-Level Logging

### `setModuleLevel(module: []const u8, level: Level) !void`

Sets a log level filter for a specific module.

```zig
try logger.setModuleLevel("database", .debug);
try logger.setModuleLevel("http.server", .info);
```

### `getModuleLevel(module: []const u8) ?Level`

Gets the log level for a specific module, or null if not set.

### `scoped(module: []const u8) ScopedLogger`

Returns a scoped logger for a specific module.

```zig
const dbLogger = logger.scoped("database");
try dbLogger.info("Connection established");
```

## Custom Levels

### `addCustomLevel(name: []const u8, priority: u8, color: []const u8) !void`

Registers a custom log level with a name, priority, and ANSI color code.
**Returns error.LevelAlreadyExists if level name already exists.**

```zig
// Color code only (no \x1b[ prefix needed)
try logger.addCustomLevel("audit", 35, "35");     // Magenta
try logger.addCustomLevel("security", 55, "91");  // Bright red
try logger.addCustomLevel("notice", 22, "36;1");  // Bold cyan
try logger.addCustomLevel("alert", 42, "31;4");   // Underline red

// Handle duplicate error
logger.addCustomLevel("audit", 40, "31") catch |err| {
    if (err == error.LevelAlreadyExists) {
        std.debug.print("Level already exists!\n", .{});
    }
};
```

### `updateCustomLevel(name: []const u8, priority: u8, color: []const u8) !void`

Updates an existing custom level, or creates it if it doesn't exist.
Use this when you want to allow updates without errors.

```zig
// This will update if exists, or create if not
try logger.updateCustomLevel("audit", 40, "91;1");
```

### `hasCustomLevel(name: []const u8) bool`

Checks if a custom level with the given name exists.

```zig
if (logger.hasCustomLevel("audit")) {
    try logger.custom("audit", "User action", @src());
}
```

### `getCustomLevelCount() usize`

Returns the count of registered custom levels.

```zig
std.debug.print("Custom levels: {}\n", .{logger.getCustomLevelCount()});
```

**Color Code Reference:**

| Code | Color | Code | Color |
|------|-------|------|-------|
| `31` | Red | `91` | Bright Red |
| `32` | Green | `92` | Bright Green |
| `33` | Yellow | `93` | Bright Yellow |
| `34` | Blue | `94` | Bright Blue |
| `35` | Magenta | `95` | Bright Magenta |
| `36` | Cyan | `96` | Bright Cyan |
| `37` | White | `97` | Bright White |

**Modifiers:** Add with semicolon: `31;1` (bold), `34;4` (underline), `32;7` (reverse)

### `removeCustomLevel(name: []const u8) void`

Removes a previously registered custom level.

### `custom(levelName: []const u8, message: []const u8, src: ?std.builtin.SourceLocation) !void`

Logs using a registered custom level. The entire line is colored:

```zig
try logger.addCustomLevel("audit", 35, "35;1"); // Bold magenta
try logger.custom("audit", "User login detected", @src());
// Output: [2024-01-15 10:30:45] [AUDIT] myfile.zig:42:0: User login detected (bold magenta)
```

### `customf(levelName: []const u8, comptime fmt: []const u8, args: anytype, src: ?std.builtin.SourceLocation) !void`

Formatted logging with custom levels:

```zig
try logger.customf("audit", "User {s} logged in from {s}", .{ "alice", "10.0.0.1" }, @src());
```

## Callbacks

### `setLogCallback(callback: *const fn (*const Record) anyerror!void) void`

Sets a callback function that is invoked for each log record. Useful for integration with external systems.

### `setColorCallback(callback: *const fn (Level, []const u8) []const u8) void`

Sets a custom color callback for overriding default level colors.

## Control Methods

### `enable() void`

Enables the logger (logging is enabled by default).

### `disable() void`

Temporarily disables all logging.

> \[!NOTE]
> **Dispatch priority**: When multiple logging backends are enabled, records are dispatched in the following order:
>
> 1. **AsyncLogger** (highest priority) — if `asyncConfig.enabled = true`, records are queued in the ring buffer for background processing.
> 2. **Thread Pool** — if `threadPool.enabled = true`, records are submitted as tasks to the worker pool.
> 3. **Direct Sinks** (lowest priority) — records are written synchronously to all configured sinks.
>
> `autoFlush` only applies to the **sync** and **asyncLogger** paths. The thread pool path does **not** flush on `autoFlush` because the task is merely queued to a worker — no sink write has occurred yet at the point `dispatchRecord` returns.

### `flush() !void`

Flushes all sinks, ensuring all buffered data is written.
Note: `config.autoFlush` defaults to `false` for throughput. Enable it when immediate durability is required.

### `reloadFromFile(filePath: []const u8) !void`

Dynamically reloads the configuration of the logger from a JSON file on disk. This will update the logger's active levels, sinks, formats, and invoke triggers at runtime without dropping log records or restarting the application.

```zig
try logger.reloadFromFile("config.json");
```

### `logPanic(message: []const u8) !void`

Synchronously writes a fatal crash dump (with stack traces) directly to all active sinks, bypassing asynchronous worker queues to prevent deadlocks during application panics.

```zig
try logger.logPanic("Database connection pool saturated!");
```

## Logging Methods

All logging methods accept an optional source location parameter. Pass `@src()` to enable clickable file:line:column output in terminal, or `null` if source location is not needed.

### Source Location Parameter

The `src` parameter is **optional** (type `?std.builtin.SourceLocation`):

| Value | Result |
|-------|--------|
| `@src()` | Includes file:line:column in output (when enabled in config) |
| `null` | No source location in output |

```zig
// With source location - recommended for debugging
try logger.info("Application started", @src());

// Without source location - useful for high-volume logging
try logger.debug("Processing item", null);
```

### `trace(message: []const u8, src: ?std.builtin.SourceLocation) !void`

Logs a message at the **TRACE** level (Priority 5).

```zig
try logger.trace("Detailed trace info", @src());  // With source location
try logger.trace("Trace without location", null); // Without source location
```

### `debug(message: []const u8, src: ?std.builtin.SourceLocation) !void`

Logs a message at the **DEBUG** level (Priority 10).

### `info(message: []const u8, src: ?std.builtin.SourceLocation) !void`

Logs a message at the **INFO** level (Priority 20).

### `notice(message: []const u8, src: ?std.builtin.SourceLocation) !void`

Logs a message at the **NOTICE** level (Priority 22).

### `success(message: []const u8, src: ?std.builtin.SourceLocation) !void`

Logs a message at the **SUCCESS** level (Priority 25).

### `warning(message: []const u8, src: ?std.builtin.SourceLocation) !void`

Logs a message at the **WARNING** level (Priority 30).

* **Alias**: `warn()`

### `err(message: []const u8, src: ?std.builtin.SourceLocation) !void`

Logs a message at the **ERROR** level (Priority 40).

* **Alias**: `@"error"()` (Zig keyword escape)

### `fail(message: []const u8, src: ?std.builtin.SourceLocation) !void`

Logs a message at the **FAIL** level (Priority 45).

### `critical(message: []const u8, src: ?std.builtin.SourceLocation) !void`

Logs a message at the **CRITICAL** level (Priority 50).

* **Alias**: `crit()`

### `fatal(message: []const u8, src: ?std.builtin.SourceLocation) !void`

Logs a message at the **FATAL** level (Priority 55).
This is the highest severity level with white text on red background.

```zig
try logger.fatal("System crash imminent!", @src());
```

### `custom(levelName: []const u8, message: []const u8, src: ?std.builtin.SourceLocation) !void`

Logs a message using a user-defined custom level. The level must be registered first.

```zig
try logger.addCustomLevel("audit", 35, "35;1");
try logger.custom("audit", "User login detected", @src());
```

## Formatted Logging

For formatted messages, use the `f`-suffix methods:

```zig
// Use infof, debugf, etc. for formatted messages
try logger.infof("User {s} connected from {s}", .{ "alice", "10.0.0.1" }, @src());
try logger.warningf("Request took {d}ms", .{elapsedMs}, @src());
try logger.critf("Failed after {d} retries: {s}", .{ retry_count, errorMsg }, @src());
```

### Legacy Format Methods (f-suffix)

These methods are maintained for backward compatibility:

### `tracef(comptime fmt: []const u8, args: anytype, src: ?std.builtin.SourceLocation) !void`

### `debugf(comptime fmt: []const u8, args: anytype, src: ?std.builtin.SourceLocation) !void`

### `infof(comptime fmt: []const u8, args: anytype, src: ?std.builtin.SourceLocation) !void`

```zig
// Legacy style (still works)
try logger.infof("User {s} connected from {s}", .{ "alice", "10.0.0.1" }, @src());
```

### `successf(comptime fmt: []const u8, args: anytype, src: ?std.builtin.SourceLocation) !void`

### `warningf(comptime fmt: []const u8, args: anytype, src: ?std.builtin.SourceLocation) !void`

* **Alias**: `warnf()`

### `errf(comptime fmt: []const u8, args: anytype, src: ?std.builtin.SourceLocation) !void`

* **Alias**: `errorf()`

### `failf(comptime fmt: []const u8, args: anytype, src: ?std.builtin.SourceLocation) !void`

### `criticalf(comptime fmt: []const u8, args: anytype, src: ?std.builtin.SourceLocation) !void`

* **Alias**: `critf()`

### `customf(levelName: []const u8, comptime fmt: []const u8, args: anytype, src: ?std.builtin.SourceLocation) !void`

## Source Location Display

When you enable `showFilename` and `showLineno` in the configuration and pass `@src()` to logging calls, the output includes clickable file:line:column information:

```zig
var config = logly.Config.default();
config.showFilename = true;
config.showLineno = true;
logger.configure(config);

try logger.info("This message has source location", @src());
// Output: [2024-01-15 10:30:45] [INFO] myfile.zig:42:0: This message has source location
```

The format `file:line:column:` is compatible with most terminals and IDEs, allowing you to click on it to jump directly to the source location.

## Utility Methods

### `logError(message: []const u8, errVal: anyerror) !void`

Logs an error with automatic error name resolution.

### `logTimed(level: Level, message: []const u8, startTime: i128, src: ?std.builtin.SourceLocation) !i128`

Logs a message with elapsed time calculation and optional source location.

### `getRecordCount() u64`

Returns the total number of log records processed.

### `getUptime() i64`

Returns the logger uptime in seconds.
