diff --git a/src/jetzig/colors.zig b/src/jetzig/colors.zig index e44a633..cc776d3 100644 --- a/src/jetzig/colors.zig +++ b/src/jetzig/colors.zig @@ -29,7 +29,7 @@ pub const codes = .{ }; /// Map color codes generated by `std.io.tty.Config.setColor` back to `std.io.tty.Color`. Used by -/// `jetzig.loggers.LogQueue.writeWindows` to parse escape codes so they can be passed to +/// `jetzig.util.writeAnsi` to parse escape codes so they can be passed to /// `std.io.tty.Config.setColor` (using Windows API to set console color mode). const ansi_colors = .{ .{ "30", .black }, diff --git a/src/jetzig/loggers/DevelopmentLogger.zig b/src/jetzig/loggers/DevelopmentLogger.zig index 91b77d0..dc4e207 100644 --- a/src/jetzig/loggers/DevelopmentLogger.zig +++ b/src/jetzig/loggers/DevelopmentLogger.zig @@ -57,7 +57,8 @@ pub fn log( const formatted_level = colorizedLogLevel(level); - try self.logWriter(level).print( + try self.print( + level, "{s: >5} [{s}] {s}\n", .{ formatted_level, iso8601, output }, ); @@ -93,7 +94,7 @@ pub fn logRequest(self: DevelopmentLogger, request: *const jetzig.http.Request) const formatted_level = if (self.stdout_colorized) colorizedLogLevel(.INFO) else @tagName(.INFO); - try self.logWriter(.INFO).print("{s: >5} [{s}] [{s}/{s}/{s}]{s}{s}{s}{s}{s}{s}{s}{s}{s}{s} {s}\n", .{ + try self.print(.INFO, "{s: >5} [{s}] [{s}/{s}/{s}]{s}{s}{s}{s}{s}{s}{s}{s}{s}{s} {s}\n", .{ formatted_level, iso8601, formatted_duration, @@ -118,7 +119,7 @@ pub fn logSql(self: *const DevelopmentLogger, event: jetzig.jetquery.events.Even // from multiple threads. JSON logger etc. write in one call and the log queue prevents // clobbering, but this is not the case here. const formatted_level = if (self.stdout_colorized) colorizedLogLevel(.INFO) else @tagName(.INFO); - try self.logWriter(.INFO).print("{s} [database] ", .{formatted_level}); + try self.print(.INFO, "{s} [database] ", .{formatted_level}); try self.printSql(event.sql orelse ""); var duration_buf: [256]u8 = undefined; @@ -128,7 +129,8 @@ pub fn logSql(self: *const DevelopmentLogger, event: jetzig.jetquery.events.Even self.stdout_colorized, ) else ""; - try self.logWriter(.INFO).print( + try self.print( + .INFO, std.fmt.comptimePrint(" [{s}]\n", .{jetzig.colors.cyan("{s}")}), .{formatted_duration}, ); @@ -233,7 +235,7 @@ fn printSql(self: *const DevelopmentLogger, sql: []const u8) !void { }, } } - try self.logWriter(.INFO).print("{s}", .{stream.getWritten()}); + try self.print(.INFO, "{s}", .{stream.getWritten()}); } pub fn logError(self: *const DevelopmentLogger, err: anyerror) !void { @@ -249,12 +251,41 @@ pub fn logError(self: *const DevelopmentLogger, err: anyerror) !void { try self.log(.ERROR, "Encountered Error: {s}", .{@errorName(err)}); } -fn logWriter(self: DevelopmentLogger, comptime level: jetzig.loggers.LogLevel) std.fs.File.Writer { +fn logFile(self: DevelopmentLogger, comptime level: jetzig.loggers.LogLevel) std.fs.File { const target = comptime jetzig.loggers.logTarget(level); return switch (target) { .stdout => self.stdout, .stderr => self.stderr, - }.writer(); + }; +} + +fn logWriter(self: DevelopmentLogger, comptime level: jetzig.loggers.LogLevel) std.fs.File.Writer { + return self.logFile(level).writer(); +} + +fn print( + self: DevelopmentLogger, + comptime level: jetzig.loggers.LogLevel, + comptime template: []const u8, + args: anytype, +) !void { + const log_writer = self.logWriter(level); + const count = std.fmt.count(template, args); + const buf_size = 4096; + if (count <= buf_size) { + var buf: [buf_size]u8 = undefined; + var stream = std.io.fixedBufferStream(&buf); + const writer = stream.writer(); + try writer.print(template, args); + try jetzig.util.writeAnsi(self.logFile(level), log_writer, stream.getWritten()); + } else { + const buf = try self.allocator.alloc(u8, count); + defer self.allocator.free(buf); + var stream = std.io.fixedBufferStream(buf); + const writer = stream.writer(); + try writer.print(template, args); + try jetzig.util.writeAnsi(self.logFile(level), log_writer, stream.getWritten()); + } } inline fn colorizedLogLevel(comptime level: LogLevel) []const u8 { diff --git a/src/jetzig/loggers/LogQueue.zig b/src/jetzig/loggers/LogQueue.zig index 5a65790..97002e3 100644 --- a/src/jetzig/loggers/LogQueue.zig +++ b/src/jetzig/loggers/LogQueue.zig @@ -164,7 +164,6 @@ pub const Reader = struct { var stdout_written = false; var stderr_written = false; var file: std.fs.File = undefined; - var colorize = false; while (try self.queue.popFirst()) |event| { self.queue.writer.mutex.lock(); @@ -175,14 +174,12 @@ pub const Reader = struct { stdout_written = true; if (builtin.os.tag == .windows) { file = self.stdout_file; - colorize = self.queue.stdout_colorize; } }, .stderr => { stderr_written = true; if (builtin.os.tag == .windows) { file = self.stderr_file; - colorize = self.queue.stderr_colorize; } }, } @@ -199,7 +196,7 @@ pub const Reader = struct { continue; } - try jetzig.util.writeAnsi(file, writer, event.message[0..event.len]); + try writer.writeAll(event.message[0..event.len]); self.queue.writer.position -= 1; @@ -270,26 +267,6 @@ fn initPool(allocator: std.mem.Allocator, T: type) std.heap.MemoryPool(T) { return std.heap.MemoryPool(T).initPreheated(allocator, max_pool_len) catch @panic("OOM"); } -fn writeWindows(file: std.fs.File, writer: anytype, event: Event) !void { - var info: std.os.windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; - _ = std.os.windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info); - - var it = std.mem.tokenizeSequence(u8, event.message[0..event.len], "\x1b["); - while (it.next()) |token| { - if (std.mem.indexOfScalar(u8, token, 'm')) |index| { - if (index > 0 and index + 1 < token.len) { - if (jetzig.colors.windows_map.get(token[0..index])) |color| { - try std.os.windows.SetConsoleTextAttribute(file.handle, color); - try writer.writeAll(token[index + 1 ..]); - continue; - } - } - } - // Fallback - try writer.writeAll(token); - } -} - test "print to stdout and stderr" { var log_queue = LogQueue.init(std.testing.allocator); defer log_queue.deinit();