2020-08-12 15:37:56 +02:00
|
|
|
//! std.log is a standardized interface for logging which allows for the logging
|
2020-05-15 17:10:56 +02:00
|
|
|
//! of programs and libraries using this interface to be formatted and filtered
|
2023-01-03 19:37:11 +02:00
|
|
|
//! by the implementer of the `std.options.logFn` function.
|
2020-05-15 17:10:56 +02:00
|
|
|
//!
|
2020-08-13 17:12:16 +02:00
|
|
|
//! Each log message has an associated scope enum, which can be used to give
|
|
|
|
|
//! context to the logging. The logging functions in std.log implicitly use a
|
|
|
|
|
//! scope of .default.
|
|
|
|
|
//!
|
|
|
|
|
//! A logging namespace using a custom scope can be created using the
|
|
|
|
|
//! std.log.scoped function, passing the scope as an argument; the logging
|
|
|
|
|
//! functions in the resulting struct use the provided scope parameter.
|
|
|
|
|
//! For example, a library called 'libfoo' might use
|
|
|
|
|
//! `const log = std.log.scoped(.libfoo);` to use .libfoo as the scope of its
|
|
|
|
|
//! log messages.
|
2020-05-15 17:10:56 +02:00
|
|
|
//!
|
2023-01-03 19:37:11 +02:00
|
|
|
//! An example `logFn` might look something like this:
|
2020-05-15 17:10:56 +02:00
|
|
|
//!
|
|
|
|
|
//! ```
|
|
|
|
|
//! const std = @import("std");
|
|
|
|
|
//!
|
2025-05-22 12:50:33 +02:00
|
|
|
//! pub const std_options: std.Options = .{
|
2023-01-03 19:37:11 +02:00
|
|
|
//! // Set the log level to info
|
2024-01-28 00:30:24 +02:00
|
|
|
//! .log_level = .info,
|
2020-05-15 17:10:56 +02:00
|
|
|
//!
|
2023-01-03 19:37:11 +02:00
|
|
|
//! // Define logFn to override the std implementation
|
2024-01-28 00:30:24 +02:00
|
|
|
//! .logFn = myLogFn,
|
2023-01-03 19:37:11 +02:00
|
|
|
//! };
|
|
|
|
|
//!
|
|
|
|
|
//! pub fn myLogFn(
|
2020-05-15 17:10:56 +02:00
|
|
|
//! comptime level: std.log.Level,
|
2024-08-28 02:35:53 +01:00
|
|
|
//! comptime scope: @Type(.enum_literal),
|
2020-05-15 17:10:56 +02:00
|
|
|
//! comptime format: []const u8,
|
2020-07-11 22:04:38 +03:00
|
|
|
//! args: anytype,
|
2020-05-15 17:10:56 +02:00
|
|
|
//! ) void {
|
2021-10-24 13:13:06 +02:00
|
|
|
//! // Ignore all non-error logging from sources other than
|
2022-10-26 21:03:02 +01:00
|
|
|
//! // .my_project, .nice_library and the default
|
2020-05-15 17:10:56 +02:00
|
|
|
//! const scope_prefix = "(" ++ switch (scope) {
|
2022-10-26 21:03:02 +01:00
|
|
|
//! .my_project, .nice_library, std.log.default_log_scope => @tagName(scope),
|
2023-06-15 13:14:16 +06:00
|
|
|
//! else => if (@intFromEnum(level) <= @intFromEnum(std.log.Level.err))
|
2020-05-15 17:10:56 +02:00
|
|
|
//! @tagName(scope)
|
|
|
|
|
//! else
|
|
|
|
|
//! return,
|
|
|
|
|
//! } ++ "): ";
|
|
|
|
|
//!
|
2022-08-30 18:07:23 -03:00
|
|
|
//! const prefix = "[" ++ comptime level.asText() ++ "] " ++ scope_prefix;
|
2020-05-15 17:10:56 +02:00
|
|
|
//!
|
|
|
|
|
//! // Print the message to stderr, silently ignoring any errors
|
2024-05-24 08:22:47 -07:00
|
|
|
//! std.debug.lockStdErr();
|
|
|
|
|
//! defer std.debug.unlockStdErr();
|
2025-06-27 20:05:22 -07:00
|
|
|
//! const stderr = std.fs.File.stderr().deprecatedWriter();
|
2020-07-22 23:26:41 +02:00
|
|
|
//! nosuspend stderr.print(prefix ++ format ++ "\n", args) catch return;
|
2020-05-15 17:10:56 +02:00
|
|
|
//! }
|
|
|
|
|
//!
|
|
|
|
|
//! pub fn main() void {
|
2020-08-13 17:12:16 +02:00
|
|
|
//! // Using the default scope:
|
2021-10-24 13:13:06 +02:00
|
|
|
//! std.log.debug("A borderline useless debug log message", .{}); // Won't be printed as log_level is .info
|
|
|
|
|
//! std.log.info("Flux capacitor is starting to overheat", .{});
|
2020-08-12 15:37:56 +02:00
|
|
|
//!
|
2020-08-13 17:12:16 +02:00
|
|
|
//! // Using scoped logging:
|
|
|
|
|
//! const my_project_log = std.log.scoped(.my_project);
|
|
|
|
|
//! const nice_library_log = std.log.scoped(.nice_library);
|
|
|
|
|
//! const verbose_lib_log = std.log.scoped(.verbose_lib);
|
2020-08-12 15:37:56 +02:00
|
|
|
//!
|
2021-10-24 13:13:06 +02:00
|
|
|
//! my_project_log.debug("Starting up", .{}); // Won't be printed as log_level is .info
|
|
|
|
|
//! nice_library_log.warn("Something went very wrong, sorry", .{});
|
|
|
|
|
//! verbose_lib_log.warn("Added 1 + 1: {}", .{1 + 1}); // Won't be printed as it gets filtered out by our log function
|
2020-05-15 17:10:56 +02:00
|
|
|
//! }
|
|
|
|
|
//! ```
|
|
|
|
|
//! Which produces the following output:
|
|
|
|
|
//! ```
|
2021-10-24 13:13:06 +02:00
|
|
|
//! [info] (default): Flux capacitor is starting to overheat
|
|
|
|
|
//! [warning] (nice_library): Something went very wrong, sorry
|
2020-05-15 17:10:56 +02:00
|
|
|
//! ```
|
|
|
|
|
|
2021-02-24 21:29:01 -07:00
|
|
|
const std = @import("std.zig");
|
2021-10-04 23:47:27 -07:00
|
|
|
const builtin = @import("builtin");
|
2021-02-24 21:29:01 -07:00
|
|
|
|
2020-05-15 17:10:56 +02:00
|
|
|
pub const Level = enum {
|
2021-10-24 13:13:06 +02:00
|
|
|
/// Error: something has gone wrong. This might be recoverable or might
|
|
|
|
|
/// be followed by the program exiting.
|
2020-05-15 17:10:56 +02:00
|
|
|
err,
|
|
|
|
|
/// Warning: it is uncertain if something has gone wrong or not, but the
|
|
|
|
|
/// circumstances would be worth investigating.
|
|
|
|
|
warn,
|
2021-10-24 13:13:06 +02:00
|
|
|
/// Info: general messages about the state of the program.
|
2020-05-15 17:10:56 +02:00
|
|
|
info,
|
|
|
|
|
/// Debug: messages only useful for debugging.
|
|
|
|
|
debug,
|
2021-06-24 04:30:05 -06:00
|
|
|
|
|
|
|
|
/// Returns a string literal of the given level in full text form.
|
2022-07-06 19:27:47 +02:00
|
|
|
pub fn asText(comptime self: Level) []const u8 {
|
2021-06-24 04:30:05 -06:00
|
|
|
return switch (self) {
|
|
|
|
|
.err => "error",
|
|
|
|
|
.warn => "warning",
|
2021-10-24 13:13:06 +02:00
|
|
|
.info => "info",
|
|
|
|
|
.debug => "debug",
|
2021-06-24 04:30:05 -06:00
|
|
|
};
|
|
|
|
|
}
|
2020-05-15 17:10:56 +02:00
|
|
|
};
|
|
|
|
|
|
2020-09-26 21:03:38 -07:00
|
|
|
/// The default log level is based on build mode.
|
2020-05-15 17:10:56 +02:00
|
|
|
pub const default_level: Level = switch (builtin.mode) {
|
|
|
|
|
.Debug => .debug,
|
2025-07-09 23:03:35 -07:00
|
|
|
.ReleaseSafe, .ReleaseFast, .ReleaseSmall => .info,
|
2020-05-15 17:10:56 +02:00
|
|
|
};
|
|
|
|
|
|
2023-01-03 19:37:11 +02:00
|
|
|
const level = std.options.log_level;
|
2020-05-15 17:10:56 +02:00
|
|
|
|
2021-06-09 10:23:45 +01:00
|
|
|
pub const ScopeLevel = struct {
|
2024-08-28 02:35:53 +01:00
|
|
|
scope: @Type(.enum_literal),
|
2021-06-09 10:23:45 +01:00
|
|
|
level: Level,
|
|
|
|
|
};
|
|
|
|
|
|
2023-01-03 19:37:11 +02:00
|
|
|
const scope_levels = std.options.log_scope_levels;
|
2021-06-09 10:23:45 +01:00
|
|
|
|
2020-05-15 17:10:56 +02:00
|
|
|
fn log(
|
|
|
|
|
comptime message_level: Level,
|
2024-08-28 02:35:53 +01:00
|
|
|
comptime scope: @Type(.enum_literal),
|
2020-05-15 17:10:56 +02:00
|
|
|
comptime format: []const u8,
|
2020-07-11 14:09:04 +03:00
|
|
|
args: anytype,
|
2020-05-15 17:10:56 +02:00
|
|
|
) void {
|
2022-10-26 21:03:02 +01:00
|
|
|
if (comptime !logEnabled(message_level, scope)) return;
|
|
|
|
|
|
2023-01-03 19:37:11 +02:00
|
|
|
std.options.logFn(message_level, scope, format, args);
|
2022-10-26 21:03:02 +01:00
|
|
|
}
|
2021-06-09 10:23:45 +01:00
|
|
|
|
2022-10-26 21:03:02 +01:00
|
|
|
/// Determine if a specific log message level and scope combination are enabled for logging.
|
2024-08-28 02:35:53 +01:00
|
|
|
pub fn logEnabled(comptime message_level: Level, comptime scope: @Type(.enum_literal)) bool {
|
2022-10-26 21:03:02 +01:00
|
|
|
inline for (scope_levels) |scope_level| {
|
2023-06-15 13:14:16 +06:00
|
|
|
if (scope_level.scope == scope) return @intFromEnum(message_level) <= @intFromEnum(scope_level.level);
|
2020-05-15 17:10:56 +02:00
|
|
|
}
|
2023-06-15 13:14:16 +06:00
|
|
|
return @intFromEnum(message_level) <= @intFromEnum(level);
|
2022-10-26 21:03:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Determine if a specific log message level using the default log scope is enabled for logging.
|
|
|
|
|
pub fn defaultLogEnabled(comptime message_level: Level) bool {
|
|
|
|
|
return comptime logEnabled(message_level, default_log_scope);
|
2020-05-15 17:10:56 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-10 12:41:26 -07:00
|
|
|
/// The default implementation for the log function. Custom log functions may
|
2023-01-03 19:37:11 +02:00
|
|
|
/// forward log messages to this function.
|
2025-07-10 12:41:26 -07:00
|
|
|
///
|
|
|
|
|
/// Uses a 64-byte buffer for formatted printing which is flushed before this
|
|
|
|
|
/// function returns.
|
2021-06-24 04:11:28 -06:00
|
|
|
pub fn defaultLog(
|
|
|
|
|
comptime message_level: Level,
|
2024-08-28 02:35:53 +01:00
|
|
|
comptime scope: @Type(.enum_literal),
|
2021-06-24 04:11:28 -06:00
|
|
|
comptime format: []const u8,
|
|
|
|
|
args: anytype,
|
|
|
|
|
) void {
|
2021-06-24 04:30:05 -06:00
|
|
|
const level_txt = comptime message_level.asText();
|
2021-06-24 04:11:28 -06:00
|
|
|
const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
|
2025-07-10 12:41:26 -07:00
|
|
|
var buffer: [64]u8 = undefined;
|
|
|
|
|
const stderr = std.debug.lockStderrWriter(&buffer);
|
|
|
|
|
defer std.debug.unlockStderrWriter();
|
|
|
|
|
nosuspend stderr.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return;
|
2021-06-24 04:11:28 -06:00
|
|
|
}
|
|
|
|
|
|
2020-08-12 15:37:56 +02:00
|
|
|
/// Returns a scoped logging namespace that logs all messages using the scope
|
|
|
|
|
/// provided here.
|
2024-08-28 02:35:53 +01:00
|
|
|
pub fn scoped(comptime scope: @Type(.enum_literal)) type {
|
2020-08-12 14:03:02 +02:00
|
|
|
return struct {
|
2021-10-24 13:13:06 +02:00
|
|
|
/// Log an error message. This log level is intended to be used
|
|
|
|
|
/// when something has gone wrong. This might be recoverable or might
|
|
|
|
|
/// be followed by the program exiting.
|
2020-08-12 14:03:02 +02:00
|
|
|
pub fn err(
|
|
|
|
|
comptime format: []const u8,
|
|
|
|
|
args: anytype,
|
|
|
|
|
) void {
|
2024-08-24 16:16:53 +01:00
|
|
|
@branchHint(.cold);
|
2020-08-12 14:03:02 +02:00
|
|
|
log(.err, scope, format, args);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-12 15:54:21 +02:00
|
|
|
/// Log a warning message. This log level is intended to be used if
|
2020-08-12 14:03:02 +02:00
|
|
|
/// it is uncertain whether something has gone wrong or not, but the
|
|
|
|
|
/// circumstances would be worth investigating.
|
|
|
|
|
pub fn warn(
|
|
|
|
|
comptime format: []const u8,
|
|
|
|
|
args: anytype,
|
|
|
|
|
) void {
|
|
|
|
|
log(.warn, scope, format, args);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-12 15:54:21 +02:00
|
|
|
/// Log an info message. This log level is intended to be used for
|
2020-08-12 14:03:02 +02:00
|
|
|
/// general messages about the state of the program.
|
|
|
|
|
pub fn info(
|
|
|
|
|
comptime format: []const u8,
|
|
|
|
|
args: anytype,
|
|
|
|
|
) void {
|
|
|
|
|
log(.info, scope, format, args);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-12 15:54:21 +02:00
|
|
|
/// Log a debug message. This log level is intended to be used for
|
2020-08-12 14:03:02 +02:00
|
|
|
/// messages which are only useful for debugging.
|
|
|
|
|
pub fn debug(
|
|
|
|
|
comptime format: []const u8,
|
|
|
|
|
args: anytype,
|
|
|
|
|
) void {
|
|
|
|
|
log(.debug, scope, format, args);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-26 21:03:02 +01:00
|
|
|
pub const default_log_scope = .default;
|
|
|
|
|
|
2020-08-12 15:37:56 +02:00
|
|
|
/// The default scoped logging namespace.
|
2022-10-26 21:03:02 +01:00
|
|
|
pub const default = scoped(default_log_scope);
|
2020-08-13 16:50:38 +02:00
|
|
|
|
|
|
|
|
/// Log an error message using the default scope. This log level is intended to
|
2021-10-24 13:13:06 +02:00
|
|
|
/// be used when something has gone wrong. This might be recoverable or might
|
|
|
|
|
/// be followed by the program exiting.
|
2020-08-13 16:50:38 +02:00
|
|
|
pub const err = default.err;
|
|
|
|
|
|
|
|
|
|
/// Log a warning message using the default scope. This log level is intended
|
|
|
|
|
/// to be used if it is uncertain whether something has gone wrong or not, but
|
|
|
|
|
/// the circumstances would be worth investigating.
|
|
|
|
|
pub const warn = default.warn;
|
|
|
|
|
|
|
|
|
|
/// Log an info message using the default scope. This log level is intended to
|
|
|
|
|
/// be used for general messages about the state of the program.
|
|
|
|
|
pub const info = default.info;
|
|
|
|
|
|
|
|
|
|
/// Log a debug message using the default scope. This log level is intended to
|
|
|
|
|
/// be used for messages which are only useful for debugging.
|
|
|
|
|
pub const debug = default.debug;
|