mirror of
https://github.com/jetzig-framework/jetzig.git
synced 2025-05-14 22:16:08 +00:00
WIP
This commit is contained in:
parent
6575add452
commit
0ff19d5d26
@ -75,10 +75,20 @@ pub fn start(self: App, routes_module: type, options: AppOptions) !void {
|
||||
);
|
||||
defer cache.deinit();
|
||||
|
||||
const server_options = try self.environment.getServerOptions();
|
||||
var log_queue = try jetzig.loggers.LogQueue.init(self.allocator);
|
||||
try log_queue.setFile(std.io.getStdOut());
|
||||
|
||||
const server_options = try self.environment.getServerOptions(&log_queue);
|
||||
defer self.allocator.free(server_options.bind);
|
||||
defer self.allocator.free(server_options.secret);
|
||||
|
||||
var log_thread = try std.Thread.spawn(
|
||||
.{ .allocator = self.allocator },
|
||||
jetzig.loggers.LogQueue.Reader.publish,
|
||||
.{log_queue.reader},
|
||||
);
|
||||
defer log_thread.join();
|
||||
|
||||
if (server_options.detach) {
|
||||
const argv = try std.process.argsAlloc(self.allocator);
|
||||
defer std.process.argsFree(self.allocator, argv);
|
||||
|
@ -59,7 +59,10 @@ pub fn init(allocator: std.mem.Allocator) Environment {
|
||||
}
|
||||
|
||||
/// Generate server initialization options using command line args with defaults.
|
||||
pub fn getServerOptions(self: Environment) !jetzig.http.Server.ServerOptions {
|
||||
pub fn getServerOptions(
|
||||
self: Environment,
|
||||
log_queue: *jetzig.loggers.LogQueue,
|
||||
) !jetzig.http.Server.ServerOptions {
|
||||
const options = try args.parseForCurrentProcess(Options, self.allocator, .print);
|
||||
defer options.deinit();
|
||||
|
||||
@ -72,22 +75,24 @@ pub fn getServerOptions(self: Environment) !jetzig.http.Server.ServerOptions {
|
||||
const environment = options.options.environment;
|
||||
|
||||
var logger = switch (options.options.@"log-format") {
|
||||
.development => jetzig.loggers.Logger{
|
||||
.development, .json => jetzig.loggers.Logger{
|
||||
.development_logger = jetzig.loggers.DevelopmentLogger.init(
|
||||
self.allocator,
|
||||
resolveLogLevel(options.options.@"log-level", environment),
|
||||
try getLogFile(.stdout, options.options),
|
||||
try getLogFile(.stderr, options.options),
|
||||
),
|
||||
},
|
||||
.json => jetzig.loggers.Logger{
|
||||
.json_logger = jetzig.loggers.JsonLogger.init(
|
||||
self.allocator,
|
||||
resolveLogLevel(options.options.@"log-level", environment),
|
||||
try getLogFile(.stdout, options.options),
|
||||
try getLogFile(.stderr, options.options),
|
||||
log_queue,
|
||||
// try getLogFile(.stdout, options.options),
|
||||
// try getLogFile(.stderr, options.options),
|
||||
),
|
||||
},
|
||||
// TODO
|
||||
// .json => jetzig.loggers.Logger{
|
||||
// .json_logger = jetzig.loggers.JsonLogger.init(
|
||||
// self.allocator,
|
||||
// resolveLogLevel(options.options.@"log-level", environment),
|
||||
// try getLogFile(.stdout, options.options),
|
||||
// try getLogFile(.stderr, options.options),
|
||||
// ),
|
||||
// },
|
||||
};
|
||||
|
||||
if (options.options.detach and std.mem.eql(u8, options.options.log, "-")) {
|
||||
|
@ -6,6 +6,7 @@ const Self = @This();
|
||||
|
||||
pub const DevelopmentLogger = @import("loggers/DevelopmentLogger.zig");
|
||||
pub const JsonLogger = @import("loggers/JsonLogger.zig");
|
||||
pub const LogQueue = @import("loggers/LogQueue.zig");
|
||||
|
||||
pub const LogLevel = enum(u4) { TRACE, DEBUG, INFO, WARN, ERROR, FATAL };
|
||||
pub const LogFormat = enum { development, json };
|
||||
|
@ -8,28 +8,23 @@ const Timestamp = jetzig.types.Timestamp;
|
||||
const LogLevel = jetzig.loggers.LogLevel;
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
stdout: std.fs.File,
|
||||
stderr: std.fs.File,
|
||||
stdout_colorized: bool,
|
||||
stderr_colorized: bool,
|
||||
level: LogLevel,
|
||||
mutex: std.Thread.Mutex,
|
||||
log_queue: *jetzig.loggers.LogQueue,
|
||||
|
||||
/// Initialize a new Development Logger.
|
||||
pub fn init(
|
||||
allocator: std.mem.Allocator,
|
||||
level: LogLevel,
|
||||
stdout: std.fs.File,
|
||||
stderr: std.fs.File,
|
||||
log_queue: *jetzig.loggers.LogQueue,
|
||||
) DevelopmentLogger {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.level = level,
|
||||
.stdout = stdout,
|
||||
.stderr = stderr,
|
||||
.stdout_colorized = stdout.isTty(),
|
||||
.stderr_colorized = stderr.isTty(),
|
||||
.mutex = std.Thread.Mutex{},
|
||||
.log_queue = log_queue,
|
||||
.stdout_colorized = true, // TODO
|
||||
.stderr_colorized = true, // TODO
|
||||
};
|
||||
}
|
||||
|
||||
@ -53,19 +48,13 @@ pub fn log(
|
||||
.TRACE, .DEBUG, .INFO => self.stdout_colorized,
|
||||
.WARN, .ERROR, .FATAL => self.stderr_colorized,
|
||||
};
|
||||
const file = switch (level) {
|
||||
.TRACE, .DEBUG, .INFO => self.stdout,
|
||||
.WARN, .ERROR, .FATAL => self.stderr,
|
||||
const writer = switch (level) {
|
||||
.TRACE, .DEBUG, .INFO => self.log_queue.writer,
|
||||
.WARN, .ERROR, .FATAL => self.log_queue.writer,
|
||||
};
|
||||
const writer = file.writer();
|
||||
const level_formatted = if (colorized) colorizedLogLevel(level) else @tagName(level);
|
||||
|
||||
@constCast(self).mutex.lock();
|
||||
defer @constCast(self).mutex.unlock();
|
||||
|
||||
try writer.print("{s: >5} [{s}] {s}\n", .{ level_formatted, iso8601, output });
|
||||
|
||||
if (!file.isTty()) try file.sync();
|
||||
}
|
||||
|
||||
/// Log a one-liner including response status code, path, method, duration, etc.
|
||||
|
92
src/jetzig/loggers/LogQueue.zig
Normal file
92
src/jetzig/loggers/LogQueue.zig
Normal file
@ -0,0 +1,92 @@
|
||||
const std = @import("std");
|
||||
|
||||
const List = std.DoublyLinkedList([]const u8);
|
||||
allocator: std.mem.Allocator,
|
||||
list: *List,
|
||||
read_write_mutex: *std.Thread.Mutex,
|
||||
condition: *std.Thread.Condition,
|
||||
condition_mutex: *std.Thread.Mutex,
|
||||
writer: *Writer = undefined,
|
||||
reader: *Reader = undefined,
|
||||
|
||||
const LogQueue = @This();
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator) !LogQueue {
|
||||
const list = try allocator.create(std.DoublyLinkedList([]const u8));
|
||||
list.* = .{};
|
||||
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.list = list,
|
||||
.condition = try allocator.create(std.Thread.Condition),
|
||||
.condition_mutex = try allocator.create(std.Thread.Mutex),
|
||||
.read_write_mutex = try allocator.create(std.Thread.Mutex),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn setFile(self: *LogQueue, file: std.fs.File) !void {
|
||||
self.writer = try self.allocator.create(Writer);
|
||||
self.writer.* = Writer{ .file = file, .queue = self };
|
||||
self.reader = try self.allocator.create(Reader);
|
||||
self.reader.* = Reader{ .file = file, .queue = self };
|
||||
}
|
||||
|
||||
pub const Writer = struct {
|
||||
file: std.fs.File,
|
||||
queue: *LogQueue,
|
||||
|
||||
pub fn isTty(self: Writer) bool {
|
||||
return self.file.isTty();
|
||||
}
|
||||
|
||||
pub fn print(self: *Writer, comptime message: []const u8, args: anytype) !void {
|
||||
const output = try std.fmt.allocPrint(self.queue.allocator, message, args);
|
||||
defer self.queue.allocator.free(output);
|
||||
try self.queue.append(output);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Reader = struct {
|
||||
file: std.fs.File,
|
||||
queue: *LogQueue,
|
||||
|
||||
pub fn publish(self: *Reader) !void {
|
||||
const writer = self.file.writer();
|
||||
while (true) {
|
||||
self.queue.condition_mutex.lock();
|
||||
defer self.queue.condition_mutex.unlock();
|
||||
|
||||
self.queue.condition.wait(self.queue.condition_mutex);
|
||||
|
||||
while (try self.queue.popFirst()) |message| {
|
||||
defer self.queue.allocator.free(message);
|
||||
try writer.writeAll(message);
|
||||
}
|
||||
|
||||
if (!self.file.isTty()) try self.file.sync();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
node.* = .{ .data = try self.allocator.dupe(u8, message) };
|
||||
self.list.append(node);
|
||||
self.condition.signal();
|
||||
}
|
||||
|
||||
pub fn popFirst(self: *LogQueue) !?[]const u8 {
|
||||
self.read_write_mutex.lock();
|
||||
defer self.read_write_mutex.unlock();
|
||||
|
||||
if (self.list.popFirst()) |node| {
|
||||
const value = node.data;
|
||||
self.allocator.destroy(node);
|
||||
return value;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user