Skip to content

Diagnostics API Reference

The Diagnostics module collects comprehensive host information including OS, CPU, memory, and storage details for logging and monitoring.

Overview

Diagnostics provides:

  • OS Information: Operating system and architecture detection
  • CPU Details: Model name and logical core count
  • Memory Stats: Total and available physical memory
  • Drive Information: Capacity and free space for all drives (Windows/Linux)
  • Structured Output: Context fields for custom formatting
  • Cross-Platform: Works on Windows, Linux, and macOS

Core Types

Diagnostics

Complete system information snapshot.

zig
pub const Diagnostics = struct {
    os_tag: []const u8,           // OS tag from builtin (e.g., "windows")
    arch: []const u8,              // CPU architecture (e.g., "x86_64")
    cpu_model: []const u8,         // Human-readable CPU model name
    logical_cores: usize,          // Number of logical CPU cores
    total_mem: ?u64,               // Total physical memory in bytes (null if unavailable)
    avail_mem: ?u64,               // Available physical memory in bytes (null if unavailable)
    drives: []DriveInfo,           // Array of drive information
    
    pub fn deinit(self: *Diagnostics, allocator: std.mem.Allocator) void;
};

Fields:

FieldTypeDescriptionPlatform
os_tag[]const u8Operating system tagAll
arch[]const u8CPU architectureAll
cpu_model[]const u8Processor model nameAll
logical_coresusizeLogical processor countAll
total_mem?u64Total RAM in bytesAll platforms
avail_mem?u64Available RAM in bytesAll platforms
drives[]DriveInfoDrive informationWindows/Linux

Examples:

zig
std.debug.print("OS: {s}\n", .{diag.os_tag});           // Output: "windows"
std.debug.print("Arch: {s}\n", .{diag.arch});           // Output: "x86_64"
std.debug.print("CPU: {s}\n", .{diag.cpu_model});       // Output: "Intel Core i7-9700K"
std.debug.print("Cores: {d}\n", .{diag.logical_cores}); // Output: 8

if (diag.total_mem) |total| {
    std.debug.print("Total RAM: {d} MB\n", .{total / (1024 * 1024)});
}

if (diag.avail_mem) |avail| {
    std.debug.print("Available RAM: {d} MB\n", .{avail / (1024 * 1024)});
}

DriveInfo

Information about a single drive or volume.

zig
pub const DriveInfo = struct {
    name: []const u8,        // Drive name (e.g., "C:\" or "/mnt/data")
    total_bytes: u64,        // Total capacity in bytes
    free_bytes: u64,         // Free bytes available
};

Fields:

FieldTypeDescription
name[]const u8Drive identifier (path or letter)
total_bytesu64Total capacity in bytes
free_bytesu64Available space in bytes

Examples:

zig
for (diag.drives) |drive| {
    const total_gb = @as(f64, @floatFromInt(drive.total_bytes)) / (1024 * 1024 * 1024);
    const free_gb = @as(f64, @floatFromInt(drive.free_bytes)) / (1024 * 1024 * 1024);
    const used_percent = 100.0 - (free_gb / total_gb * 100.0);
    
    std.debug.print("{s}: {d:.1} GB total, {d:.1} GB free ({d:.1}% used)\n", 
        .{drive.name, total_gb, free_gb, used_percent});
}

Functions

collect()

Collects system diagnostics information.

zig
pub fn collect(allocator: std.mem.Allocator, include_drives: bool) !Diagnostics

Parameters:

ParameterTypeDescription
allocatorstd.mem.AllocatorMemory allocator for diagnostic data (must call deinit() to free)
include_drivesboolInclude drive enumeration (adds ~1-5ms on Windows)

Returns: Diagnostics struct with collected information

Errors:

  • error.OutOfMemory - If allocation fails

Behavior:

  • Windows: Uses Win32 APIs (GlobalMemoryStatusEx, GetLogicalDriveStrings, GetDiskFreeSpaceEx)
  • Linux: Parses /proc/meminfo for memory, /proc/mounts for drives
  • macOS: Uses sysctl for memory information

Example:

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

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();
    
    // Collect diagnostics with drive information
    var diag = try logly.Diagnostics.collect(allocator, true);
    defer diag.deinit(allocator);
    
    std.debug.print("System Information:\n", .{});
    std.debug.print("  OS: {s}\n", .{diag.os_tag});
    std.debug.print("  Architecture: {s}\n", .{diag.arch});
    std.debug.print("  CPU: {s}\n", .{diag.cpu_model});
    std.debug.print("  Cores: {d}\n", .{diag.logical_cores});
    
    if (diag.total_mem) |total| {
        if (diag.avail_mem) |avail| {
            std.debug.print("  Memory: {d} MB / {d} MB\n", 
                .{avail / (1024 * 1024), total / (1024 * 1024)});
        }
    }
    
    std.debug.print("\nDrives:\n", .{});
    for (diag.drives) |drive| {
        const total_gb = @as(f64, @floatFromInt(drive.total_bytes)) / (1024 * 1024 * 1024);
        const free_gb = @as(f64, @floatFromInt(drive.free_bytes)) / (1024 * 1024 * 1024);
        std.debug.print("  {s}: {d:.1} GB total, {d:.1} GB free\n", 
            .{drive.name, total_gb, free_gb});
    }
}

