Skip to content

Add rodney logs command for capturing browser console output - #34

Open
slaskis wants to merge 9 commits into
simonw:mainfrom
slaskis:logs
Open

Add rodney logs command for capturing browser console output#34
slaskis wants to merge 9 commits into
simonw:mainfrom
slaskis:logs

Conversation

@slaskis

@slaskis slaskis commented Feb 19, 2026

Copy link
Copy Markdown

Add rodney logs — persistent console log capture via --logs flag

What this adds

A new rodney start --logs flag that spawns a background _logger subprocess. The logger stays connected to Chrome via CDP and writes Runtime.consoleAPICalled events to per-page NDJSON files (<stateDir>/logs/<targetID>.ndjson). rodney logs reads those files; rodney logs -f tails them.

rodney start --logs
rodney open https://example.com
rodney logs              # snapshot
rodney logs -f           # follow
rodney logs -n 20        # last 20 entries
rodney logs --json       # machine-readable
rodney stop              # kills logger subprocess

Architecture

  • _logger subprocess — spawned inline in cmdStart (like the _proxy helper). Connects to Chrome, calls Target.setDiscoverTargets, and listens for TargetTargetCreated events. For each new page it immediately calls RuntimeEnable and begins writing to a .ndjson file.
  • Blank-page-first strategycmdOpen/cmdNewPage create a blank page first when --logs is active, then poll (waitForLogger) for the log file to appear on disk. The file is created by _logger only after RuntimeEnable returns, making it an exact synchronisation signal. This ensures RuntimeEnable is active before any inline scripts execute, with no fixed sleep.
  • cmdLogs streams — snapshot mode uses bufio.Scanner + a ring buffer for -n N, so memory is bounded at O(N) lines regardless of file size.
  • cmdLogs requires --logs — errors with a helpful message if logs weren't enabled at start.

Fixes #27

slaskis and others added 9 commits February 18, 2026 21:04
Adds `rodney logs [-f] [-n N] [--json]` to capture JavaScript console
messages (log/warn/error/debug) from the active Chrome tab via CDP
Runtime.consoleAPICalled. Snapshot mode (default) collects events for
100ms then exits; follow mode (-f) streams until Ctrl+C.

Uses the Runtime domain rather than the Log domain because headless
Chrome does not reliably deliver Log.entryAdded events for JavaScript
console calls. Also avoids page.Context() wrapping for EachEvent
listeners, which creates a detached copy with a separate event publisher.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each `rodney js` invocation now captures Runtime.consoleAPICalled events
within its own CDP session (the only session that receives evaluate-triggered
console calls) and appends them as NDJSON to <stateDir>/logs/<targetID>.ndjson.

`rodney logs` reads that file directly; `rodney logs -f` tails it.

The background _logger subprocess approach was removed — it couldn't capture
`rodney js` console output due to Chrome's cross-session CDP limitation, so
it added complexity without covering the primary use case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…output

- Add `Logs` and `LoggerPID` fields to State struct
- Add `--logs` flag to `rodney start`; gates logger infrastructure
- Restore `rodney _logger <debugURL> <logsDir>` hidden subcommand that polls
  browser.Pages() every 100ms and writes page-native console events to
  per-page NDJSON files
- Add `startBrowserLogger(s)` called from `cmdOpen`; spawns one _logger
  process, stores PID in state, idempotent via signal(0) check
- Add `setupConsoleCapture(s, page)` helper used by `cmdJS` and `cmdAssert`:
  always prints Runtime.consoleAPICalled events to stderr; also appends to
  .ndjson when --logs is enabled
- `cmdStop` now SIGTERMs LoggerPID before removing state
- `cmdLogs` exits with a helpful error when logs are not enabled

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Chrome broadcasts Runtime.consoleAPICalled to all CDP sessions, so both
the _logger subprocess and the in-process EachEvent listener in cmdJS/cmdAssert
were writing the same event to the NDJSON file. Fix by removing file writes
from setupConsoleCapture — it now only prints to stderr. The _logger subprocess
is the sole writer of NDJSON log files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…events

Chrome broadcasts Runtime.consoleAPICalled to all CDP sessions regardless of
whether events were triggered by page-native code or Runtime.evaluate, so the
_logger subprocess captures everything. No in-process capture in cmdJS/cmdAssert
is needed. Remove setupConsoleCapture and revert those commands to plain withPage().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Start

