authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-18 21:40:06-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-06-18 21:40:06-04:00
log0d18eda1d6e5ae6d4eb544b37ecd888e3bf41c2b
tree62be437c046b39e943f808805c9e993c03cdd237
parentc70633eacdf4e17cfafe0ab44f4ea83323b6d7a3
parentc3e0224792510e69763dbc6ba68794f9134925f2
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5348 from ifreund/std-log

Introduce std.log

3 files changed, 210 insertions(+), 3 deletions(-)

lib/std/debug.zig+7-3
...@@ -52,9 +52,13 @@ pub const LineInfo = struct {...@@ -52,9 +52,13 @@ pub const LineInfo = struct {
5252
53var stderr_mutex = std.Mutex.init();53var stderr_mutex = std.Mutex.init();
5454
55/// Tries to write to stderr, unbuffered, and ignores any error returned.55/// Deprecated. Use `std.log` functions for logging or `std.debug.print` for
56/// Does not append a newline.56/// "printf debugging".
57pub fn warn(comptime fmt: []const u8, args: var) void {57pub const warn = print;
58
59/// Print to stderr, unbuffered, and silently returning on failure. Intended
60/// for use in "printf debugging." Use `std.log` functions for proper logging.
61pub fn print(comptime fmt: []const u8, args: var) void {
58 const held = stderr_mutex.acquire();62 const held = stderr_mutex.acquire();
59 defer held.release();63 defer held.release();
60 const stderr = io.getStdErr().writer();64 const stderr = io.getStdErr().writer();
lib/std/log.zig created+202
...@@ -0,0 +1,202 @@
1const std = @import("std.zig");
2const builtin = std.builtin;
3const root = @import("root");
4
5//! std.log is standardized interface for logging which allows for the logging
6//! of programs and libraries using this interface to be formatted and filtered
7//! by the implementer of the root.log function.
8//!
9//! The scope parameter should be used to give context to the logging. For
10//! example, a library called 'libfoo' might use .libfoo as its scope.
11//!
12//! An example root.log might look something like this:
13//!
14//! ```
15//! const std = @import("std");
16//!
17//! // Set the log level to warning
18//! pub const log_level: std.log.Level = .warn;
19//!
20//! // Define root.log to override the std implementation
21//! pub fn log(
22//! comptime level: std.log.Level,
23//! comptime scope: @TypeOf(.EnumLiteral),
24//! comptime format: []const u8,
25//! args: var,
26//! ) void {
27//! // Ignore all non-critical logging from sources other than
28//! // .my_project and .nice_library
29//! const scope_prefix = "(" ++ switch (scope) {
30//! .my_project, .nice_library => @tagName(scope),
31//! else => if (@enumToInt(level) <= @enumToInt(std.log.Level.crit))
32//! @tagName(scope)
33//! else
34//! return,
35//! } ++ "): ";
36//!
37//! const prefix = "[" ++ @tagName(level) ++ "] " ++ scope_prefix;
38//!
39//! // Print the message to stderr, silently ignoring any errors
40//! const held = std.debug.getStderrMutex().acquire();
41//! defer held.release();
42//! const stderr = std.debug.getStderrStream();
43//! nosuspend stderr.print(prefix ++ format, args) catch return;
44//! }
45//!
46//! pub fn main() void {
47//! // Won't be printed as log_level is .warn
48//! std.log.info(.my_project, "Starting up.\n", .{});
49//! std.log.err(.nice_library, "Something went very wrong, sorry.\n", .{});
50//! // Won't be printed as it gets filtered out by our log function
51//! std.log.err(.lib_that_logs_too_much, "Added 1 + 1\n", .{});
52//! }
53//! ```
54//! Which produces the following output:
55//! ```
56//! [err] (nice_library): Something went very wrong, sorry.
57//! ```
58
59pub const Level = enum {
60 /// Emergency: a condition that cannot be handled, usually followed by a
61 /// panic.
62 emerg,
63 /// Alert: a condition that should be corrected immediately (e.g. database
64 /// corruption).
65 alert,
66 /// Critical: A bug has been detected or something has gone wrong and it
67 /// will have an effect on the operation of the program.
68 crit,
69 /// Error: A bug has been detected or something has gone wrong but it is
70 /// recoverable.
71 err,
72 /// Warning: it is uncertain if something has gone wrong or not, but the
73 /// circumstances would be worth investigating.
74 warn,
75 /// Notice: non-error but significant conditions.
76 notice,
77 /// Informational: general messages about the state of the program.
78 info,
79 /// Debug: messages only useful for debugging.
80 debug,
81};
82
83/// The default log level is based on build mode. Note that in ReleaseSmall
84/// builds the default level is emerg but no messages will be stored/logged
85/// by the default logger to save space.
86pub const default_level: Level = switch (builtin.mode) {
87 .Debug => .debug,
88 .ReleaseSafe => .notice,
89 .ReleaseFast => .err,
90 .ReleaseSmall => .emerg,
91};
92
93/// The current log level. This is set to root.log_level if present, otherwise
94/// log.default_level.
95pub const level: Level = if (@hasDecl(root, "log_level"))
96 root.log_level
97else
98 default_level;
99
100fn log(
101 comptime message_level: Level,
102 comptime scope: @Type(.EnumLiteral),
103 comptime format: []const u8,
104 args: var,
105) void {
106 if (@enumToInt(message_level) <= @enumToInt(level)) {
107 if (@hasDecl(root, "log")) {
108 root.log(message_level, scope, format, args);
109 } else if (builtin.mode != .ReleaseSmall) {
110 const held = std.debug.getStderrMutex().acquire();
111 defer held.release();
112 const stderr = io.getStdErr().writer();
113 nosuspend stderr.print(format, args) catch return;
114 }
115 }
116}
117
118/// Log an emergency message to stderr. This log level is intended to be used
119/// for conditions that cannot be handled and is usually followed by a panic.
120pub fn emerg(
121 comptime scope: @Type(.EnumLiteral),
122 comptime format: []const u8,
123 args: var,
124) void {
125 @setCold(true);
126 log(.emerg, scope, format, args);
127}
128
129/// Log an alert message to stderr. This log level is intended to be used for
130/// conditions that should be corrected immediately (e.g. database corruption).
131pub fn alert(
132 comptime scope: @Type(.EnumLiteral),
133 comptime format: []const u8,
134 args: var,
135) void {
136 @setCold(true);
137 log(.alert, scope, format, args);
138}
139
140/// Log a critical message to stderr. This log level is intended to be used
141/// when a bug has been detected or something has gone wrong and it will have
142/// an effect on the operation of the program.
143pub fn crit(
144 comptime scope: @Type(.EnumLiteral),
145 comptime format: []const u8,
146 args: var,
147) void {
148 @setCold(true);
149 log(.crit, scope, format, args);
150}
151
152/// Log an error message to stderr. This log level is intended to be used when
153/// a bug has been detected or something has gone wrong but it is recoverable.
154pub fn err(
155 comptime scope: @Type(.EnumLiteral),
156 comptime format: []const u8,
157 args: var,
158) void {
159 @setCold(true);
160 log(.err, scope, format, args);
161}
162
163/// Log a warning message to stderr. This log level is intended to be used if
164/// it is uncertain whether something has gone wrong or not, but the
165/// circumstances would be worth investigating.
166pub fn warn(
167 comptime scope: @Type(.EnumLiteral),
168 comptime format: []const u8,
169 args: var,
170) void {
171 log(.warn, scope, format, args);
172}
173
174/// Log a notice message to stderr. This log level is intended to be used for
175/// non-error but significant conditions.
176pub fn notice(
177 comptime scope: @Type(.EnumLiteral),
178 comptime format: []const u8,
179 args: var,
180) void {
181 log(.notice, scope, format, args);
182}
183
184/// Log an info message to stderr. This log level is intended to be used for
185/// general messages about the state of the program.
186pub fn info(
187 comptime scope: @Type(.EnumLiteral),
188 comptime format: []const u8,
189 args: var,
190) void {
191 log(.info, scope, format, args);
192}
193
194/// Log a debug message to stderr. This log level is intended to be used for
195/// messages which are only useful for debugging.
196pub fn debug(
197 comptime scope: @Type(.EnumLiteral),
198 comptime format: []const u8,
199 args: var,
200) void {
201 log(.debug, scope, format, args);
202}
lib/std/std.zig+1
...@@ -49,6 +49,7 @@ pub const heap = @import("heap.zig");...@@ -49,6 +49,7 @@ pub const heap = @import("heap.zig");
49pub const http = @import("http.zig");49pub const http = @import("http.zig");
50pub const io = @import("io.zig");50pub const io = @import("io.zig");
51pub const json = @import("json.zig");51pub const json = @import("json.zig");
52pub const log = @import("log.zig");
52pub const macho = @import("macho.zig");53pub const macho = @import("macho.zig");
53pub const math = @import("math.zig");54pub const math = @import("math.zig");
54pub const mem = @import("mem.zig");55pub const mem = @import("mem.zig");