deinit()

Frees allocated memory for diagnostics data.

zig
pub fn deinit(self: *Diagnostics, allocator: std.mem.Allocator) void

Parameters:

ParameterTypeDescription
self*DiagnosticsThe Diagnostics struct to deinitialize
allocatorstd.mem.AllocatorThe same allocator used in collect()

Example:

zig
var diag = try logly.Diagnostics.collect(allocator, true);
defer diag.deinit(allocator);  // Always call deinit to free memory

Logger Integration

logSystemDiagnostics()

Logger helper method that collects and logs diagnostics.

zig
pub fn logSystemDiagnostics(self: *Logger, src: ?std.builtin.SourceLocation) !void

Parameters:

ParameterTypeDescription
self*LoggerLogger instance
src?std.builtin.SourceLocationSource location (typically @src())

Example:

zig
const logger = try logly.Logger.init(allocator);
defer logger.deinit();

// Log system diagnostics
try logger.logSystemDiagnostics(@src());

Output Example:

[INFO] [DIAGNOSTICS] os=windows arch=x86_64 cpu=Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz cores=8 ram_total=32768MB ram_available=16384MB drives=[C:\ total=931GB free=256GB; D:\ total=1863GB free=512GB]

Context Fields

When diagnostics are logged via logSystemDiagnostics(), the following fields are available in the log record context for custom formatting:

FieldTypeDescriptionExample Value
diag.osstringOS tag"windows", "linux", "macos"
diag.archstringCPU architecture"x86_64", "aarch64"
diag.cpustringCPU model name"Intel Core i7-9700K"
diag.coresintegerLogical cores8, 16
diag.ram_total_mbintegerTotal RAM in MB32768
diag.ram_avail_mbintegerAvailable RAM in MB16384

Custom Format Example:

zig
config.log_format = "[{level}] System: {diag.os}/{diag.arch} | CPU: {diag.cpu} ({diag.cores} cores) | RAM: {diag.ram_avail_mb}/{diag.ram_total_mb} MB";

Configuration Options

emit_system_diagnostics_on_init

Automatically emit diagnostics when logger initializes.

zig
config.emit_system_diagnostics_on_init = true;  // Default: false

Type: bool
Default: false
Effect: Emits diagnostics at INFO level during Logger.init() or Logger.initWithConfig()

include_drive_diagnostics

Include drive/volume information in diagnostics collection.

zig
config.include_drive_diagnostics = true;  // Default: true

Type: bool
Default: true
Effect: Adds drive enumeration to diagnostics output (adds 1-5ms on Windows)

color

Enable color-coded diagnostic output.

zig
config.color = true;  // Default: true

Type: bool
Default: true
Effect: Enables ANSI color codes in diagnostic output

Note: On Windows, requires calling logly.Terminal.enableAnsiColors() first.

Platform-Specific Behavior

Windows

FeatureImplementationNotes
Memory InfoGlobalMemoryStatusEx APIReports physical RAM
Drive EnumerationGetLogicalDriveStrings + GetDiskFreeSpaceExAll logical drives (C:, D:, etc.)
ANSI ColorsVirtual Terminal ProcessingRequires Terminal.enableAnsiColors()
Performance~2-7ms totalWith drive enumeration

Linux

FeatureImplementationNotes
Memory Info/proc/meminfo parsingMemTotal and MemAvailable
Drive Enumeration/proc/mountsMounted filesystems
ANSI ColorsNative supportWorks out of the box
Performance~1-3ms totalFast file parsing

macOS

FeatureImplementationNotes
Memory Infosysctl querieshw.memsize and vm.stats
Drive EnumerationMount pointsVia system calls
ANSI ColorsNative supportWorks out of the box
Performance~1-3ms totalEfficient system calls

Complete Example

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

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Enable ANSI colors on Windows
    _ = logly.Terminal.enableAnsiColors();

    // Example 1: Auto-emit at startup
    {
        var config = logly.Config.default();
        config.emit_system_diagnostics_on_init = true;
        config.include_drive_diagnostics = true;
        config.color = true;

        const logger = try logly.Logger.initWithConfig(allocator, config);
        defer logger.deinit();
        
        // Diagnostics already logged during init
    }

    // Example 2: Manual on-demand
    {
        const logger = try logly.Logger.init(allocator);
        defer logger.deinit();

        try logger.logSystemDiagnostics(@src());
    }

    // Example 3: Direct collection
    {
        var diag = try logly.Diagnostics.collect(allocator, true);
        defer diag.deinit(allocator);

        std.debug.print("CPU: {s} ({d} cores)\n", .{diag.cpu_model, diag.logical_cores});
        
        if (diag.total_mem) |total| {
            if (diag.avail_mem) |avail| {
                const used_mb = (total - avail) / (1024 * 1024);
                const total_mb = total / (1024 * 1024);
                std.debug.print("Memory: {d}/{d} MB\n", .{used_mb, total_mb});
            }
        }
    }
}

See Also

Released under the MIT License.