Fancy logger hopefully

This commit is contained in:
Lyssieth 2024-12-01 04:43:08 +02:00
parent 864322bd88
commit 954b62d4a0
Signed by untrusted user who does not match committer: lyssieth
GPG key ID: 200268854934CFAB

View file

@ -6,6 +6,24 @@ const log = std.log;
pub const Level = log.Level;
pub const Scope = @Type(.EnumLiteral);
pub const Color = enum {
red,
green,
yellow,
blue,
magenta,
cyan,
white,
default,
};
pub const ScopeModifier = struct {
scope: Scope,
color: ?Color = .default,
bright: bool = false,
rename: ?[]const u8 = null,
};
const Allocator = std.mem.Allocator;
const Globals = struct {
@ -14,13 +32,25 @@ const Globals = struct {
enableFileOutput: bool = false,
outputFile: ?std.fs.File = null,
additionalScopes: std.ArrayList(ScopeModifier),
fn arena(self: *Globals) std.heap.ArenaAllocator {
return std.heap.ArenaAllocator.init(self.allocator);
}
fn initOrGetFile(self: *Globals) !std.fs.File {
if (self.outputFile) |file| {
return file;
} else {
return error.NoFileSet;
}
}
fn init(allocator: Allocator) !Globals {
return .{
allocator,
.allocator = allocator,
.additionalScopes = std.ArrayList(ScopeModifier).init(allocator),
};
}
@ -29,6 +59,8 @@ const Globals = struct {
file.close();
}
self.additionalScopes.deinit();
self.* = undefined;
}
};
@ -67,6 +99,14 @@ pub const config = struct {
unreachable; // logging is not initialized
}
}
pub fn addScope(modifier: ScopeModifier) !void {
if (core) |*globals| {
try globals.additionalScopes.append(modifier);
} else {
unreachable; // logging is not initialized
}
}
};
pub fn init(allocator: Allocator) !void {
@ -79,6 +119,8 @@ pub fn deinit() void {
}
}
var longestScopeYet: usize = 0;
/// If using this log function, you *must* call `init` before any logging occurs.
/// Otherwise, it will complain. A lot.
pub fn logFn(comptime level: Level, comptime scope: Scope, comptime format: []const u8, args: anytype) void {
@ -87,18 +129,97 @@ pub fn logFn(comptime level: Level, comptime scope: Scope, comptime format: []co
};
}
fn get() !*Globals {
return &core orelse error.NotInitialized;
}
fn logFnImpl(comptime level: Level, comptime scope: Scope, comptime format: []const u8, args: anytype) !void {
var arena = core.?.arena();
const globals = try get();
var arena = globals.arena();
const c = cham.initRuntime(.{
.allocator = arena.allocator(),
});
defer {
c.deinit();
arena.deinit();
}
_ = c;
var scopeLen = 4;
const scopeText = switch (scope) {
.default => "main",
.gpa => gpaBlock: {
const gpa = "General Purpose Allocator";
scopeLen = gpa;
_ = level;
_ = scope;
_ = format;
_ = args;
break :gpaBlock try c.redBright().fmt("{s}", .{gpa});
},
return error.NotImplemented;
else => elseBlock: {
for (globals.additionalScopes.items) |modifier| {
if (modifier.scope == scope) {
const text = blk: {
if (modifier.rename) |rename| {
break :blk rename;
} else {
break :blk @tagName(scope);
}
};
scopeLen = text.len;
if (modifier.color) |color| {
switch (color) {
.default => break :elseBlock text,
.blue => break :elseBlock try c.blue().fmt("{s}", .{text}),
.green => break :elseBlock try c.green().fmt("{s}", .{text}),
.red => break :elseBlock try c.red().fmt("{s}", .{text}),
.white => break :elseBlock try c.white().fmt("{s}", .{text}),
.yellow => break :elseBlock try c.yellow().fmt("{s}", .{text}),
.magenta => break :elseBlock try c.magenta().fmt("{s}", .{text}),
.cyan => break :elseBlock try c.cyan().fmt("{s}", .{text}),
}
} else {
break :elseBlock text;
}
}
}
},
};
longestScopeYet = std.math.max(longestScopeYet, scopeLen);
const levelText = switch (level) {
.debug => try c.gray().fmt("{s: >5}", .{"DEBUG"}),
.info => try c.white().fmt("{s: >5}", .{"INFO"}),
.warn => try c.yellow().fmt("{s: >5}", .{"WARN"}),
.err => try c.red().fmt("{s: >5}", .{"ERROR"}),
};
const paddingLen = longestScopeYet - scopeLen;
const padding = try arena.allocator().alloc(u8, paddingLen);
for (padding) |*p| p.* = ' ';
const prefix = try std.fmt.allocPrint(arena.allocator(), "[{s}] [{s}{s}]", .{
levelText,
padding,
scopeText,
});
const message = try std.fmt.allocPrint(arena.allocator(), format, args);
if (globals.enableFileOutput) {
var file = try globals.initOrGetFile();
var writer = file.writer().any();
nosuspend try writer.print("{s} {s}\n", .{
prefix,
message,
});
} else {
nosuspend std.debug.print("{s} {s}\n", .{
prefix,
message,
});
}
}