Skip to content

[kernel-1116] browser debug: add cdp monitor#202

Open
archandatta wants to merge 17 commits intoarchand/kernel-1116/cdp-pipelinefrom
archand/kernel-1116/cdp-monitor
Open

[kernel-1116] browser debug: add cdp monitor#202
archandatta wants to merge 17 commits intoarchand/kernel-1116/cdp-pipelinefrom
archand/kernel-1116/cdp-monitor

Conversation

@archandatta
Copy link
Copy Markdown
Contributor

@archandatta archandatta commented Apr 6, 2026

Tests

  • run the chromium-headful image
  • run curl -v -X POST http://localhost:444/events/start to start the event capture stream
  • look through the docker container logs for /var/logs/ and there should files created for console.log, network.log etc.

I did some browsing and started a yt video and got these logs from it:

  • network.log was the largest - open to thoughts on filtering some of it to reduce the size

    • Static assets (by MIME type):
    • Images: image/svg+xml (111), image/gif (45), image/jpeg (17), image/png
      (14), image/avif (14), image/x-icon (12), image/webp (1)
    • JavaScript: text/javascript (69), application/x-javascript (25),
      application/javascript (4)
    • CSS: text/css (34)
    • Fonts: font/woff2 (15)
    • Media: audio/mpeg (4), application/vnd.yt-ump (7)

    Other skipped:

    • text/html (23) — these are likely iframe/subframe HTML documents where
      the body fetch returned empty or the resource type was filtered

    What we ARE capturing bodies for (30 responses):

    • application/json (21) — API responses, the most useful data
    • text/plain (3)
    • text/html (2) — top-level page HTML
    • application/json+protobuf (2)
    • application/manifest+json (1)
  ┌─────────────────┬───────┬─────────────────────────────────────────────┐
  │    Log File     │ Lines │                 Event Types                 │
  ├─────────────────┼───────┼─────────────────────────────────────────────┤
  │ console.log     │ 2     │ console_log (2)                             │
  ├─────────────────┼───────┼─────────────────────────────────────────────┤
  │                 │       │ network_request (483), network_response     │
  │ network.log     │ 921   │ (417), network_loading_failed (18),         │
  │                 │       │ network_idle (3)                            │
  ├─────────────────┼───────┼─────────────────────────────────────────────┤
  │                 │       │ layout_shift (28), navigation (13),         │
  │ page.log        │ 55    │ dom_content_loaded (5), page_load (5),      │
  │                 │       │ layout_settled (3), navigation_settled (1)  │
  ├─────────────────┼───────┼─────────────────────────────────────────────┤
  │ interaction.log │ 9     │ interaction_click (7), interaction_key (1), │
  │                 │       │  scroll_settled (1)                         │
  ├─────────────────┼───────┼─────────────────────────────────────────────┤
  │ system.log      │ 4     │ screenshot (4)                              │
  └─────────────────┴───────┴─────────────────────────────────────────────┘
  ┌─────────────────┬──────┐
  │      File       │ Size │
  ├─────────────────┼──────┤
  │ console.log     │ 19K  │
  ├─────────────────┼──────┤
  │ interaction.log │ 4.5K │
  ├─────────────────┼──────┤
  │ network.log     │ 2.3M │
  ├─────────────────┼──────┤
  │ page.log        │ 40K  │
  ├─────────────────┼──────┤
  │ system.log      │ 658K │
  └─────────────────┴──────┘

Note

Medium Risk
Adds a new CDP WebSocket monitoring subsystem with reconnection, async network body capture, and screenshotting, plus changes to event categorization and log writing behavior. Risk is mainly around concurrency/reconnect edge cases and the CategoryFor underscore parsing potentially re-categorizing existing event types.

Overview
Introduces a full cdpmonitor implementation that connects to Chrome DevTools via WebSocket, auto-attaches to targets (including pre-existing ones), and publishes structured events for console output, page/navigation lifecycle, network activity (including optional truncated response bodies), interactions (click/key/scroll), layout shifts, and periodic screenshots.

Adds computed meta-events (network_idle, layout_settled, navigation_settled) with debounced timers and navigation-safe invalidation, and implements restart handling when the upstream DevTools URL changes, emitting monitor_disconnected/monitor_reconnected events.

Tightens the events pipeline by changing CategoryFor to split on _ (and updating mappings) and by capping per-category log files at 64MB in FileWriter; CaptureSession.Publish now publishes to the ring buffer under lock before doing file I/O to preserve sequence ordering. Comprehensive new tests cover monitor lifecycle, reconnects, handlers, computed events, and screenshot rate-limiting.

Reviewed by Cursor Bugbot for commit 69be86f. Bugbot is set up for automated code reviews on this repo. Configure here.

@archandatta archandatta marked this pull request as ready for review April 6, 2026 13:41
Copy link
Copy Markdown
Contributor

@hiroTamada hiroTamada left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed incrementally—overall this is a solid foundation for cdp-based observability. left inline comments on a few areas:

  • secrets/redaction: network events pass through raw headers, cookies, tokens with no scrubbing—worth documenting or gating
  • disk growth: filewriter appends indefinitely with no rotation/cap—risky on constrained unikraft instances
  • reconnect gap: readloop exits silently on ws error without same-url redial; depends on upstreammgr to always notify
  • 500ms debounce: works well but rationale isn't documented for future readers
  • duration: open question on whether to persist timing data on events for downstream analytics

no blockers for merge imo, but the disk growth and secrets points are worth resolving before wider rollout.

@archandatta archandatta requested a review from hiroTamada April 7, 2026 18:52
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 69be86f. Configure here.

func (m *Monitor) handleLoadEventFired(params json.RawMessage, sessionID string) {
m.publishEvent(EventPageLoad, events.DetailMinimal, events.Source{Kind: events.KindCDP}, "Page.loadEventFired", params, sessionID)
m.computed.onPageLoad()
go m.tryScreenshot(m.getLifecycleCtx())
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subframe sessions prematurely advance computed state machine

Medium Severity

handleDOMContentLoaded and handleLoadEventFired unconditionally call computed.onDOMContentLoaded() and computed.onPageLoad() for events from any session, including auto-attached subframe targets. But handleFrameNavigated only resets computed state for top-level frames (ParentID == ""). This means a subframe session's Page.loadEventFired can start the layout_settled timer and set navDOMLoaded before the main page reaches those milestones. If the subframe's timer fires first, layoutFired becomes true and the main page's subsequent onPageLoad early-returns without restarting the timer, causing layout_settled and navigation_settled to fire based on subframe timing rather than main-page timing.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 69be86f. Configure here.

return ""
}
return truncateBody(resp.Body, bodyCapFor(state.mimeType))
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Response body base64 encoding flag is ignored

Low Severity

fetchResponseBody parses the base64Encoded field from Chrome's Network.getResponseBody response but never checks it. When Chrome returns base64Encoded: true, the body string is base64-encoded data that gets passed through truncateBody and published as-is. This produces garbled body content in the event and could also truncate mid-encoding, yielding invalid base64.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 69be86f. Configure here.

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.

2 participants