Skip to content

feat(trace): add cursor pagination to trace list#324

Merged
BYK merged 6 commits intomainfrom
feat/trace-list-pagination
Mar 3, 2026
Merged

feat(trace): add cursor pagination to trace list#324
BYK merged 6 commits intomainfrom
feat/trace-list-pagination

Conversation

@BYK
Copy link
Copy Markdown
Member

@BYK BYK commented Mar 3, 2026

Summary

sentry trace list previously had no pagination — --limit was the only way to get more results, with no way to continue to the next page.

This PR adds --cursor / -c pagination and extracts shared infrastructure from duplicated code in issue list.

Usage

sentry trace list my-org/my-project           # first page
sentry trace list my-org/my-project -c last   # next page
sentry trace list my-org/my-project -c last --sort duration  # preserves flags

Changes

Commit 1: feat(trace) — Add cursor pagination

src/lib/api-client.ts

  • listTransactions() returns PaginatedResponse<TransactionListItem[]> instead of a raw array
  • Forwards cursor to the Sentry events API; extracts next cursor from the Link header

src/commands/trace/list.ts

  • New --cursor / -c flag: "last" resumes from stored cursor; bare integers rejected early
  • Cursor storage via composite context key (host + org/project + sort + query)
  • JSON output: { data, nextCursor?, hasMore } envelope (consistent with issue list)
  • Human output: Next page: sentry trace list <target> -c last footer when more exist

Commit 2: refactor — Extract shared pagination infrastructure

src/lib/db/pagination.ts — new buildPaginationContextKey(type, scope, params?)

  • Generalizes the host:…|type:…[|key:value]* pattern hand-rolled in 3 places
  • buildOrgContextKey now delegates to it (backward compatible)

src/lib/list-command.ts — new parseCursorFlag()

  • Extracts the digits-rejecting cursor parser duplicated in issue list and trace list
  • LIST_CURSOR_FLAG updated to use it — all commands get cursor validation for free

src/commands/trace/list.ts — uses LIST_CURSOR_FLAG and buildPaginationContextKey directly

src/commands/issue/list.ts — uses parseCursorFlag and buildPaginationContextKey; removes local ALL_DIGITS_RE and manual context key construction in handleOrgAllIssues

Add `--cursor` / `-c` flag to `sentry trace list`, enabling users to
page through large result sets instead of being limited to a single
`--limit`-bounded response.

Changes:
- `listTransactions()` now returns `PaginatedResponse<TransactionListItem[]>`
  and passes the `cursor` param to the Sentry events API, extracting
  the next-page cursor from the `Link` response header.
- `trace list` resolves and stores the pagination cursor via the shared
  DB pagination module (same pattern as `issue list`). A composite
  context key (host + org/project + sort + query) scopes each cursor so
  different searches never share state.
- `--cursor last` resumes from the saved cursor; raw cursor strings are
  accepted too (bare integers are rejected with a clear error).
- JSON output now follows the `{ data, nextCursor?, hasMore }` envelope
  used by other list commands.
- Human output shows a `Next page: sentry trace list <target> -c last`
  footer when more pages exist, preserving active `--sort` / `-q` flags.
- Tests updated to reflect the new `PaginatedResponse` shape and cover
  pagination hint rendering, JSON envelope, and cursor passthrough.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 3, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

Trace

  • Add cursor pagination to trace list by BYK in #324

Other

  • (api) Add --data/-d flag and auto-detect JSON body in fields by BYK in #320
  • (formatters) Render all terminal output as markdown by BYK in #297
  • (issue-list) Global limit with fair distribution, compound cursor, and richer progress by BYK in #306

Bug Fixes 🐛

Api

  • Use numeric project ID to avoid "not actively selected" error by betegon in #312
  • Use limit param for issues endpoint page size by BYK in #309
  • Auto-correct ':' to '=' in --field values with a warning by BYK in #302

Formatters

  • Expand streaming table to fill terminal width by betegon in #314
  • Fix HTML entities and escaped underscores in table output by betegon in #313

Other

  • (ci) Generate JUnit XML to silence codecov-action warnings by BYK in #300
  • (nightly) Push to GHCR from artifacts dir so layer titles are bare filenames by BYK in #301
  • (region) Resolve DSN org prefix at resolution layer by BYK in #316
  • (test) Handle 0/-0 in getComparator anti-symmetry property test by BYK in #308
  • (trace-logs) Timestamp_precise is a number, not a string by BYK in #323

Internal Changes 🔧

