Skip to content

feat(logging): route diagnostics through tracing with a rolling file sink - #45

Closed
Lyrex wants to merge 3 commits into
WyrmStudios:mainfrom
Lyrex:tracing-logging
Closed

Lyrex wants to merge 3 commits into
WyrmStudios:mainfrom
Lyrex:tracing-logging

Conversation

@Lyrex

@Lyrex Lyrex commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

feat(logging): route diagnostics through tracing with a rolling file sink

Three commits, meant to be reviewed in order: subscriber, then the mechanical
eprintln! sweep, then the spans. If you want the first and not the rest, the
first stands alone.

The problem, stated narrowly. There are 40 eprintln!/println! diagnostics
across lib.rs, memory_scanner.rs and wfcd.rs. They go to stderr, which a
packaged Tauri app does not have, so in the field they go nowhere. They are also
all-or-nothing: there is no way to ask a user for scanner detail without asking for
everything.

What this is not. You already have file logging: append_to_file /
append_to_diag, 35 call sites, writing %TEMP%\frameforge_riven_session.txt and
the per-session diagnostics/ tree. This change does not touch any of it. I
considered folding it in and decided against it. That trail is what you debug riven
OCR with, its format is presumably load-bearing for you, and I cannot run the
Windows path to check I had not made your debugging worse. So the two coexist after
this PR, which is a real wart and worth saying out loud rather than leaving for you
to notice. Unifying them is a separate conversation, and yours to start.

What lands.

  1. feat(logging): add a tracing subscriber with a rolling file sink. New
    src-tauri/src/logging.rs (93 lines), four dependencies, mod logging;, and a
    logging::init(app.handle()) at the top of setup. Two sinks: stderr as
    before, and a daily-rolling file in the platform log dir (app_log_dir(), Tauri's
    own resolver) keeping five files. Both filtered by RUST_LOG. A panic hook
    records panics with location before delegating to the previous hook, and
    tracing_log::LogTracer captures anything logging through the log crate.
    Writing is non-blocking so the scanner and OCR loops never stall on disk.
  2. refactor(logging): replace eprintln diagnostics with tracing macros, the
    mechanical sweep. Levels follow intent: info! for results and state changes,
    debug! for per-cycle detail, warn! for dropped scans and failed fetches,
    error! where data is lost. Values formatted into messages become structured
    fields. This commit is boring by design and should read at a glance.
  3. feat(logging): instrument the scan, OCR and market paths. Spans on the
    capture, OCR, blob-parse and fetch entry points; the subscriber emits span-close
    events carrying time.busy / time.idle, so the log records how long each
    stage took. warframe.market needed a small shape change to be timeable at all:
    every site built a request with wfm_request and issued the call itself, so a
    span on the builder would have timed struct construction. Two helpers,
    wfm_call and wfm_send_json, wrap request and call together; 15 sites route
    through them. Two of those were .send_string(&body.to_string()) and are now
    wfm_send_json(..., &body), the same bytes on the wire, since the body was
    already a serde_json::Value.

Dependencies. Four: tracing, tracing-appender, tracing-log,
tracing-subscriber (with env-filter). All MIT/Apache-2.0. Cargo.lock grows by
101 lines and nothing existing is bumped. I updated it surgically rather than
regenerating, because a full cargo generate-lockfile on my machine rewrites 1,800
lines and drags in dbus and objc2 entries from my platform. Worth a sanity check
on your side that the lock still resolves the same for you.

Verification.

  • memory_scanner.rs conversions: the scanner tests run on Linux (7 passed) and
    the Windows arm type-checks under --target x86_64-pc-windows-gnu. That covers
    the file with the most conversions.
  • lib.rs, wfcd.rs, ocr.rs: not compiled. Those files do not build on Linux
    (Win32 memory APIs, WinRT OCR), and I have no MSVC linker here. The conversions
    are mechanical and mostly one-line, but "mechanical" is not "compiled" and you
    should expect to fix at least a stray format-argument mismatch.
  • logging.rs itself has never run. app_log_dir() resolves on Windows by
    contract, not by my having watched it.
  • I develop on Linux. None of this has been executed on your platform.

If you reimplement this rather than taking the commits, the load-bearing parts are:

  1. The WorkerGuard must outlive the process. tracing_appender::non_blocking
    returns a guard whose drop flushes the buffer; dropping it at the end of init
    means the last events, including the panic that made you look, never reach
    disk. That is why it goes in a OnceLock.
  2. The panic hook must delegate to the previous hook. Replacing it outright
    loses the default backtrace behaviour.
  3. init must be idempotent. It is called from setup, and a second global
    subscriber install would otherwise panic or silently no-op depending on order.
  4. The file sink and console sink need separate filters. A single filter forces
    the file to be as quiet as the console, which defeats the point: the file wants
    debug, the console wants info.
  5. If you keep the spans, keep FmtSpan::CLOSE. Without it the spans are
    structure with no timings, which is most of what they are for.
  6. Instrument wfm_call, not wfm_request. Timing the builder measures nothing.

Lyrex added 3 commits August 9, 2026 20:36
Diagnostics written with eprintln! go to stderr, which a packaged Tauri
app does not have, so those lines are lost in the field and bug reports
arrive without them.

Install a tracing subscriber with two sinks: stderr as before, and a
daily-rolling file in the platform log dir with five files kept. Both
honour RUST_LOG. Panics and anything logging through the log crate are
routed into the same sinks, so a crash leaves a record on disk.

The existing append_to_file / append_to_diag trail is deliberately left
alone; this covers the stderr half only.
Every diagnostic eprintln! becomes a leveled tracing macro, so the same
lines now reach the file sink and can be filtered with RUST_LOG rather
than being all-or-nothing on stderr.

Levels follow what the line is for: info! for scan results and state
changes, debug! for per-cycle detail, warn! for dropped scans and failed
fetches, error! for failures that lose data. Values that used to be
formatted into the message become structured fields.

The bracketed prefixes are gone, since the subscriber prints the module target
instead, except where the prefix named something finer than the module,
which becomes an explicit target.
Spans on the capture, OCR, blob-parse and fetch entry points, so the file
sink records how long each stage took rather than only what it printed.
The subscriber emits span-close events, which carry time.busy and
time.idle.

warframe.market calls needed a shape change to be timed at all: every
site built a request with wfm_request and then issued the call itself, so
a span on the builder would have measured struct construction rather than
the round-trip. Two helpers, wfm_call and wfm_send_json, now wrap the
request and the call together, and all sites route through them.
@Lyrex

Lyrex commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

thank you for integrating the PRs into the main repo! verified it on/against the linux branch, and everything is working well!

@Lyrex Lyrex closed this Aug 10, 2026
@Lyrex
Lyrex deleted the tracing-logging branch August 10, 2026 20:50
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