This commit is contained in:
Bob Farrell 2024-05-10 18:28:01 +01:00
parent b39653b90f
commit a155e33121

View File

@ -37,24 +37,30 @@ pub fn setFile(self: *LogQueue, file: std.fs.File) !void {
self.is_tty = file.isTty(); self.is_tty = file.isTty();
} }
/// Writer for `LogQueue`. Receives log events and publishes to the queue.
pub const Writer = struct { pub const Writer = struct {
file: std.fs.File, file: std.fs.File,
queue: *LogQueue, queue: *LogQueue,
/// True if target output file is a TTY.
pub fn isTty(self: Writer) bool { pub fn isTty(self: Writer) bool {
return self.file.isTty(); return self.file.isTty();
} }
/// Print a log event.
pub fn print(self: *Writer, comptime message: []const u8, args: anytype) !void { pub fn print(self: *Writer, comptime message: []const u8, args: anytype) !void {
const output = try std.fmt.allocPrint(self.queue.allocator, message, args); const output = try std.fmt.allocPrint(self.queue.allocator, message, args);
try self.queue.append(output); try self.queue.append(output);
} }
}; };
/// Reader for `LogQueue`. Reads log events from the queue.
pub const Reader = struct { pub const Reader = struct {
file: std.fs.File, file: std.fs.File,
queue: *LogQueue, queue: *LogQueue,
/// Publish log events from the queue. Invoke from a dedicated thread. Sleeps when log queue
/// is empty, wakes up when a new event is published.
pub fn publish(self: *Reader) !void { pub fn publish(self: *Reader) !void {
const writer = self.file.writer(); const writer = self.file.writer();
while (true) { while (true) {
@ -73,17 +79,18 @@ pub const Reader = struct {
} }
}; };
pub fn append(self: *LogQueue, message: []const u8) !void { // Append a log event to the queue. Signal the publish loop thread to wake up. Recycle nodes if
// available in the pool, otherwise create a new one.
fn append(self: *LogQueue, message: []const u8) !void {
self.read_write_mutex.lock(); self.read_write_mutex.lock();
defer self.read_write_mutex.unlock(); defer self.read_write_mutex.unlock();
const node = if (self.position >= self.pool.items.len) blk: { const node = if (self.position >= self.pool.items.len) blk: {
self.position += 1;
break :blk try self.allocator.create(List.Node); break :blk try self.allocator.create(List.Node);
} else blk: { } else blk: {
self.position += 1; break :blk self.pool.items[self.position];
break :blk self.pool.items[self.position - 1];
}; };
self.position += 1;
node.* = .{ .data = message }; node.* = .{ .data = message };
self.list.append(node); self.list.append(node);
@ -91,7 +98,8 @@ pub fn append(self: *LogQueue, message: []const u8) !void {
self.condition.signal(); self.condition.signal();
} }
pub fn popFirst(self: *LogQueue) !?[]const u8 { // Pop a log event from the queue. Return node to the pool for re-use.
fn popFirst(self: *LogQueue) !?[]const u8 {
self.read_write_mutex.lock(); self.read_write_mutex.lock();
defer self.read_write_mutex.unlock(); defer self.read_write_mutex.unlock();
@ -101,7 +109,7 @@ pub fn popFirst(self: *LogQueue) !?[]const u8 {
if (self.position < self.pool.items.len) { if (self.position < self.pool.items.len) {
self.pool.items[self.position] = node; self.pool.items[self.position] = node;
} else { } else {
try self.pool.append(node); try self.pool.append(node); // TODO: Set a maximum here to avoid never-ending inflation.
} }
return value; return value;
} else { } else {