diff --git a/src/jetzig/colors.zig b/src/jetzig/colors.zig index 36e4af0..af08bb8 100644 --- a/src/jetzig/colors.zig +++ b/src/jetzig/colors.zig @@ -101,15 +101,16 @@ pub fn runtimeWhite(allocator: std.mem.Allocator, message: []const u8) ![]const return try runtimeWrap(allocator, codes.white, message); } -pub fn duration(allocator: std.mem.Allocator, delta: i64) ![]const u8 { - var buf: [1024]u8 = undefined; - const formatted_duration = try std.fmt.bufPrint(&buf, "{}", .{std.fmt.fmtDurationSigned(delta)}); - - if (delta < 1000000) { - return try runtimeGreen(allocator, formatted_duration); - } else if (delta < 5000000) { - return try runtimeYellow(allocator, formatted_duration); - } else { - return try runtimeRed(allocator, formatted_duration); - } +pub fn duration(buf: *[256]u8, delta: i64) ![]const u8 { + const code = if (delta < 1000000) + codes.green + else if (delta < 5000000) + codes.yellow + else + codes.red; + return try std.fmt.bufPrint( + buf, + "{s}{s}m{}{s}{s}m", + .{ codes.escape, code, std.fmt.fmtDurationSigned(delta), codes.escape, codes.reset }, + ); } diff --git a/src/jetzig/loggers/DevelopmentLogger.zig b/src/jetzig/loggers/DevelopmentLogger.zig index 0f3998c..d510ff3 100644 --- a/src/jetzig/loggers/DevelopmentLogger.zig +++ b/src/jetzig/loggers/DevelopmentLogger.zig @@ -22,9 +22,9 @@ pub fn init( return .{ .allocator = allocator, .level = level, - .log_queue = log_queue, - .stdout_colorized = true, // TODO - .stderr_colorized = true, // TODO + .log_queue = log_queue, // TODO: stdout/stderr queues + .stdout_colorized = log_queue.is_tty, + .stderr_colorized = log_queue.is_tty, }; } @@ -40,9 +40,9 @@ pub fn log( const output = try std.fmt.allocPrint(self.allocator, message, args); defer self.allocator.free(output); - const timestamp = Timestamp.init(std.time.timestamp(), self.allocator); - const iso8601 = try timestamp.iso8601(); - defer self.allocator.free(iso8601); + const timestamp = Timestamp.init(std.time.timestamp()); + var timestamp_buf: [256]u8 = undefined; + const iso8601 = try timestamp.iso8601(×tamp_buf); const colorized = switch (level) { .TRACE, .DEBUG, .INFO => self.stdout_colorized, @@ -59,15 +59,15 @@ pub fn log( /// Log a one-liner including response status code, path, method, duration, etc. pub fn logRequest(self: DevelopmentLogger, request: *const jetzig.http.Request) !void { + var duration_buf: [256]u8 = undefined; const formatted_duration = if (self.stdout_colorized) - try jetzig.colors.duration(self.allocator, jetzig.util.duration(request.start_time)) + try jetzig.colors.duration(&duration_buf, jetzig.util.duration(request.start_time)) else - try std.fmt.allocPrint( - self.allocator, + try std.fmt.bufPrint( + &duration_buf, "{}", .{std.fmt.fmtDurationSigned(jetzig.util.duration(request.start_time))}, ); - defer self.allocator.free(formatted_duration); const status: jetzig.http.status_codes.TaggedStatusCode = switch (request.response.status_code) { inline else => |status_code| @unionInit( @@ -82,14 +82,19 @@ pub fn logRequest(self: DevelopmentLogger, request: *const jetzig.http.Request) else status.getFormatted(.{}); - const message = try std.fmt.allocPrint(self.allocator, "[{s}/{s}/{s}] {s}", .{ + const timestamp = Timestamp.init(std.time.timestamp()); + var timestamp_buf: [256]u8 = undefined; + const iso8601 = try timestamp.iso8601(×tamp_buf); + + const writer = self.log_queue.writer; + try writer.print("{s: >5} [{s}] [{s}/{s}/{s}] {s}\n", .{ + if (self.stdout_colorized) colorizedLogLevel(.INFO) else @tagName(.INFO), + iso8601, formatted_duration, request.fmtMethod(self.stdout_colorized), formatted_status, request.path.path, }); - defer self.allocator.free(message); - try self.log(.INFO, "{s}", .{message}); } fn colorizedLogLevel(comptime level: LogLevel) []const u8 { diff --git a/src/jetzig/loggers/JsonLogger.zig b/src/jetzig/loggers/JsonLogger.zig index 0399a77..4dd8cca 100644 --- a/src/jetzig/loggers/JsonLogger.zig +++ b/src/jetzig/loggers/JsonLogger.zig @@ -54,9 +54,9 @@ pub fn log( const output = try std.fmt.allocPrint(self.allocator, message, args); defer self.allocator.free(output); - const timestamp = Timestamp.init(std.time.timestamp(), self.allocator); - const iso8601 = try timestamp.iso8601(); - defer self.allocator.free(iso8601); + const timestamp = Timestamp.init(std.time.timestamp()); + var timestamp_buf: [256]u8 = undefined; + const iso8601 = try timestamp.iso8601(×tamp_buf); const file = self.getFile(level); const writer = file.writer(); @@ -80,9 +80,9 @@ pub fn logRequest(self: *const JsonLogger, request: *const jetzig.http.Request) const duration = jetzig.util.duration(request.start_time); - const timestamp = Timestamp.init(std.time.timestamp(), self.allocator); - const iso8601 = try timestamp.iso8601(); - defer self.allocator.free(iso8601); + const timestamp = Timestamp.init(std.time.timestamp()); + var timestamp_buf: [256]u8 = undefined; + const iso8601 = try timestamp.iso8601(×tamp_buf); const status = switch (request.response.status_code) { inline else => |status_code| @unionInit( diff --git a/src/jetzig/loggers/LogQueue.zig b/src/jetzig/loggers/LogQueue.zig index 26d8003..f3faf08 100644 --- a/src/jetzig/loggers/LogQueue.zig +++ b/src/jetzig/loggers/LogQueue.zig @@ -8,6 +8,9 @@ condition: *std.Thread.Condition, condition_mutex: *std.Thread.Mutex, writer: *Writer = undefined, reader: *Reader = undefined, +pool: std.ArrayList(*List.Node), +position: usize, +is_tty: bool = undefined, const LogQueue = @This(); @@ -21,6 +24,8 @@ pub fn init(allocator: std.mem.Allocator) !LogQueue { .condition = try allocator.create(std.Thread.Condition), .condition_mutex = try allocator.create(std.Thread.Mutex), .read_write_mutex = try allocator.create(std.Thread.Mutex), + .pool = std.ArrayList(*List.Node).init(allocator), + .position = 0, }; } @@ -29,6 +34,7 @@ pub fn setFile(self: *LogQueue, file: std.fs.File) !void { self.writer.* = Writer{ .file = file, .queue = self }; self.reader = try self.allocator.create(Reader); self.reader.* = Reader{ .file = file, .queue = self }; + self.is_tty = file.isTty(); } pub const Writer = struct { @@ -71,9 +77,17 @@ pub fn append(self: *LogQueue, message: []const u8) !void { self.read_write_mutex.lock(); defer self.read_write_mutex.unlock(); - const node = try self.allocator.create(List.Node); + const node = if (self.position >= self.pool.items.len) blk: { + self.position += 1; + break :blk try self.allocator.create(List.Node); + } else blk: { + self.position += 1; + break :blk self.pool.items[self.position - 1]; + }; + node.* = .{ .data = message }; self.list.append(node); + self.condition.signal(); } @@ -83,7 +97,12 @@ pub fn popFirst(self: *LogQueue) !?[]const u8 { if (self.list.popFirst()) |node| { const value = node.data; - self.allocator.destroy(node); + self.position -= 1; + if (self.position < self.pool.items.len) { + self.pool.items[self.position] = node; + } else { + try self.pool.append(node); + } return value; } else { return null; diff --git a/src/jetzig/types/Timestamp.zig b/src/jetzig/types/Timestamp.zig index 58c7720..bd43405 100644 --- a/src/jetzig/types/Timestamp.zig +++ b/src/jetzig/types/Timestamp.zig @@ -3,7 +3,6 @@ const std = @import("std"); const Self = @This(); timestamp: i64, -allocator: std.mem.Allocator, const constants = struct { pub const seconds_in_day: i64 = 60 * 60 * 24; @@ -12,18 +11,18 @@ const constants = struct { pub const epoch_year: i64 = 1970; }; -pub fn init(timestamp: i64, allocator: std.mem.Allocator) Self { - return .{ .allocator = allocator, .timestamp = timestamp }; +pub fn init(timestamp: i64) Self { + return .{ .timestamp = timestamp }; } -pub fn iso8601(self: *const Self) ![]const u8 { +pub fn iso8601(self: *const Self, buf: *[256]u8) ![]const u8 { const u32_year: u32 = @intCast(self.year()); const u32_month: u32 = @intCast(self.month()); const u32_day_of_month: u32 = @intCast(self.dayOfMonth()); const u32_hour: u32 = @intCast(self.hour()); const u32_minute: u32 = @intCast(self.minute()); const u32_second: u32 = @intCast(self.second()); - return try std.fmt.allocPrint(self.allocator, "{d:0>4}-{d:0>2}-{d:0>2} {d:0>2}:{d:0>2}:{d:0>2}", .{ + return try std.fmt.bufPrint(buf, "{d:0>4}-{d:0>2}-{d:0>2} {d:0>2}:{d:0>2}:{d:0>2}", .{ u32_year, u32_month, u32_day_of_month,