Skip to content

Commit 7a36f9c

Browse files
committed
Improve script logging
1 - Add a custom console.lp function to make our debug logs stand out from script logs. 2 - In some cases, significantly improve how JavaScript values are serialized in debug logs and in console.log.
1 parent 58a5fad commit 7a36f9c

File tree

3 files changed

+66
-26
lines changed

3 files changed

+66
-26
lines changed

src/browser/console/console.zig

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@
1919
const std = @import("std");
2020
const builtin = @import("builtin");
2121

22-
const JsObject = @import("../env.zig").Env.JsObject;
22+
const Allocator = std.mem.Allocator;
2323
const Page = @import("../page.zig").Page;
24+
const JsObject = @import("../env.zig").Env.JsObject;
2425

2526
const log = if (builtin.is_test) &test_capture else @import("../../log.zig");
2627

@@ -29,6 +30,13 @@ pub const Console = struct {
2930
timers: std.StringHashMapUnmanaged(u32) = .{},
3031
counts: std.StringHashMapUnmanaged(u32) = .{},
3132

33+
pub fn _lp(_: *const Console, values: []JsObject, page: *Page) !void {
34+
if (values.len == 0) {
35+
return;
36+
}
37+
log.fatal(.console, "lightpanda", .{ .args = try serializeValues(values, page) });
38+
}
39+
3240
pub fn _log(_: *const Console, values: []JsObject, page: *Page) !void {
3341
if (values.len == 0) {
3442
return;
@@ -134,12 +142,19 @@ pub const Console = struct {
134142
}
135143

136144
fn serializeValues(values: []JsObject, page: *Page) ![]const u8 {
145+
if (values.len == 0) {
146+
return "";
147+
}
148+
137149
const arena = page.call_arena;
150+
const separator = log.separator();
138151
var arr: std.ArrayListUnmanaged(u8) = .{};
139-
try arr.appendSlice(arena, try values[0].toString());
140-
for (values[1..]) |value| {
141-
try arr.append(arena, ' ');
142-
try arr.appendSlice(arena, try value.toString());
152+
153+
for (values, 1..) |value, i| {
154+
try arr.appendSlice(arena, separator);
155+
try arr.writer(arena).print("{d}: ", .{i});
156+
const serialized = if (builtin.mode == .Debug) value.toDetailString() else value.toString();
157+
try arr.appendSlice(arena, try serialized);
143158
}
144159
return arr.items;
145160
}

src/log.zig

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,17 @@ fn logLogfmt(comptime scope: Scope, level: Level, comptime msg: []const u8, data
173173
}
174174

175175
fn logPretty(comptime scope: Scope, level: Level, comptime msg: []const u8, data: anytype, writer: anytype) !void {
176-
try writer.writeAll(switch (level) {
177-
.debug => "\x1b[0;36mDEBUG\x1b[0m ",
178-
.info => "\x1b[0;32mINFO\x1b[0m ",
179-
.warn => "\x1b[0;33mWARN\x1b[0m ",
180-
.err => "\x1b[0;31mERROR\x1b[0m ",
181-
.fatal => "\x1b[0;35mFATAL\x1b[0m ",
182-
});
176+
if (scope == .console and level == .fatal and comptime std.mem.eql(u8, msg, "lightpanda")) {
177+
try writer.writeAll("\x1b[0;104mWARN ");
178+
} else {
179+
try writer.writeAll(switch (level) {
180+
.debug => "\x1b[0;36mDEBUG\x1b[0m ",
181+
.info => "\x1b[0;32mINFO\x1b[0m ",
182+
.warn => "\x1b[0;33mWARN\x1b[0m ",
183+
.err => "\x1b[0;31mERROR ",
184+
.fatal => "\x1b[0;35mFATAL ",
185+
});
186+
}
183187

184188
const prefix = @tagName(scope) ++ " : " ++ msg;
185189
try writer.writeAll(prefix);
@@ -194,7 +198,7 @@ fn logPretty(comptime scope: Scope, level: Level, comptime msg: []const u8, data
194198
if (@mod(padding, 2) == 1) {
195199
try writer.writeByte(' ');
196200
}
197-
try writer.print(" [+{d}ms]", .{elapsed()});
201+
try writer.print(" \x1b[0m[+{d}ms]", .{elapsed()});
198202
try writer.writeByte('\n');
199203
}
200204

src/runtime/js.zig

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,6 +1373,12 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
13731373
return valueToString(scope.call_arena, js_value, scope.isolate, scope.context);
13741374
}
13751375

1376+
pub fn toDetailString(self: JsObject) ![]const u8 {
1377+
const scope = self.scope;
1378+
const js_value = self.js_obj.toValue();
1379+
return valueToDetailString(scope.call_arena, js_value, scope.isolate, scope.context);
1380+
}
1381+
13761382
pub fn format(self: JsObject, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
13771383
return writer.writeAll(try self.toString());
13781384
}
@@ -2493,6 +2499,15 @@ fn Caller(comptime E: type, comptime State: type) type {
24932499
}
24942500

24952501
fn handleError(self: *Self, comptime Struct: type, comptime named_function: NamedFunction, err: anyerror, info: anytype) void {
2502+
if (builtin.mode == .Debug and log.enabled(.js, .warn) and @hasDecl(@TypeOf(info), "length")) {
2503+
const args_dump = self.serializeFunctionArgs(info) catch "failed to serialize args";
2504+
log.warn(.js, "function call error", .{
2505+
.name = named_function.full_name,
2506+
.err = err,
2507+
.args = args_dump,
2508+
});
2509+
}
2510+
24962511
const isolate = self.isolate;
24972512
var js_err: ?v8.Value = switch (err) {
24982513
error.InvalidArgument => createTypeException(isolate, "invalid argument"),
@@ -2635,15 +2650,6 @@ fn Caller(comptime E: type, comptime State: type) type {
26352650
const last_js_parameter = params_to_map.len - 1;
26362651
var is_variadic = false;
26372652

2638-
errdefer |err| if (builtin.mode == .Debug and log.enabled(.js, .warn)) {
2639-
const args_dump = self.serializeFunctionArgs(info) catch "failed to serialize args";
2640-
log.warn(.js, "function call error", .{
2641-
.name = named_function.full_name,
2642-
.err = err,
2643-
.args = args_dump,
2644-
});
2645-
};
2646-
26472653
{
26482654
// This is going to get complicated. If the last Zig paremeter
26492655
// is a slice AND the corresponding javascript parameter is
@@ -2710,6 +2716,7 @@ fn Caller(comptime E: type, comptime State: type) type {
27102716
const isolate = self.isolate;
27112717
const context = self.context;
27122718
const arena = self.call_arena;
2719+
const separator = log.separator();
27132720
const js_parameter_count = info.length();
27142721

27152722
var arr: std.ArrayListUnmanaged(u8) = .{};
@@ -2718,7 +2725,7 @@ fn Caller(comptime E: type, comptime State: type) type {
27182725
const value_string = try valueToDetailString(arena, js_value, isolate, context);
27192726
const value_type = try jsStringToZig(arena, try js_value.typeOf(isolate), isolate);
27202727
try std.fmt.format(arr.writer(arena), "{s}{d}: {s} ({s})", .{
2721-
log.separator(),
2728+
separator,
27222729
i + 1,
27232730
value_string,
27242731
value_type,
@@ -3057,9 +3064,23 @@ const TaggedAnyOpaque = struct {
30573064
subtype: ?SubType,
30583065
};
30593066

3060-
fn valueToDetailString(allocator: Allocator, value: v8.Value, isolate: v8.Isolate, context: v8.Context) ![]u8 {
3061-
const str = try value.toDetailString(context);
3062-
return jsStringToZig(allocator, str, isolate);
3067+
fn valueToDetailString(arena: Allocator, value: v8.Value, isolate: v8.Isolate, context: v8.Context) ![]u8 {
3068+
var str: ?v8.String = null;
3069+
if (value.isObject() and !value.isFunction()) {
3070+
str = try v8.Json.stringify(context, value, null);
3071+
3072+
if (str.?.lenUtf8(isolate) == 2) {
3073+
// {} isn't useful, null this so that we can get the toDetailString
3074+
// (which might also be useless, but maybe not)
3075+
str = null;
3076+
}
3077+
}
3078+
3079+
if (str == null) {
3080+
str = try value.toDetailString(context);
3081+
}
3082+
3083+
return jsStringToZig(arena, str.?, isolate);
30633084
}
30643085

30653086
fn valueToString(allocator: Allocator, value: v8.Value, isolate: v8.Isolate, context: v8.Context) ![]u8 {

0 commit comments

Comments
 (0)