Repository navigation
feat(local): Add capture controls and telemetry investigation #1509
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
d161ccb
feat(local): Add browser session switching
MathurAditya724 8124a15
feat(local): Add a searchable session picker
MathurAditya724 ffbcc0e
fix(local): Give receiver actions room in the sidebar
MathurAditya724 ae71daa
fix(local): Keep secondary receiver actions compact
MathurAditya724 71289e1
fix(local): Align receiver actions in one flex row
MathurAditya724 6abe933
feat(local): Discover sessions from receiver connections
MathurAditya724 df0d845
feat(local): Print hosted viewer links in command output
MathurAditya724 15701e2
feat(local): Add appearance controls to Settings
MathurAditya724 d4f5dde
fix(local): Complete receiver connection and session recovery flows
MathurAditya724 b7d7952
test(local): Close receiver sockets during fixture teardown
MathurAditya724 382d7c8
fix(local): Clarify retained envelope counts in Settings
MathurAditya724 f05a41b
fix(local): Polish viewer and integrate exception details
MathurAditya724 04aedaf
fix(local): Clear stale receiver errors while editing
MathurAditya724 bf766b3
fix(local): Preserve scoped sessions when retrying connections
MathurAditya724 515ae1e
fix(local): Retry transient daemon ownership reads
MathurAditya724 5f9feec
fix(local): Preserve sessions on unchanged receiver submissions
MathurAditya724 481b9b2
fix(local): Make capture and viewer lifecycle actions consistent
MathurAditya724 9531251
feat(local): Allow validated runtime retention from hosted viewers
MathurAditya724 ada1980
fix(local): Keep only five recent receiver connections
MathurAditya724 da78ed8
fix(local): Keep archived retention read-only during replay
MathurAditya724 716b1c0
fix(local): Restore clear recovery and preserve disconnection
MathurAditya724 d415547
chore(local): Merge main and resolve session viewer conflicts
MathurAditya724 6cac395
fix(local): Harden discovery and preserve streamed telemetry
MathurAditya724 484be12
test(local): Await retention request completion in viewer test
MathurAditya724 b45530e
feat(local): Clarify capture workflows and event inspection
MathurAditya724 fe714cc
test(local): Bound replay setup and scope retention queries
MathurAditya724 d5e5863
fix(local): Preserve receiver and inspector state across actions
MathurAditya724 48be2cb
feat(local): Add telemetry insights and envelope replay
MathurAditya724 eb6ab17
test(local): Preserve raw envelopes on Windows checkouts
MathurAditya724 0b924dd
fix(local): Retain AI spans identified by origin
MathurAditya724 771367e
test(local): Budget the full capture replay scenario
MathurAditya724 fbdbea3
fix(local): Keep attachments inert and preserve viewer state
MathurAditya724 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # SDK envelope item lengths count raw bytes. Preserve fixture bytes on every OS. | ||
| apps/local/fixtures/*.txt -text |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| # Sentry Local viewer | ||
|
|
||
| The viewer connects to a Local receiver and inspects captured SDK envelopes. | ||
| Start the receiver and UI in separate terminals from the repository root: | ||
|
|
||
| ```sh | ||
| pnpm --filter sentry run cli local serve | ||
| pnpm --filter local dev | ||
| ``` | ||
|
|
||
| Open the URL printed by Vite and connect to `http://localhost:8969`. | ||
| The receiver can also be a named Local session or an explicitly selected remote | ||
| receiver. Capture lifecycle and retention are managed through the existing | ||
| Local controls. | ||
|
|
||
| ## Replay example captures | ||
|
|
||
| With a receiver running, load all bundled examples: | ||
|
|
||
| ```sh | ||
| pnpm --filter local sample | ||
| ``` | ||
|
|
||
| The examples cover correlated errors/logs/traces, repeated database queries, | ||
| resource loading, Web Vitals, an AI conversation and tool execution, feedback, | ||
| SDK reports, legacy and continuous profiles, standalone span-v2 telemetry, | ||
| and text/JSON/HTML/image attachments. All names and content are synthetic. | ||
| They follow the SDK envelope shapes used in Spotlight's fixture corpus. | ||
|
|
||
| Replay any directory of raw SDK envelopes, including Spotlight's `_fixtures` | ||
| directory, recursively: | ||
|
|
||
| ```sh | ||
| pnpm --filter local sample /path/to/spotlight/packages/spotlight/_fixtures \ | ||
| --endpoint http://localhost:8969/stream --compression gzip | ||
|
|
||
| pnpm --filter local sample --interval 200 --repeat 3 | ||
| ``` | ||
|
|
||
| `--fixtures` is an alternative to the positional path. `--endpoint` takes | ||
| precedence over `SENTRY_SPOTLIGHT`; otherwise the default is | ||
| `http://localhost:8969/stream`. A named session requires its ingestion endpoint, | ||
| not its capability-protected viewer stream URL. | ||
|
|
||
| The loader sends `.txt`, `.bin`, and `.envelope` files in sorted order, preserving | ||
| raw bytes and captured timestamps. Bundled byte-counted envelopes disable Git | ||
| line-ending conversion; preserve the original bytes when checking out external | ||
| captures as well. `--compression` supports `none`, `gzip`, and | ||
| `br`; `--interval` is milliseconds between envelopes and `--repeat` is a finite | ||
| number of passes. It stops with a nonzero exit status when a request is rejected | ||
| or times out. The command does not clear existing capture history. Raise the | ||
| receiver's envelope retention limit when replaying a large corpus. | ||
|
|
||
| ## Investigation views | ||
|
|
||
| - Errors include exception causes, captured source lines and local variables, | ||
| breadcrumbs, request/context data, tags, modules, VS Code links for absolute | ||
| local paths, and a copyable Markdown summary for AI assistants. | ||
| - AI inspection reads standard `gen_ai.*` and Vercel AI fields from both embedded | ||
| transaction spans and standalone spans. Prompts, responses, token usage and | ||
| tool arguments/results appear when the SDK captured them. Child AI steps stay | ||
| linked to their parent interaction. | ||
| - Queries and resources group exact operation/description pairs. Sort by count, | ||
| duration or captured resource size and open an execution in its trace. | ||
| - Web Vitals groups visits by page and shows individual captured measurements. | ||
| LCP, INP, CLS, FCP and TTFB use the [Web Vitals thresholds](https://web.dev/articles/vitals); | ||
| FID is labelled as a legacy metric. Local samples are not field percentiles. | ||
| - Profiles support Sentry sample/stack/frame payloads in legacy `profile` items | ||
| and continuous `profile_chunk` items. Select a thread, compare inclusive/self | ||
| time and samples, and explore flame, treemap or sunburst views. Observed time | ||
| uses adjacent samples on each thread; no duration is invented for the last | ||
| sample. Charts limit displayed depth/nodes for responsiveness; JSON preserves | ||
| the original payload. | ||
| - SDKs lists observed names, versions, platforms and last-seen metadata, followed | ||
| by session/client reports. Feedback links to associated errors in the capture. | ||
| - Attachments show safe text/JSON/image/video previews and downloads. Captured | ||
| HTML, SVG and code remain inert; the viewer never executes them or fetches | ||
| captured resource URLs. | ||
|
|
||
| Use severity/logger filters and sorting in event/log views. The Columns control | ||
| chooses which metadata appears beside each message. In a trace, search spans, | ||
| show only matches, collapse branches, or adjust the tree width. | ||
|
|
||
| ## Tests | ||
|
|
||
| ```sh | ||
| pnpm --filter local test | ||
| pnpm --filter local typecheck | ||
| pnpm --filter local build | ||
| ``` | ||
|
|
||
| Integration tests start an actual receiver, replay the bundled capture through | ||
| HTTP/SSE, then navigate the analysis and inspector views. Replay tests cover | ||
| binary bytes, gzip/Brotli, recursive directories, repeated passes and rejected | ||
| requests. Unknown payloads remain inspectable as JSON. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| {"event_id": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "sent_at": "2024-10-27T03:33:20Z", "sdk": {"name": "sentry.javascript.node", "version": "10.0.0"}} | ||
| {"type": "transaction", "length": 2554} | ||
| {"event_id":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","type":"transaction","transaction":"GET /checkout","platform":"javascript","start_timestamp":1730000000,"timestamp":1730000002,"contexts":{"trace":{"trace_id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","span_id":"1111111111111111","op":"pageload"},"profile":{"profile_id":"ffffffffffffffffffffffffffffffff","profiler_id":"demo-profiler"}},"measurements":{"lcp":{"value":3200,"unit":"millisecond"},"inp":{"value":125,"unit":"millisecond"},"cls":{"value":0.04,"unit":"none"},"fcp":{"value":900,"unit":"millisecond"},"ttfb":{"value":180,"unit":"millisecond"}},"spans":[{"span_id":"2222222222222222","parent_span_id":"1111111111111111","op":"db.sql.query","description":"SELECT id, total FROM orders WHERE user_id = ?","start_timestamp":1730000000.1,"timestamp":1730000000.3,"data":{"db.system":"postgresql"}},{"span_id":"3333333333333333","parent_span_id":"1111111111111111","op":"db.sql.query","description":"SELECT id, total FROM orders WHERE user_id = ?","start_timestamp":1730000000.4,"timestamp":1730000000.8,"data":{"db.system":"postgresql"}},{"span_id":"4444444444444444","parent_span_id":"1111111111111111","op":"resource.script","description":"http://localhost:3000/checkout.js","start_timestamp":1730000000.01,"timestamp":1730000000.2,"data":{"http.response_content_length":20480}},{"span_id":"5555555555555555","parent_span_id":"1111111111111111","op":"resource.img","description":"http://localhost:3000/cart.png","start_timestamp":1730000000.02,"timestamp":1730000000.4,"data":{"http.response_content_length":8192}},{"span_id":"6666666666666666","parent_span_id":"1111111111111111","op":"gen_ai.chat","description":"Order assistant","start_timestamp":1730000000.8,"timestamp":1730000001.6,"data":{"gen_ai.request.model":"demo-model","gen_ai.system":"demo-provider","gen_ai.usage.input_tokens":84,"gen_ai.usage.output_tokens":26,"gen_ai.system_instructions":"Help the user find their order.","gen_ai.request.messages":"[{\"role\": \"user\", \"content\": \"Where is order 42?\"}]","gen_ai.response.text":"Order 42 ships tomorrow.","gen_ai.response.tool_calls":"[{\"id\": \"call-demo\", \"name\": \"lookup_order\", \"arguments\": {\"order_id\": 42}}]"}},{"span_id":"7777777777777777","parent_span_id":"6666666666666666","op":"gen_ai.execute_tool","description":"lookup_order","start_timestamp":1730000001,"timestamp":1730000001.2,"data":{"gen_ai.tool.name":"lookup_order","gen_ai.tool.call.id":"call-demo","gen_ai.tool.input":"{\"order_id\": 42}","gen_ai.tool.output":"{\"status\": \"shipping tomorrow\"}"}}]} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| {"event_id": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "sent_at": "2024-10-27T03:33:20Z", "sdk": {"name": "sentry.javascript.node", "version": "10.0.0"}} | ||
| {"type": "event", "length": 1131} | ||
| {"event_id":"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee","level":"error","platform":"javascript","timestamp":1730000001.8,"contexts":{"trace":{"trace_id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","span_id":"2222222222222222"},"browser":{"name":"Firefox","version":"130"},"runtime":{"name":"node","version":"22"}},"request":{"method":"POST","url":"http://localhost:3000/checkout","headers":{"content-type":"application/json"}},"tags":{"environment":"local","feature":"checkout"},"extra":{"cart_items":2},"modules":{"checkout-demo":"1.0.0"},"breadcrumbs":[{"timestamp":1730000000.1,"category":"navigation","message":"Opened checkout"},{"timestamp":1730000001.6,"category":"http","message":"POST /checkout returned 500","level":"error","data":{"status_code":500}}],"exception":{"values":[{"type":"TypeError","value":"Payment method is missing","stacktrace":{"frames":[{"function":"submitOrder","abs_path":"/app/checkout.ts","filename":"checkout.ts","lineno":42,"colno":7,"context_line":"throw new TypeError(\"Payment method is missing\");","pre_context":["if (!paymentMethod) {"],"post_context":["}"],"vars":{"cartItems":2,"paymentMethod":null}}]}}]}} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| {"event_id": "b738e253681bd7b552a2beec92fc38bf", "sent_at": "2024-10-27T03:33:20Z", "sdk": {"name": "sentry.javascript.node", "version": "10.0.0"}} | ||
| {"type": "log", "length": 495} | ||
| {"items":[{"timestamp":1730000000.5,"body":"Loaded two orders","level":"info","trace_id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","span_id":"2222222222222222","attributes":{"sentry.logger.name":{"type":"string","value":"orders"},"order.count":{"type":"integer","value":2}}},{"timestamp":1730000001.8,"body":"Payment validation failed","level":"error","trace_id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","span_id":"2222222222222222","attributes":{"sentry.logger.name":{"type":"string","value":"payments"}}}]} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| {"event_id": "9dd5c245c456bb1da2b82673d5b3a9d4", "sent_at": "2024-10-27T03:33:20Z", "sdk": {"name": "sentry.javascript.node", "version": "10.0.0"}} | ||
| {"type": "feedback", "length": 291} | ||
| {"timestamp":1730000002.1,"contexts":{"feedback":{"message":"The checkout button did not complete my order.","name":"Example User","contact_email":"user@example.com","url":"http://localhost:3000/checkout","source":"feedback_widget","associated_event_id":"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"}}} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| {"event_id": "ffffffffffffffffffffffffffffffff", "sent_at": "2024-10-27T03:33:20Z", "sdk": {"name": "sentry.javascript.node", "version": "10.0.0"}} | ||
| {"type": "profile", "length": 1118} | ||
| {"event_id":"ffffffffffffffffffffffffffffffff","platform":"javascript","transactions":[{"id":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","trace_id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}],"profile":{"frames":[{"function":"main","filename":"checkout.ts","in_app":true},{"function":"submitOrder","filename":"checkout.ts","lineno":40,"in_app":true},{"function":"queryDatabase","filename":"db.ts","lineno":12,"in_app":true},{"function":"read","module":"node:fs","in_app":false}],"stacks":[[0],[1,0],[2,1,0],[3,2,1,0]],"samples":[{"elapsed_since_start_ns":"0","thread_id":"main","stack_id":0},{"elapsed_since_start_ns":"10000000","thread_id":"main","stack_id":1},{"elapsed_since_start_ns":"20000000","thread_id":"main","stack_id":2},{"elapsed_since_start_ns":"30000000","thread_id":"main","stack_id":3},{"elapsed_since_start_ns":"40000000","thread_id":"main","stack_id":2},{"elapsed_since_start_ns":"50000000","thread_id":"main","stack_id":2},{"elapsed_since_start_ns":"60000000","thread_id":"main","stack_id":1},{"elapsed_since_start_ns":"70000000","thread_id":"main","stack_id":0}],"thread_metadata":{"main":{"name":"Main thread"}}}} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| {"event_id": "57c18c15911867b6a10701947b1a9a6c", "sent_at": "2024-10-27T03:33:20Z", "sdk": {"name": "sentry.javascript.node", "version": "10.0.0"}} | ||
| {"type": "profile_chunk", "length": 1208} | ||
| {"chunk_id":"cccccccccccccccccccccccccccccccc","profiler_id":"demo-profiler","platform":"javascript","profile":{"frames":[{"function":"main","filename":"checkout.ts","in_app":true},{"function":"submitOrder","filename":"checkout.ts","lineno":40,"in_app":true},{"function":"queryDatabase","filename":"db.ts","lineno":12,"in_app":true},{"function":"read","module":"node:fs","in_app":false}],"stacks":[[0],[1,0],[2,1,0],[3,2,1,0]],"samples":[{"timestamp":1730000000.0,"thread_id":"main","stack_id":0},{"timestamp":1730000000.01,"thread_id":"main","stack_id":1},{"timestamp":1730000000.02,"thread_id":"main","stack_id":2},{"timestamp":1730000000.03,"thread_id":"main","stack_id":3},{"timestamp":1730000000.04,"thread_id":"main","stack_id":0},{"timestamp":1730000000.05,"thread_id":"main","stack_id":1},{"timestamp":1730000000.06,"thread_id":"main","stack_id":2},{"timestamp":1730000000.07,"thread_id":"main","stack_id":3},{"timestamp":1730000000.08,"thread_id":"main","stack_id":0},{"timestamp":1730000000.09,"thread_id":"main","stack_id":1},{"timestamp":1730000000.1,"thread_id":"main","stack_id":2},{"timestamp":1730000000.11,"thread_id":"main","stack_id":3}],"thread_metadata":{"main":{"name":"Main thread"}}}} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| {"event_id": "199741d5b434c4a604635de1884cec77", "sent_at": "2024-10-27T03:33:20Z", "sdk": {"name": "sentry.javascript.node", "version": "10.0.0"}} | ||
| {"type": "session", "length": 100} | ||
| {"sid":"dddddddddddddddddddddddddddddddd","started":"2024-10-27T03:33:20Z","status":"ok","errors":0} | ||
| {"type": "client_report", "length": 108} | ||
| {"timestamp":1730000000,"discarded_events":[{"reason":"sample_rate","category":"transaction","quantity":3}]} |
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| {"event_id": "15e02eb45f3d4a0d7f566cf8a189f0ea", "sent_at": "2024-10-27T03:33:20Z", "sdk": {"name": "sentry.javascript.node", "version": "10.0.0"}} | ||
| {"type": "span", "length": 352} | ||
| {"version":2,"items":[{"span_id":"8888888888888888","trace_id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","parent_span_id":"1111111111111111","name":"SELECT count(*) FROM orders","start_timestamp":1730000001.5,"end_timestamp":1730000001.7,"attributes":{"sentry.op":{"type":"string","value":"db.sql.query"},"db.system":{"type":"string","value":"postgresql"}}}]} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.