- cmdInternalLogger now uses Target.setDiscoverTargets + EachEvent on
  TargetTargetCreated instead of polling every 100ms. Chrome fires the event
  the moment a page target is created, giving _logger near-zero reaction time.
- _logger is spawned in cmdStart (not cmdOpen), so it is already connected
  and listening before any page is opened.
- cmdOpen and cmdNewPage create a blank page first when s.Logs is true,
  sleep 100ms for _logger to subscribe and call RuntimeEnable, then navigate
  to the real URL. RuntimeEnable persists across same-target navigations, so
  all inline scripts on the real URL are captured.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- trackPage now opens the log file *after* RuntimeEnable returns (which
  blocks until Chrome acks). The file's appearance on disk is an exact
  ready signal that Chrome will send events for any subsequent console call.
- cmdOpen and cmdNewPage replace time.Sleep(100ms) with waitForLogger(),
  which polls for the log file in 5ms increments (500ms timeout). Resolves
  in ~10-15ms in practice instead of always waiting 100ms.
- Logger subprocess is now spawned inline in cmdStart (like the _proxy
  helper) rather than via a separate startBrowserLogger function.
- LoggerPID is set directly in the initial State struct, eliminating the
  second saveState call.
- Update notes/cdp-console-logs.md: correct the cross-session broadcast
  finding (events ARE broadcast to all sessions), document the current
  _logger architecture and blank-page-first strategy, and remove the
  now-deleted in-process capture approach.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- cmdLogs snapshot mode: replace os.ReadFile+slice with scanLogFile (streaming
  bufio.Scanner). For -n N, use a ring buffer so memory is bounded at O(N)
  lines regardless of file size. For unlimited, stream directly to stdout.
- tailLogFile backread (-f -n N): replace io.ReadAll with the same ring buffer
  approach via bufio.Scanner on the already-open file handle.
- Add scanLogFile(logFile, fn) helper; remove readLogLines and readNDJSONLines.
- Update TestLogs_ReadLogLines → TestLogs_ScanLogFile to use the new helper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
jstockdi added a commit to Battle-Creek-LLC/rodney that referenced this pull request Mar 9, 2026
Integrate PR simonw#34 (slaskis/rodney#logs) onto main. Adds a `_logger`
subprocess spawned by `rodney start --logs` that captures browser
console output to per-page NDJSON files via Runtime.consoleAPICalled.

- `rodney logs` prints buffered console entries (snapshot mode)
- `rodney logs -f` streams new entries in real time
- `rodney logs -n N` limits to last N entries
- `rodney logs --json` outputs raw NDJSON

Uses a blank-page-first strategy in cmdOpen/cmdNewPage when logs are
enabled to ensure RuntimeEnable is called before inline scripts execute.
jstockdi added a commit to Battle-Creek-LLC/rodney that referenced this pull request Mar 9, 2026
Integrate PR simonw#34 (slaskis/rodney#logs) onto main. Adds a `_logger`
subprocess spawned by `rodney start --logs` that captures browser
console output to per-page NDJSON files via Runtime.consoleAPICalled.

- `rodney logs` prints buffered console entries (snapshot mode)
- `rodney logs -f` streams new entries in real time
- `rodney logs -n N` limits to last N entries
- `rodney logs --json` outputs raw NDJSON

Uses a blank-page-first strategy in cmdOpen/cmdNewPage when logs are
enabled to ensure RuntimeEnable is called before inline scripts execute.
player1537 added a commit to player1537-forks/rodney that referenced this pull request Mar 12, 2026
Integrate the logs feature from PR simonw#34 which adds:
- rodney start --logs flag for persistent console log capture
- rodney logs command with -f (follow), -n N (last N entries), --json options
- Background _logger subprocess architecture
- NDJSON file-backed log storage per page

Resolved merge conflicts by:
- Adding enableLogs field to startFlags struct
- Updating parseStartFlags to handle --logs flag
- Keeping both parseStartFlags tests and logs command tests
- Using structured flag parsing from fix/show-flag-parsing branch

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
alex-pezarro-portswigger added a commit to alex-pezarro-portswigger/rodney that referenced this pull request Apr 20, 2026
Resolve conflicts by:
- Merging Label, Logs, LoggerPID fields into the State struct
- Adding --logs as a flag in parseStartArgs (which now also returns
  enableLogs); updating cmdStart to thread the flag through
- Adding [--logs] to the rodney start line in help.txt
- Updating all parseStartArgs tests to unpack 5 return values and
  adding TestParseStartArgs_LogsFlag
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.

rodney logs command

1 participant