Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion docs/src/content/docs/commands/event.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: event
description: Event commands for the Sentry CLI
---

View Sentry events
View and list Sentry events

## Commands

Expand All @@ -25,6 +25,27 @@ View details of a specific event
| `--spans <spans>` | Span tree depth limit (number, "all" for unlimited, "no" to disable) (default: "3") |
| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data |

### `sentry event list <issue>`

List events for an issue

**Arguments:**

| Argument | Description |
|----------|-------------|
| `<issue>` | Issue: @latest, @most_frequent, &lt;org&gt;/ID, &lt;project&gt;-suffix, ID, or suffix |

**Options:**

| Option | Description |
|--------|-------------|
| `-n, --limit <limit>` | Number of events (1-1000) (default: "25") |
| `-q, --query <query>` | Search query (Sentry search syntax) |
| `--full` | Include full event body (stacktraces) |
| `-t, --period <period>` | Time period (e.g., "1h", "24h", "7d", "30d") (default: "7d") |
| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data |
| `-c, --cursor <cursor>` | Navigate pages: "next", "prev", "first" (or raw cursor string) |

All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields.

<!-- GENERATED:END -->
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/commands/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The Sentry CLI provides commands for interacting with various Sentry resources.
| [`repo`](./repo/) | Work with Sentry repositories |
| [`team`](./team/) | Work with Sentry teams |
| [`issue`](./issue/) | Manage Sentry issues |
| [`event`](./event/) | View Sentry events |
| [`event`](./event/) | View and list Sentry events |
| [`log`](./log/) | View Sentry logs |
| [`sourcemap`](./sourcemap/) | Manage sourcemaps |
| [`span`](./span/) | List and view spans in projects or traces |
Expand Down
3 changes: 2 additions & 1 deletion plugins/sentry-cli/skills/sentry-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,10 @@ Manage Sentry issues

### Event

View Sentry events
View and list Sentry events

- `sentry event view <org/project/event-id...>` — View details of a specific event
- `sentry event list <issue>` — List events for an issue

→ Full flags and examples: `references/event.md`

Expand Down
36 changes: 34 additions & 2 deletions plugins/sentry-cli/skills/sentry-cli/references/event.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
---
name: sentry-cli-event
version: 0.25.0-dev.0
description: View Sentry events
description: View and list Sentry events
requires:
bins: ["sentry"]
auth: true
---

# Event Commands

View Sentry events
View and list Sentry events

### `sentry event view <org/project/event-id...>`

