master
  1//! std.log is a standardized interface for logging which allows for the logging
  2//! of programs and libraries using this interface to be formatted and filtered
  3//! by the implementer of the `std.options.logFn` function.
  4//!
  5//! Each log message has an associated scope enum, which can be used to give
  6//! context to the logging. The logging functions in std.log implicitly use a
  7//! scope of .default.
  8//!
  9//! A logging namespace using a custom scope can be created using the
 10//! std.log.scoped function, passing the scope as an argument; the logging
 11//! functions in the resulting struct use the provided scope parameter.
 12//! For example, a library called 'libfoo' might use
 13//! `const log = std.log.scoped(.libfoo);` to use .libfoo as the scope of its
 14//! log messages.
 15//!
 16//! For an example implementation of the `logFn` function, see `defaultLog`,
 17//! which is the default implementation. It outputs to stderr, using color if
 18//! the detected `std.Io.tty.Config` supports it. Its output looks like this:
 19//! ```
 20//! error: this is an error
 21//! error(scope): this is an error with a non-default scope
 22//! warning: this is a warning
 23//! info: this is an informative message
 24//! debug: this is a debugging message
 25//! ```
 26
 27const std = @import("std.zig");
 28const builtin = @import("builtin");
 29
 30pub const Level = enum {
 31    /// Error: something has gone wrong. This might be recoverable or might
 32    /// be followed by the program exiting.
 33    err,
 34    /// Warning: it is uncertain if something has gone wrong or not, but the
 35    /// circumstances would be worth investigating.
 36    warn,
 37    /// Info: general messages about the state of the program.
 38    info,
 39    /// Debug: messages only useful for debugging.
 40    debug,
 41
 42    /// Returns a string literal of the given level in full text form.
 43    pub fn asText(comptime self: Level) []const u8 {
 44        return switch (self) {
 45            .err => "error",
 46            .warn => "warning",
 47            .info => "info",
 48            .debug => "debug",
 49        };
 50    }
 51};
 52
 53/// The default log level is based on build mode.
 54pub const default_level: Level = switch (builtin.mode) {
 55    .Debug => .debug,
 56    .ReleaseSafe, .ReleaseFast, .ReleaseSmall => .info,
 57};
 58
 59pub const ScopeLevel = struct {
 60    scope: @EnumLiteral(),
 61    level: Level,
 62};
 63
 64fn log(
 65    comptime level: Level,
 66    comptime scope: @EnumLiteral(),
 67    comptime format: []const u8,
 68    args: anytype,
 69) void {
 70    if (comptime !logEnabled(level, scope)) return;
 71
 72    std.options.logFn(level, scope, format, args);
 73}
 74
 75/// Determine if a specific log message level and scope combination are enabled for logging.
 76pub fn logEnabled(comptime level: Level, comptime scope: @EnumLiteral()) bool {
 77    inline for (std.options.log_scope_levels) |scope_level| {
 78        if (scope_level.scope == scope) return @intFromEnum(level) <= @intFromEnum(scope_level.level);
 79    }
 80    return @intFromEnum(level) <= @intFromEnum(std.options.log_level);
 81}
 82
 83/// The default implementation for the log function. Custom log functions may
 84/// forward log messages to this function.
 85///
 86/// Uses a 64-byte buffer for formatted printing which is flushed before this
 87/// function returns.
 88pub fn defaultLog(
 89    comptime level: Level,
 90    comptime scope: @EnumLiteral(),
 91    comptime format: []const u8,
 92    args: anytype,
 93) void {
 94    var buffer: [64]u8 = undefined;
 95    const stderr, const ttyconf = std.debug.lockStderrWriter(&buffer);
 96    defer std.debug.unlockStderrWriter();
 97    ttyconf.setColor(stderr, switch (level) {
 98        .err => .red,
 99        .warn => .yellow,
100        .info => .green,
101        .debug => .magenta,
102    }) catch {};
103    ttyconf.setColor(stderr, .bold) catch {};
104    stderr.writeAll(level.asText()) catch return;
105    ttyconf.setColor(stderr, .reset) catch {};
106    ttyconf.setColor(stderr, .dim) catch {};
107    ttyconf.setColor(stderr, .bold) catch {};
108    if (scope != .default) {
109        stderr.print("({s})", .{@tagName(scope)}) catch return;
110    }
111    stderr.writeAll(": ") catch return;
112    ttyconf.setColor(stderr, .reset) catch {};
113    stderr.print(format ++ "\n", args) catch return;
114}
115
116/// Returns a scoped logging namespace that logs all messages using the scope
117/// provided here.
118pub fn scoped(comptime scope: @EnumLiteral()) type {
119    return struct {
120        /// Log an error message. This log level is intended to be used
121        /// when something has gone wrong. This might be recoverable or might
122        /// be followed by the program exiting.
123        pub fn err(
124            comptime format: []const u8,
125            args: anytype,
126        ) void {
127            @branchHint(.cold);
128            log(.err, scope, format, args);
129        }
130
131        /// Log a warning message. This log level is intended to be used if
132        /// it is uncertain whether something has gone wrong or not, but the
133        /// circumstances would be worth investigating.
134        pub fn warn(
135            comptime format: []const u8,
136            args: anytype,
137        ) void {
138            log(.warn, scope, format, args);
139        }
140
141        /// Log an info message. This log level is intended to be used for
142        /// general messages about the state of the program.
143        pub fn info(
144            comptime format: []const u8,
145            args: anytype,
146        ) void {
147            log(.info, scope, format, args);
148        }
149
150        /// Log a debug message. This log level is intended to be used for
151        /// messages which are only useful for debugging.
152        pub fn debug(
153            comptime format: []const u8,
154            args: anytype,
155        ) void {
156            log(.debug, scope, format, args);
157        }
158    };
159}
160
161pub const default_log_scope = .default;
162
163/// The default scoped logging namespace.
164pub const default = scoped(default_log_scope);
165
166/// Log an error message using the default scope. This log level is intended to
167/// be used when something has gone wrong. This might be recoverable or might
168/// be followed by the program exiting.
169pub const err = default.err;
170
171/// Log a warning message using the default scope. This log level is intended
172/// to be used if it is uncertain whether something has gone wrong or not, but
173/// the circumstances would be worth investigating.
174pub const warn = default.warn;
175
176/// Log an info message using the default scope. This log level is intended to
177/// be used for general messages about the state of the program.
178pub const info = default.info;
179
180/// Log a debug message using the default scope. This log level is intended to
181/// be used for messages which are only useful for debugging.
182pub const debug = default.debug;