Merge pull request #3365 from lightpanda-io/log-notes

log: allow 'note' to be silenced, log CLI tips
This commit is contained in:
Karl Seguin authored and GitHub committed 2026-09-01 15:36:19 +08:00
commit a43db3cbd2
3 files changed
+48 -13

No files matched your search

+31 -12
View File
@@ -34,6 +34,7 @@ pub const Scope = enum {
http,
js,
mcp,
note,
not_implemented,
scheduler,
storage,
@@ -178,6 +179,19 @@ pub fn warnDisabledIFrame() void {
}
pub fn log(scope: Scope, level: Level, msg: []const u8, data: anytype) void {
var kvs: [@typeInfo(@TypeOf(data)).@"struct".fields.len]KV = undefined;
initKVs(data, &kvs);
logKVs(scope, level, msg, &kvs);
}
inline fn initKVs(data: anytype, kvs: []KV) void {
inline for (@typeInfo(@TypeOf(data)).@"struct".fields, 0..) |f, i| {
const value = @field(data, f.name);
kvs[i] = .{ .key = f.name, .value = Value.init(&value) };
}
}
pub fn logKVs(scope: Scope, level: Level, msg: []const u8, kvs: []const KV) void {
if (enabled(scope, level) == false) {
return;
}
@@ -193,7 +207,7 @@ pub fn log(scope: Scope, level: Level, msg: []const u8, data: anytype) void {
if (sink) |s| {
var buf: [4096]u8 = undefined;
var w: std.Io.Writer = .fixed(&buf);
logTo(scope, level, msg, data, &w) catch |log_err| {
logToErased(scope, level, msg, kvs, &w) catch |log_err| {
std.debug.print("$time={d} $level=fatal $scope={s} $msg=\"log err\" err={s} log_msg=\"{s}\"\n", .{ timestamp(.real), @tagName(scope), @errorName(log_err), msg });
return;
};
@@ -205,20 +219,16 @@ pub fn log(scope: Scope, level: Level, msg: []const u8, data: anytype) void {
const stderr = std.debug.lockStderr(&buf);
defer std.debug.unlockStderr();
logTo(scope, level, msg, data, &stderr.file_writer.interface) catch |log_err| {
std.debug.print("$time={d} $level=fatal $scope={s} $msg=\"log err\" err={s} log_msg=\"{s}\"\n", .{ timestamp(.real), @errorName(log_err), @tagName(scope), msg });
logToErased(scope, level, msg, kvs, &stderr.file_writer.interface) catch |log_err| {
std.debug.print("$time={d} $level=fatal $scope={s} $msg=\"log err\" err={s} log_msg=\"{s}\"\n", .{ timestamp(.real), @tagName(scope), @errorName(log_err), msg });
};
}
// Converts each field of `data` into a runtime Value so that a single copy of
// the formatting code (logToErased and below) can do the actual writing.
// Like `log`, but to an explicit writer and without the enabled/sink
// gating. Only used by tests.
fn logTo(scope: Scope, level: Level, msg: []const u8, data: anytype, out: *std.Io.Writer) !void {
const fields = @typeInfo(@TypeOf(data)).@"struct".fields;
var kvs: [fields.len]KV = undefined;
inline for (fields, 0..) |f, i| {
const value = @field(data, f.name);
kvs[i] = .{ .key = f.name, .value = Value.init(&value) };
}
var kvs: [@typeInfo(@TypeOf(data)).@"struct".fields.len]KV = undefined;
initKVs(data, &kvs);
return logToErased(scope, level, msg, &kvs, out);
}
@@ -320,9 +330,18 @@ fn logPrettyPrefix(scope: Scope, level: Level, msg: []const u8, writer: *std.Io.
}
}
const KV = struct {
pub const KV = struct {
key: []const u8,
value: Value,
// `vp` is a pointer, as with Value.init. A string literal is already one;
// for anything else pass `&value` and keep it alive until the log call.
pub fn init(key: []const u8, vp: anytype) KV {
return .{
.key = key,
.value = .init(vp),
};
}
};
const Value = union(enum) {
+16
View File
@@ -94,6 +94,8 @@ fn run(allocator: Allocator, main_arena: Allocator, proc_args: std.process.Args)
app.telemetry.record(.{ .run = {} });
logConfigTips(app.config);
defer if (app.config.dumpMetricsOnExit()) {
var writer = std.Io.File.stdout().writerStreaming(lp.io, &.{});
lp.metrics.write(&writer.interface);
@@ -396,3 +398,17 @@ fn mcpThread(allocator: std.mem.Allocator, app: *App, cdp_server: ?*lp.Server, e
log.fatal(.mcp, "mcp error", .{ .err = err });
};
}
fn logConfigTips(config: *const Config) void {
var count: usize = 0;
var tips: [2]log.KV = undefined;
if (config.obeyRobots() == false) {
tips[count] = .init("robots", "use '--obey-robots' to use a sites robots.txt");
count += 1;
}
if (count > 0) {
tips[count] = .init("meta", "use '--log-filter note' to silence this message");
log.logKVs(.note, .note, "config tips", tips[0 .. count + 1]);
}
}
+1 -1
View File
@@ -151,7 +151,7 @@ pub fn init(app: *App, address: sys_net.IpAddress) !*Server {
const listener = try bindListener(app.config, &bound_address);
errdefer _ = std.c.close(listener);
pollfds[1] = .{ .fd = listener, .events = posix.POLL.IN, .revents = 0 };
log.note(.app, "server running", .{ .address = bound_address });
log.note(.note, "server running", .{ .address = bound_address });
const port = bound_address.getPort();
const json_version_response = try buildJSONVersionResponse(app, port);