Expand All @@ -20,6 +20,38 @@ View details of a specific event
- `--spans <value> - Span tree depth limit (number, "all" for unlimited, "no" to disable) - (default: "3")`
- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data`

### `sentry event list <issue>`

List events for an issue

**Flags:**
- `-n, --limit <value> - Number of events (1-1000) - (default: "25")`
- `-q, --query <value> - Search query (Sentry search syntax)`
- `--full - Include full event body (stacktraces)`
- `-t, --period <value> - Time period (e.g., "1h", "24h", "7d", "30d") - (default: "7d")`
- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data`
- `-c, --cursor <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

**JSON Fields** (use `--json --fields` to select specific fields):

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Internal event ID |
| `event.type` | string | Event type (error, default, transaction) |
| `groupID` | string \| null | Group (issue) ID |
| `eventID` | string | UUID-format event ID |
| `projectID` | string | Project ID |
| `message` | string | Event message |
| `title` | string | Event title |
| `location` | string \| null | Source location (file:line) |
| `culprit` | string \| null | Culprit function/module |
| `user` | object \| null | User context |
| `tags` | array | Event tags |
| `platform` | string \| null | Platform (python, javascript, etc.) |
| `dateCreated` | string | ISO 8601 creation timestamp |
| `crashFile` | string \| null | Crash file URL |
| `metadata` | unknown \| null | Event metadata |

**Examples:**

```bash
Expand Down
3 changes: 2 additions & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { cliRoute } from "./commands/cli/index.js";
import { dashboardRoute } from "./commands/dashboard/index.js";
import { listCommand as dashboardListCommand } from "./commands/dashboard/list.js";
import { eventRoute } from "./commands/event/index.js";
import { listCommand as eventListCommand } from "./commands/event/list.js";
import { helpCommand } from "./commands/help.js";
import { initCommand } from "./commands/init.js";
import { issueRoute } from "./commands/issue/index.js";
Expand Down Expand Up @@ -88,7 +89,7 @@ export const routes = buildRouteMap({
team: teamRoute,
issue: issueRoute,
event: eventRoute,
events: eventRoute,
events: eventListCommand,
Comment thread
BYK marked this conversation as resolved.
log: logRoute,
sourcemap: sourcemapRoute,
sourcemaps: sourcemapRoute,
Expand Down
9 changes: 6 additions & 3 deletions src/commands/event/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { buildRouteMap } from "@stricli/core";
import { listCommand } from "./list.js";
import { viewCommand } from "./view.js";

export const eventRoute = buildRouteMap({
routes: {
view: viewCommand,
list: listCommand,
},
defaultCommand: "view",
aliases: { show: "view" },
docs: {
brief: "View Sentry events",
brief: "View and list Sentry events",
fullDescription:
"View detailed event data from Sentry. " +
"Use 'sentry event view <event-id>' to view a specific event.",
"View and list event data from Sentry.\n\n" +
"Use 'sentry event view <event-id>' to view a specific event.\n" +
"Use 'sentry event list <issue-id>' to list events for an issue.",
hideRoute: {},
},
});
182 changes: 182 additions & 0 deletions src/commands/event/list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/**
* sentry event list
*
* List events for a specific Sentry issue.
* This is the top-level event listing command — functionally equivalent to
* `sentry issue events` but living in the `event` route. The `sentry events`
* plural alias points here.
*/

import type { SentryContext } from "../../context.js";
import { listIssueEvents } from "../../lib/api-client.js";
import {
advancePaginationState,
buildPaginationContextKey,
hasPreviousPage,
resolveCursor,
} from "../../lib/db/pagination.js";
import { ContextError } from "../../lib/errors.js";
import { CommandOutput } from "../../lib/formatters/output.js";
import { buildListCommand, paginationHint } from "../../lib/list-command.js";
import { withProgress } from "../../lib/polling.js";
import { IssueEventSchema } from "../../types/index.js";
import {
buildCommandHint,
issueIdPositional,
resolveIssue,
} from "../issue/utils.js";
import {
appendEventsFlags,
EVENTS_ALIASES,
EVENTS_FLAGS,
type EventsFlags,
formatEventsHuman,
jsonTransformEvents,
} from "./shared-events.js";

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

/** Command name used in issue resolution error messages */
const COMMAND_NAME = "list";

/** Base command prefix for error hints */
const COMMAND_BASE = "sentry event";

/** Command key for pagination cursor storage */
const PAGINATION_KEY = "event-list";

// ---------------------------------------------------------------------------
// Pagination hints
// ---------------------------------------------------------------------------

/** Build the CLI hint for fetching the next page, preserving active flags. */
function nextPageHint(
issueArg: string,
flags: Pick<EventsFlags, "query" | "full" | "period">
): string {
return appendEventsFlags(`sentry event list ${issueArg} -c next`, flags);
}

/** Build the CLI hint for fetching the previous page, preserving active flags. */
function prevPageHint(
issueArg: string,
flags: Pick<EventsFlags, "query" | "full" | "period">
): string {
return appendEventsFlags(`sentry event list ${issueArg} -c prev`, flags);
}

// ---------------------------------------------------------------------------
// Command definition
// ---------------------------------------------------------------------------

export const listCommand = buildListCommand("event", {
docs: {
brief: "List events for an issue",
fullDescription:
"List events belonging to a Sentry issue.\n\n" +
"Issue formats:\n" +
" @latest - Most recent unresolved issue\n" +
" @most_frequent - Issue with highest event frequency\n" +
" <org>/ID - Explicit org: sentry/EXTENSION-7\n" +
" <project>-suffix - Project + suffix: cli-G\n" +
" ID - Short ID: CLI-G\n" +
" numeric - Numeric ID: 123456789\n\n" +
"Examples:\n" +
" sentry event list CLI-G\n" +
" sentry event list @latest --limit 50\n" +
" sentry event list 123456789 --full\n" +
' sentry event list CLI-G -q "user.email:foo@bar.com"\n' +
" sentry event list CLI-G --json",
},
output: {
human: formatEventsHuman,
jsonTransform: jsonTransformEvents,
schema: IssueEventSchema,
},
parameters: {
positional: issueIdPositional,
flags: EVENTS_FLAGS,
aliases: EVENTS_ALIASES,
},
async *func(this: SentryContext, flags: EventsFlags, issueArg: string) {
const { cwd } = this;

// Resolve issue using shared resolution logic (supports @latest, short IDs, etc.)
const { org, issue } = await resolveIssue({
issueArg,
cwd,
command: COMMAND_NAME,
commandBase: COMMAND_BASE,
});

// Org is required for region-routed events endpoint
if (!org) {
throw new ContextError(
"Organization",
buildCommandHint(COMMAND_NAME, issueArg, COMMAND_BASE)
);
}

// Build context key for pagination (keyed by issue ID + query-varying params)
const contextKey = buildPaginationContextKey(
"event-list",
`${org}/${issue.id}`,
{ q: flags.query, period: flags.period }
);
const { cursor, direction } = resolveCursor(
flags.cursor,
PAGINATION_KEY,
contextKey
);

const { data: events, nextCursor } = await withProgress(
{
message: `Fetching events for ${issue.shortId} (up to ${flags.limit})...`,
json: flags.json,
},
() =>
listIssueEvents(org, issue.id, {
limit: flags.limit,
query: flags.query,
full: flags.full,
cursor,
statsPeriod: flags.period,
})
);

// Update pagination state (handles both advance and truncation)
advancePaginationState(PAGINATION_KEY, contextKey, direction, nextCursor);
const hasPrev = hasPreviousPage(PAGINATION_KEY, contextKey);

const hasMore = !!nextCursor;

// Build footer hint based on result state
const nav = paginationHint({
hasMore,
hasPrev,
prevHint: prevPageHint(issueArg, flags),
nextHint: nextPageHint(issueArg, flags),
});
let hint: string | undefined;
if (events.length === 0 && nav) {
hint = `No events on this page. ${nav}`;
} else if (events.length > 0) {
const countText = `Showing ${events.length} event${events.length === 1 ? "" : "s"}.`;
hint = nav
? `${countText} ${nav}`
: `${countText} Use 'sentry event view <EVENT_ID>' to view full event details.`;
}

yield new CommandOutput({
events,
hasMore,
hasPrev,
nextCursor,
issueShortId: issue.shortId,
issueId: issue.id,
});
return { hint };
},
});
Loading
Loading