journal.zig (4193B)
1 const std = @import("std"); 2 3 const mem = @import("./mem.zig"); 4 // Kinda like std.log but journaling 5 // In the future this would use runtime formatting 6 7 pub const LogLevel = enum(u8) { 8 // "The system is probably dead" 9 Emergency = 0, 10 // "A problem that requires immediate attention" 11 Alert = 1, 12 // Something has gone wrong, possibly recoverable 13 Error = 2, 14 // It is uncertain if something has gone wrong or not 15 Warning = 3, 16 // "Normal but perhaps noteworthy" 17 Notice = 4, 18 // General messages 19 Info = 5, 20 // Messages only useful for debugging 21 Debug = 6, 22 23 pub fn text(comptime self: LogLevel) []const u8 { 24 return switch (self) { 25 .Emergency => "emergency", 26 .Alert => "alert", 27 .Error => "error", 28 .Warning => "warning", 29 .Notice => "notice", 30 .Info => "info", 31 .Debug => "debug", 32 }; 33 } 34 35 pub fn text_short(comptime self: LogLevel) u8 { 36 return switch (self) { 37 .Emergency => '!', 38 .Alert => 'A', 39 .Error => 'E', 40 .Warning => 'W', 41 .Notice => 'N', 42 .Info => 'I', 43 .Debug => 'D', 44 }; 45 } 46 }; 47 48 pub const LogWriter = struct { 49 node: std.SinglyLinkedList.Node, 50 writer: *std.Io.Writer, 51 }; 52 53 var log_level: LogLevel = .Info; 54 var writers: std.SinglyLinkedList = .{ .first = null }; 55 56 // TODO; shouldn't have static buffer 57 var buffer: [1024 * 1024]u8 = undefined; 58 var fba: std.heap.FixedBufferAllocator = .init(&buffer); 59 60 pub inline fn set_log_level(level: LogLevel) void { 61 log_level = level; 62 } 63 64 pub fn log(comptime level: LogLevel, comptime scope: []const u8, comptime format: []const u8, args: anytype) void { 65 const level_txt = comptime level.text_short(); 66 const prefix = if (scope.len == 0) ": " else scope ++ ": "; 67 68 const cs = mem.enter_critical_section(); 69 defer cs.exit(); 70 71 var head = writers.first; 72 while (head) |writer| { 73 const node: *LogWriter = @fieldParentPtr("node", writer); 74 75 node.writer.print(level_txt ++ prefix ++ format ++ "\n", args) catch { 76 // TODO; queue write error 77 continue; 78 }; 79 80 head = writer.next; 81 } 82 } 83 84 pub fn push_writer(w: *std.Io.Writer) void { 85 var writer = try fba.allocator().create(LogWriter); 86 writer.writer = w; 87 writers.prepend(&writer.node); 88 } 89 90 pub fn pop_writer(w: *std.Io.Writer) void { 91 var head = writers.first; 92 while (head) |writer| { 93 const node: *LogWriter = @fieldParentPtr("node", writer); 94 95 if (node.writer == w) { 96 writers.remove(node); 97 return; 98 } 99 100 head = writer.next; 101 } 102 } 103 104 pub fn scoped(comptime scope: []const u8) type { 105 return struct { 106 pub fn emergency(comptime format: []const u8, args: anytype) void { 107 @branchHint(.cold); 108 log(.Emergency, scope, format, args); 109 } 110 111 pub fn alert(comptime format: []const u8, args: anytype) void { 112 @branchHint(.cold); 113 log(.Alert, scope, format, args); 114 } 115 116 pub fn err(comptime format: []const u8, args: anytype) void { 117 @branchHint(.cold); 118 log(.Error, scope, format, args); 119 } 120 121 pub fn warn(comptime format: []const u8, args: anytype) void { 122 @branchHint(.cold); 123 log(.Warning, scope, format, args); 124 } 125 126 pub fn notice(comptime format: []const u8, args: anytype) void { 127 @branchHint(.cold); 128 log(.Notice, scope, format, args); 129 } 130 131 pub fn info(comptime format: []const u8, args: anytype) void { 132 @branchHint(.cold); 133 log(.Info, scope, format, args); 134 } 135 136 pub fn debug(comptime format: []const u8, args: anytype) void { 137 @branchHint(.cold); 138 log(.Debug, scope, format, args); 139 } 140 }; 141 } 142 143 const default = scoped(""); 144 pub const emergency = default.emergency; 145 pub const alert = default.alert; 146 pub const err = default.err; 147 pub const warning = default.warn; 148 pub const notice = default.notice; 149 pub const info = default.info; 150 pub const debug = default.debug;