vercel-labs / vercel-labs/native

native dev: default events trace floods stdout with the 500ms markup-watch timer

Open
#418 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Zig
Stars
7.7k
Forks
314
Avg merge
5h
Merged PRs (30d)
13

Description

Symptom

native dev prints this pair of lines about twice a second for as long as the app is running:

ts=1788398844994007000 level=info kind=event name="runtime.event" event="timer"
ts=1788398845494030000 level=info kind=event name="runtime.event" event="timer"

The terminal is unusable as a log: real start/stop, pointer, and error lines are buried under a heartbeat. Reproduced on @native-sdk/cli 0.10.1 with a stock TypeScript + Native markup app (src/core.ts, src/app.native, app.json). The app has no Sub.timer and no Cmd.delay.

Why

native dev builds Debug with the default trace mode events (build/app.zig: -Dtrace defaults to .events). That mode prints every record named runtime.event. Every platform event is logged in src/runtime/flow.zig (dispatchEventlog(..., "runtime.event", ...)), including .timer.

Debug also arms markup hot reload. UiApp.startMarkupWatch starts a repeating runtime timer at 500ms (markup_watch_timer_id / markup_watch_interval_ns in src/runtime/ui_app.zig). Each poll is a .timer event, so the default events trace prints two lines per second for the whole session.

The timer itself is the right behavior: it is how .native files reload without restarting. Only the log is the problem.

Workaround today: native dev -Dtrace=off. That compiles tracing out. It is a rebuild flag, not a runtime switch, and it is easy to miss because native --help only shows -D... zig build flags.

Proposed fix

Keep the 500ms markup-watch timer. Stop printing it on the default native dev path.

A small change that matches the existing filter: under -Dtrace=events, skip .timer events whose id is a reserved framework timer (markup_watch_timer_id, and any other id at or above platform.reserved_timer_id_base). App-owned timers and pointer/frame events would still show. -Dtrace=all would keep the full firehose.

Defaulting native dev to -Dtrace=off would also silence this, but it would hide the rest of the events log too. Filtering the watch poll from events keeps a useful default.

Checking it

  1. native init a TypeScript + Native markup app.
  2. Run native dev with no extra flags.
  3. After the window is up, stdout should stay quiet aside from the usual build/start lines — no repeating event="timer" lines.
  4. Saving src/app.native should still hot-reload the window.
  5. native dev -Dtrace=all should still print the watch-timer events if someone wants them.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the default trace setting in build/app.zig, then follow dispatchEvent and log in src/runtime/flow.zig. Read the markup-watch timer setup in src/runtime/ui_app.zig, including markup_watch_timer_id and markup_watch_interval_ns. Verify that native dev no longer repeats timer lines, hot reload still works, and -Dtrace=all still shows them.

Written by the indexing model from the issue text.

Assessment

Tech stack
zig
Domain
desktop, observability
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.