feat(seer): add the single log line embed - #123906
Conversation
📊 Type Coverage Diff
🔍 4 new type safety issues introducedType assertions (
This is informational only and does not block the PR. |
Story previewsPreview the stories changed in this PR on the Vercel deployment: Preview deployment: https://sentry-6h8mhda16.sentry.dev |
|
bugbot review |
|
bugbot review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 793654d. Configure here.
| const SeverityTag = styled('span')<{logColors: ReturnType<typeof getLogColors>}>` | ||
| flex-shrink: 0; | ||
| border: 1px solid ${p => p.logColors.border}; | ||
| background: ${p => p.logColors.backgroundLight}; | ||
| color: ${p => p.logColors.color}; | ||
| border-radius: ${p => p.theme.radius.sm}; | ||
| padding: 0 ${p => p.theme.space.xs}; | ||
| font-size: ${p => p.theme.font.size.sm}; | ||
| font-weight: ${p => p.theme.font.weight.sans.medium}; | ||
| text-transform: uppercase; | ||
| white-space: nowrap; | ||
| `; |
There was a problem hiding this comment.
This should be some kind of tag or something? tag in stories looks similar, but without the border
ryan953
left a comment
There was a problem hiding this comment.
This is a big one, but there are a few flavours for the log: id only, single attr, all attrs
referenced by id only, or the full id+trace+project+date tuple.
Adds two Seer markdown embeds for Explore > Agents: - **`conversation`** — one AI agent conversation. Inline renders a link; block renders the transcript with its LLM call, token, cost and tool totals. - **`conversationsQuery`** — the conversations list filtered by a search. Inline renders a link; block previews the first five matching rows with duration, message count, errors and cost. Both are gated on `organizations:gen-ai-conversations`, which already exists in `temporary.py`, so neither reaches the agent until an org has it. The last of four independent branches adding single-resource Seer embeds — see also #123901 (profile), #123905 (event) and #123906 (log). They all touch `schemas.ts`, `index.ts`, the stories page and the generated widget JSON, so whichever merges first leaves the rest needing a rebase plus a `pnpm gen:embed-widgets` re-run. ### Notes for review Both blocks avoid the route-level machinery, because it is URL-coupled and an embed must not touch the host page's history (`embeds/README.md`): - The list block builds its own query rather than using `useConversations`, which takes no arguments and reads cursor/filters through nuqs. - The transcript composes `MessagesPanel` + `ConversationAggregatesBar` directly rather than `ConversationViewContent`, which writes its tab and detail-tab state back to the URL. Message selection is local `useState`, with a test asserting the router never changes. Two shape details worth a look: - **Content flattening.** `useConversations` normalizes `firstInput`/`lastOutput` before handing rows out, but the raw endpoint returns `string | {type, text}[] | null`. Since the block calls the endpoint directly, it flattens them itself, then strips markdown to a single line for the cell. - **The agent filter lives in two places.** The list view keeps it in its own `agent` URL param and folds it into the span query only when calling the API. The link mirrors the former, the block the latter, so both are filtered identically. Ordering also differs: the endpoint returns by relevance, and the list view sorts newest-first before rendering, so the preview re-sorts to match. ### Testing 10 tests across both embeds — inline hrefs and their padded time windows, the transcript, aggregates, API-title-wins-over-tag-title, selection staying local, the error state, the row preview with ordering and formatting, content-part flattening, and the empty state. The whole `seer/markdown` suite passes; oxlint and oxfmt are clean, and `pnpm gen:embed-widgets` produces no diff. Closes https://linear.app/getsentry/issue/CW-2003/add-ai-conversations 🤖 Generated with [Claude Code](https://claude.ai/code) https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ
Ran `pnpm gen:embed-widgets`. CI regenerates this file and fails if it is out of sync with schemas.ts. Claude-Session: https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ
`<EmbedStory name="log" />` renders the schema's `examples` verbatim, and those ids are synthetic, so the stories page showed four dead cards. Every other embed keyed by an org-specific id -- replay, trace, monitor, release, savedQuery -- ships a story that fetches a real example from the current organization instead; do the same here. The story takes the most recent log that carries both a trace and a project, since the details lookup behind the block is addressed by those two, and renders the summary, both attribute views, and the id-only path that makes the block resolve trace and project for itself. Claude-Session: https://claude.ai/code/session_01MuArcDjh7FsQ3UgQKFPKst
The log block reached the details endpoint through `useExploreLogsTableRow`, which adds `enabled: props.enabled && usePageFilters().isReady` on top of whatever the caller asked for. The logs table needs that gate; an embed handed its own trace, project and timestamp does not. Nothing sets `isReady` but `PageFiltersContainer`, and that is mounted per view -- 36 of them -- not by the layout. Seer renders from the organization layout, so on every page without one the query stayed disabled, a disabled query reports `status: 'pending'`, and the block sat on a spinner forever. The stories page is one such page, which is how this surfaced. Call `useTraceItemDetails` directly instead, with the arguments the wrapper was passing anyway. The regression test drops page filters the way such a page has them -- `init()` alone, leaving `isReady` false -- and fails against the previous version. Claude-Session: https://claude.ai/code/session_01MuArcDjh7FsQ3UgQKFPKst
Only `getLogPageFilters`, in the same module, ever reads it, so knip counts the export as dead and fails the frontend build. Claude-Session: https://claude.ai/code/session_01MuArcDjh7FsQ3UgQKFPKst
Two issues Bugbot raised, both real. The header link was built from the raw props while the rest of the card used the identity resolved from the row lookup. Given only an id, the link emitted no project and scoped Explore to My Projects, so it could miss the very row the card had just loaded. It now takes the resolved identity, which also carries the row's timestamp when neither Seer nor the id supplied one. `canFetchDetails` asked only for a trace and a project id, but `useTraceItemDetails` addresses the endpoint by the project's slug and stays disabled until `useProjectFromId` finds one. A disabled query reports `pending`, so a project the viewer cannot see never reached the error branch and spun forever -- the same trap as the page-filters gate, in the half of the condition that fix left open. The spinner now waits only while the store is filling, then falls through to "Unable to load log details". Both tests fail against the previous commit. Claude-Session: https://claude.ai/code/session_01MuArcDjh7FsQ3UgQKFPKst
`useTraceItemDetails` reports a project it cannot find to Sentry unless the caller disabled it too, so enabling the query on `resolvedProjectId && resolvedTraceId` -- an id, not a project we can actually reach -- captured an exception for a state the card already renders as "Unable to load log details". `canFetchDetails` was already the right condition and now moves above the hook to serve as its `enabled`, leaving one gate instead of two that have to agree. Claude-Session: https://claude.ai/code/session_01MuArcDjh7FsQ3UgQKFPKst
Replaces the hand-rolled `SeverityTag` styled span, per review. `Tag` takes a semantic variant rather than the logs table's per-level colors, so TRACE and DEBUG share `muted` and FATAL joins ERROR on `danger`. Those finer shades earn their keep when scanned down a column of rows; a single embedded row has no column, and matching the design system is worth more here than the extra shades. The border goes with it. `getLogColors` stays -- the attribute tree still renders from it. Claude-Session: https://claude.ai/code/session_01MuArcDjh7FsQ3UgQKFPKst
797834e to
fdef2ee
Compare
Adds a
logSeer markdown embed for one row in Explore > Logs. Inline renders a link that opens the row in Explore; block renders its severity, message and timestamp.One of four independent branches adding single-resource Seer embeds — see also #123901 (profile) and #123905 (event). They all touch
schemas.ts,index.ts, the stories page and the generated widget JSON, so whichever merges first leaves the rest needing a rebase plus apnpm gen:embed-widgetsre-run.The
viewfieldviewsummary(default)attributesattribute+attributekeyattributewithout a key falls back tosummaryand issues no request.Notes for review
Only the log id is required. When
traceId/projectIdare missing the block resolves them first via an events query. Log ids are UUIDv7, sologItemIdToTimestampdecodes the creation time from the id itself and the lookup scans a ±5min window rather than the org's whole retention; it falls back to a widestatsPeriodonly when neither Seer nor the id yields a timestamp.The attribute breakdown is a plain aggregate logs query, not the trace-item stats endpoint — that endpoint's
SupportedItemTypeis spans and occurrences only, so it cannot serve logs today.LogRowContentis deliberately not reused. It hard-requires three contexts that throw without providers (QueryParamsContext,LogsAutoRefreshContext, and the analytics page source), and it emits<tr>markup that must live inside a table. MountingLogsQueryParamsProviderinside a Seer conversation is more machinery than a single row warrants, so the block renders its own card from the same severity/color helpers.The attribute tree is inert (
config={{disableActions: true}}) and its renderers get an inert location/navigate pair, since the row actions exist to filter the logs table the tree normally lives in — an embed has no query params to write, and the README forbids touching the host page's URL.Testing
6 tests covering the inline href and its time window, the block summary, both attribute views, the no-key fallback, and the id-only path resolving trace/project before fetching details. The whole
seer/markdownsuite passes; oxlint and oxfmt are clean, andpnpm gen:embed-widgetsproduces no diff.Closes https://linear.app/getsentry/issue/CW-1946/add-log-embed
🤖 Generated with Claude Code
https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