[3/10] Scan samples across a time window and by user#50
Open
oliver-kriska wants to merge 4 commits into
Open
Conversation
Bring the AGENTS.md architecture section up to date with the current `src/` tree (the `commands/logs/` split, `dashboards.rs`, `triggers.rs`, `about.rs`, `project.rs`, `output.rs`, `error.rs`, `telemetry.rs`, `version_check.rs`, `client_headers.rs`) and document two conventions that were implicit in the code: how command output and user-facing errors flow through the `output` module and `CliError`, and the end-to-end checklist for adding a new command. Add a minimal CLAUDE.md that points at AGENTS.md as the source of truth, so Claude Code sessions pick up the same conventions. [skip changeset] Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`incidents show` only exposes incident-level aggregates. Add a `samples` command that fetches the underlying transaction sample data behind an incident — action, duration, queue time, params, and the exception backtrace — which is what most incident triage actually works from. - `samples show` fetches a single sample: the latest, one by id (--sample-id), or the one closest to a timestamp (--at). Targeting a timestamp matters because the "latest" sample often hides the one that triggered the incident. - `samples list` returns an incident's samples, optionally narrowed with --start/--end/--limit. - Both accept a full AppSignal incident or sample URL (or a bare sample id) as a positional argument, or the explicit --incident plus the usual --app-id/--app/--environment/--org flags, and both support --output json. A new `appsignal_url` module parses every URL shape, matching `/samples/timestamp/<ISO>` before a generic sample-id segment and URL-decoding the timestamp. The fetch uses one GraphQL query that spreads both `... on PerformanceIncident` and `... on ExceptionIncident`, and the sample type is taken from the returned `__typename` rather than inferred from the URL path, so an exception URL can never be miscategorised as performance. The `timestamp`/`start`/`end` GraphQL variables are declared `DateTime` even though ISO-8601 strings are sent; declaring them `String` returns an HTTP 400 type mismatch. Regression tests assert the `DateTime` declaration is present. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`samples show` printed a flat field dump; raw samples are large and mostly noise. Render an analysed digest by default instead — the questions a responder actually asks: what ran, how slow, who hit it, which queries dominated, was there an N+1, and for errors what blew up and what led to it. - New `sample_analysis` module distils a `Sample` into a `SampleAnalysis`: request overview + acting user (pulled from overview/attributes), a per-group performance breakdown (count / total / % / avg), the slowest events, a database rollup, slow queries (from timeline payload bodies), N+1 suspects (repeated timeline `digest`s, plus the `hasNPlusOne` flag), and for errors the exception, backtrace, causes, and breadcrumbs. It is pure and unit-tested on synthetic samples. - `samples show` renders the digest by default, `--output json` adds the structured `analysis` object alongside the raw sample, and `--raw` prints the unprocessed sample. `samples list` is unchanged. - The sample GraphQL selection gains the fields the analysis needs (timeline, group durations/allocations, params/session/custom data, breadcrumbs); only fields with known scalar types are selected to keep deserialization robust. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The forensic question is usually "what happened between T1 and T2" or "what did this user hit", not "show me one incident". `samples list` previously required an incident; it can now scan a window across incidents instead. - Omitting `--incident` and passing `--start`/`--end` scans recent incidents and collects the samples in that window. The GraphQL `incidents` query has no time-range filter, so `scan_samples_in_window` lists recent incidents (capped by `--limit`, default 20) and applies the window at the sample level, where `samples(start:, end:)` is supported. Anomaly/log incidents have no samples and are skipped. - `--user` keeps only samples whose user identity matches the given id, email, or substring (case-insensitive). Identity is resolved from the sample's overview/attributes and, failing that, its session/custom/params JSON, via a shared `sample_analysis::sample_user` helper that also feeds the digest. - `--namespaces` filters which incidents are scanned. `--user` also applies in single-incident mode. Existing single-incident `samples list` is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
The forensic question is usually "what happened between T1 and T2" or "what did
this user hit", not "show me one incident".
samples listpreviously requiredan incident; it can now scan a window across incidents instead.
--incidentand passing--start/--endscans recent incidents andcollects the samples in that window. The GraphQL
incidentsquery has notime-range filter, so
scan_samples_in_windowlists recent incidents (cappedby
--limit, default 20) and applies the window at the sample level, wheresamples(start:, end:)is supported. Anomaly/log incidents have no samplesand are skipped.
--userkeeps only samples whose user identity matches the given id, email,or substring (case-insensitive). Identity is resolved from the sample's
overview/attributes and, failing that, its session/custom/params JSON, via a
shared
sample_analysis::sample_userhelper that also feeds the digest.--namespacesfilters which incidents are scanned.--useralso applies insingle-incident mode. Existing single-incident
samples listis unchanged.