Skip to content

fix(log): send the page's own log somewhere it can be read - #79

Merged
glennmichael123 merged 1 commit into
mainfrom
fix/page-log-sink
Aug 27, 2026
Merged

fix(log): send the page's own log somewhere it can be read#79
glennmichael123 merged 1 commit into
mainfrom
fix/page-log-sink

Conversation

@glennmichael123

Copy link
Copy Markdown
Contributor

Follow-up to #70. That issue's ask was the --log-file flag, which #78 delivered — but it also noted, separately, that the page-facing craft.log.* namespace was macOS-only and discarded its payload elsewhere. I didn't do that half, so here it is.

What it did

if (builtin.os.tag == .macos) {
    std.debug.print("[craft.{s}] {s}\n", .{ level, message });
}
bridge_error.sendResultToJS(self.allocator, "log", "{\"ok\":true}");

On Linux and Windows the payload was parsed, discarded, and answered {"ok":true}. A page that logged into that got a resolved promise and no record anywhere.

On macOS it went to stderr rather than through the host logger — so --log-file, which now exists, did not contain it either.

What it does now

Page records go through log.zig, the same sink --log-file configures, on every platform:

[2026-08-27T13:31:14Z] INFO [page] hello from the page
[2026-08-27T13:31:14Z] WARN [page] a warning from the page
[2026-08-27T13:31:14Z] ERROR [page] and an error

Verified by running the binary with --log-file --log-quiet and a page calling all four methods. The debug call is correctly absent — default level is info — and appears when --log-level debug is passed.

  • Tagged [page], because the host's records and the page's now share one stream and telling them apart is most of what makes that stream readable.
  • An unrecognised level is recorded as info, not dropped — silently discarding it would be the same failure this file already had.
  • The message is clamped, because it comes from the page.

The dead os_log handle

os_log_create("com.craft.app", "default") was called at init, stored, and never used. The comment beside it described a future revision reaching os_log properly through libBlocksRuntime — which never happened, and which a file sink is a better answer to. Removed rather than left as a placeholder for something that now has a better implementation.

Tests

The file had none, which is why nobody noticed two of three platforms recorded nothing. The level mapping is now a pure function with 5 tests, wired into zig build test — including that an invented level is still heard, and that the four levels the JS facade actually sends all map somewhere.

Verified

zig build · zig build test · zig build test-js · x86_64-windows cross-build · zig fmt --check · 511 bun tests · pickier 38 warnings, unchanged from main.

`craft.log.{debug,info,warn,error}` reached `std.debug.print` on macOS and
nothing at all anywhere else: the write sat behind
`if (builtin.os.tag == .macos)`, so on Linux and Windows the payload was
parsed, discarded, and answered `{"ok":true}`. A page that logged into that got
a resolved promise and no record.

Even on macOS it went to stderr rather than through the host logger, so
`--log-file` — which now exists — did not contain it. A page's diagnostics and
the host's belong in one stream, in one order; splitting them across two
destinations on one platform and dropping them on the others is most of what
made the namespace useless.

Records are tagged `[page]` so it is obvious which side a line came from, an
unrecognised level is recorded as info rather than dropped, and the message is
clamped, because it comes from the page.

The `os_log_create` handle is gone. It was opened at init, never used, and the
comment beside it described a future revision that would reach `os_log`
properly through libBlocksRuntime — which never happened, and which a file sink
is a better answer to anyway.

The file had no tests, which is why nobody noticed two of the three platforms
recorded nothing.
@github-actions

Copy link
Copy Markdown

✅ Binary load time

rounds:    25 interleaved
base:      p50 26.0ms   p95 27.7ms   (25.0–28.2ms)
head:      p50 26.1ms   p95 27.5ms   (24.8–28.0ms)
delta:     +0.3%  (fails above +20.0%)

No binary load time regression.
What this measures

craft --help: process spawn, dynamic linking and argument parsing.
It never opens a window, so it cannot see a change in window or
webview startup — real startup is benchmarks/startup.bench.ts, which
needs a display.

Both binaries are measured interleaved on this runner and compared by
p50, rather than against a number recorded on another machine. On
byte-identical binaries that method reads within ~3.5%; the old one
swung 45%.

@github-actions

Copy link
Copy Markdown

✅ Binary Size Report

Metric Value
Current Size 14251KB (13.91MB)
Change 0KB (0%) unchanged
Size limits
  • Warning: 14.50MB
  • Maximum: 16.00MB

@glennmichael123
glennmichael123 merged commit bc35ed9 into main Aug 27, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant