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;