zig/lib/std/log.zig
2020-06-19 02:06:27 -04:00

203 lines
6.5 KiB
Zig

const std = @import("std.zig");
const builtin = std.builtin;
const root = @import("root");
//! std.log is standardized interface for logging which allows for the logging
//! of programs and libraries using this interface to be formatted and filtered
//! by the implementer of the root.log function.
//!
//! The scope parameter should be used to give context to the logging. For
//! example, a library called 'libfoo' might use .libfoo as its scope.
//!
//! An example root.log might look something like this:
//!
//! ```
//! const std = @import("std");
//!
//! // Set the log level to warning
//! pub const log_level: std.log.Level = .warn;
//!
//! // Define root.log to override the std implementation
//! pub fn log(
//! comptime level: std.log.Level,
//! comptime scope: @TypeOf(.EnumLiteral),
//! comptime format: []const u8,
//! args: var,
//! ) void {
//! // Ignore all non-critical logging from sources other than
//! // .my_project and .nice_library
//! const scope_prefix = "(" ++ switch (scope) {
//! .my_project, .nice_library => @tagName(scope),
//! else => if (@enumToInt(level) <= @enumToInt(std.log.Level.crit))
//! @tagName(scope)
//! else
//! return,
//! } ++ "): ";
//!
//! const prefix = "[" ++ @tagName(level) ++ "] " ++ scope_prefix;
//!
//! // Print the message to stderr, silently ignoring any errors
//! const held = std.debug.getStderrMutex().acquire();
//! defer held.release();
//! const stderr = std.debug.getStderrStream();
//! nosuspend stderr.print(prefix ++ format, args) catch return;
//! }
//!
//! pub fn main() void {
//! // Won't be printed as log_level is .warn
//! std.log.info(.my_project, "Starting up.\n", .{});
//! std.log.err(.nice_library, "Something went very wrong, sorry.\n", .{});
//! // Won't be printed as it gets filtered out by our log function
//! std.log.err(.lib_that_logs_too_much, "Added 1 + 1\n", .{});
//! }
//! ```
//! Which produces the following output:
//! ```
//! [err] (nice_library): Something went very wrong, sorry.
//! ```
pub const Level = enum {
/// Emergency: a condition that cannot be handled, usually followed by a
/// panic.
emerg,
/// Alert: a condition that should be corrected immediately (e.g. database
/// corruption).
alert,
/// Critical: A bug has been detected or something has gone wrong and it
/// will have an effect on the operation of the program.
crit,
/// Error: A bug has been detected or something has gone wrong but it is
/// recoverable.
err,
/// Warning: it is uncertain if something has gone wrong or not, but the
/// circumstances would be worth investigating.
warn,
/// Notice: non-error but significant conditions.
notice,
/// Informational: general messages about the state of the program.
info,
/// Debug: messages only useful for debugging.
debug,
};
/// The default log level is based on build mode. Note that in ReleaseSmall
/// builds the default level is emerg but no messages will be stored/logged
/// by the default logger to save space.
pub const default_level: Level = switch (builtin.mode) {
.Debug => .debug,
.ReleaseSafe => .notice,
.ReleaseFast => .err,
.ReleaseSmall => .emerg,
};
/// The current log level. This is set to root.log_level if present, otherwise
/// log.default_level.
pub const level: Level = if (@hasDecl(root, "log_level"))
root.log_level
else
default_level;
fn log(
comptime message_level: Level,
comptime scope: @Type(.EnumLiteral),
comptime format: []const u8,
args: var,
) void {
if (@enumToInt(message_level) <= @enumToInt(level)) {
if (@hasDecl(root, "log")) {
root.log(message_level, scope, format, args);
} else if (builtin.mode != .ReleaseSmall) {
const held = std.debug.getStderrMutex().acquire();
defer held.release();
const stderr = std.io.getStdErr().writer();
nosuspend stderr.print(format, args) catch return;
}
}
}
/// Log an emergency message to stderr. This log level is intended to be used
/// for conditions that cannot be handled and is usually followed by a panic.
pub fn emerg(
comptime scope: @Type(.EnumLiteral),
comptime format: []const u8,
args: var,
) void {
@setCold(true);
log(.emerg, scope, format, args);
}
/// Log an alert message to stderr. This log level is intended to be used for
/// conditions that should be corrected immediately (e.g. database corruption).
pub fn alert(
comptime scope: @Type(.EnumLiteral),
comptime format: []const u8,
args: var,
) void {
@setCold(true);
log(.alert, scope, format, args);
}
/// Log a critical message to stderr. This log level is intended to be used
/// when a bug has been detected or something has gone wrong and it will have
/// an effect on the operation of the program.
pub fn crit(
comptime scope: @Type(.EnumLiteral),
comptime format: []const u8,
args: var,
) void {
@setCold(true);
log(.crit, scope, format, args);
}
/// Log an error message to stderr. This log level is intended to be used when
/// a bug has been detected or something has gone wrong but it is recoverable.
pub fn err(
comptime scope: @Type(.EnumLiteral),
comptime format: []const u8,
args: var,
) void {
@setCold(true);
log(.err, scope, format, args);
}
/// Log a warning message to stderr. 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 fn warn(
comptime scope: @Type(.EnumLiteral),
comptime format: []const u8,
args: var,
) void {
log(.warn, scope, format, args);
}
/// Log a notice message to stderr. This log level is intended to be used for
/// non-error but significant conditions.
pub fn notice(
comptime scope: @Type(.EnumLiteral),
comptime format: []const u8,
args: var,
) void {
log(.notice, scope, format, args);
}
/// Log an info message to stderr. This log level is intended to be used for
/// general messages about the state of the program.
pub fn info(
comptime scope: @Type(.EnumLiteral),
comptime format: []const u8,
args: var,
) void {
log(.info, scope, format, args);
}
/// Log a debug message to stderr. This log level is intended to be used for
/// messages which are only useful for debugging.
pub fn debug(
comptime scope: @Type(.EnumLiteral),
comptime format: []const u8,
args: var,
) void {
log(.debug, scope, format, args);
}