Api

  • Upgrade @sentry/api to 0.21.0, remove raw HTTP pagination workarounds by BYK in #321
  • Wire listIssuesPaginated through @sentry/api SDK for type safety by BYK in #310

🤖 This preview updates automatically when you update the PR.

BYK and others added 3 commits March 3, 2026 01:42
Extract two pieces of duplicated pagination logic into shared infrastructure:

1. Add buildPaginationContextKey() to src/lib/db/pagination.ts - a generalized
   context key builder that encodes host, type, scope, and optional key-value
   params. Rewrite buildOrgContextKey() to delegate to it.

2. Add parseCursorFlag() to src/lib/list-command.ts - extracts the cursor flag
   validation logic (reject bare integers, accept 'last' keyword and opaque
   cursor strings). Update LIST_CURSOR_FLAG to use it.

Simplify trace/list.ts:
- Remove local ALL_DIGITS_RE, buildContextKey(), and inline cursor parse fn
- Use buildPaginationContextKey() and LIST_CURSOR_FLAG instead
- Remove unused escapeContextKeyValue and getApiBaseUrl imports

Simplify issue/list.ts:
- Remove local ALL_DIGITS_RE constant
- Replace inline cursor parse function with parseCursorFlag
- Replace manual context key construction in handleOrgAllIssues with
  buildPaginationContextKey()
- Keep escapeContextKeyValue and getApiBaseUrl imports (still used by
  buildMultiTargetContextKey)

Add tests for both new functions.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 3, 2026

Codecov Results 📊

2431 passed | Total: 2431 | Pass Rate: 100% | Execution Time: 0ms

📊 Comparison with Base Branch

Metric Change
Total Tests 📈 +23
Passed Tests 📈 +23
Failed Tests
Skipped Tests

All tests are passing successfully.

✅ Patch coverage is 100.00%. Project has 3137 uncovered lines.
✅ Project coverage is 81.23%. Comparing base (base) to head (head).

Files with missing lines (3)
File Patch % Lines
api-client.ts 77.47% ⚠️ 201 Missing
list.ts 86.97% ⚠️ 96 Missing
list.ts 99.26% ⚠️ 1 Missing
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    80.84%    81.23%    +0.39%
==========================================
  Files          121       121         —
  Lines        16662     16711       +49
  Branches         0         0         —
==========================================
+ Hits         13470     13574      +104
- Misses        3192      3137       -55
- Partials         0         0         —

Generated by Codecov Action

@BYK BYK marked this pull request as ready for review March 3, 2026 11:09
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 1 potential issue.

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

BYK added 2 commits March 3, 2026 11:22
…x E2E

- Fix E2E trace list --json test: expect { data, hasMore } envelope
  instead of plain array (matches updated JSON output format)
- Add HTTP-level unit tests for listTransactions in api-client.test.ts:
  nextCursor from Link header, no nextCursor when results=false, cursor/
  sort/limit/query params, numeric vs slug project handling
- Add HTTP-level unit tests for listTraceLogs in api-client.test.ts:
  returns entries, traceId/statsPeriod/limit/query params, default 14d
- Add edge case tests to trace list command: empty page with hasMore,
  nextPageHint with --query flag, JSON output hasMore=false when no cursor

Improves patch coverage for the PR above the 80% threshold.
…consistency

buildPaginationContextKey escapes all param values via escapeContextKeyValue,
but buildMultiTargetContextKey only escaped period and query, leaving sort
unescaped. Fix the inconsistency by escaping sort too.

Current sort values (date/duration) don't contain pipes so there's no active
bug, but consistent escaping prevents future issues if sort values change.
@BYK
Copy link
Copy Markdown
Member Author

BYK commented Mar 3, 2026

Good catch on the escaping inconsistency — fixed in the latest commit by escaping sort in buildMultiTargetContextKey via escapeContextKeyValue for consistency with buildPaginationContextKey.

On the incomplete refactoring: buildMultiTargetContextKey is intentionally separate. It handles multiple targets (fan-out across orgs/projects), encodes them as a sorted comma-joined fingerprint, and uses the type:multi: discriminant — a fundamentally different shape than the single-scope buildPaginationContextKey(type, scope, params?) signature. Delegating to it would require adding a multi-target path to the shared helper, which would mix two distinct concerns. The PR description was slightly imprecise about this.

@BYK BYK merged commit 8993905 into main Mar 3, 2026
20 checks passed
@BYK BYK deleted the feat/trace-list-pagination branch March 3, 2026 11:38
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