Skip to content
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

feat: symbol set management #26331

Merged
merged 30 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6e3395a
feat: upload symbols for missing frames
daibhin Oct 30, 2024
d6aa65a
Merge branch 'master' into dn-feat/upload-symbols-for-missing
daibhin Nov 18, 2024
3972d06
change endpoint
daibhin Nov 18, 2024
98a4722
fix linting & add comment
daibhin Nov 18, 2024
eb6e043
Merge branch 'master' into dn-feat/upload-symbols-for-missing
daibhin Nov 21, 2024
527e479
update files
daibhin Nov 21, 2024
be47ad4
cleanup tooltip components
daibhin Nov 21, 2024
21dc249
Update UI snapshots for `chromium` (2)
github-actions[bot] Nov 21, 2024
c2b9347
symbol set configuration
daibhin Nov 21, 2024
05d0fed
Merge branch 'dn-feat/upload-symbols-for-missing' of github.com:PostH…
daibhin Nov 21, 2024
822fb3f
reset snapshots
daibhin Nov 21, 2024
db2c5bf
Update UI snapshots for `chromium` (2)
github-actions[bot] Nov 21, 2024
81ffb21
symbol set frames
daibhin Nov 21, 2024
853077b
Merge branch 'dn-feat/upload-symbols-for-missing' of github.com:PostH…
daibhin Nov 21, 2024
24e9d4b
reset snapshots
daibhin Nov 21, 2024
be3f881
Update UI snapshots for `chromium` (2)
github-actions[bot] Nov 21, 2024
ed7c513
Update UI snapshots for `chromium` (2)
github-actions[bot] Nov 21, 2024
114b421
Merge branch 'master' into dn-feat/upload-symbols-for-missing
daibhin Nov 22, 2024
e046a63
fix lint
daibhin Nov 22, 2024
cafc1a5
add endpoint tests
daibhin Nov 22, 2024
b55ceac
add tests back
daibhin Nov 22, 2024
97535bc
include to avoid n+1
daibhin Nov 22, 2024
6252233
Update UI snapshots for `chromium` (2)
github-actions[bot] Nov 22, 2024
032610d
Merge branch 'master' into dn-feat/upload-symbols-for-missing
daibhin Nov 25, 2024
22a4fda
remove upload
daibhin Nov 25, 2024
25154c2
Merge branch 'dn-feat/upload-symbols-for-missing' of github.com:PostH…
daibhin Nov 25, 2024
0c47670
Update UI snapshots for `chromium` (2)
github-actions[bot] Nov 25, 2024
061a316
Merge branch 'master' into dn-feat/upload-symbols-for-missing
daibhin Nov 25, 2024
53ebb0b
fix tests
daibhin Nov 25, 2024
cf336fe
Update UI snapshots for `chromium` (2)
github-actions[bot] Nov 25, 2024
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IconX } from '@posthog/icons'
import { LemonButton, Tooltip } from '@posthog/lemon-ui'
import { LemonButton } from '@posthog/lemon-ui'
import clsx from 'clsx'
import { useActions, useValues } from 'kea'

Expand Down Expand Up @@ -31,9 +31,13 @@ export function SidePanelPaneHeader({ children, title }: SidePanelPaneHeaderProp
</h3>
) : null}
{children}
<Tooltip placement={modalMode ? 'top' : 'bottom-end'} title={modalMode ? 'Close' : 'Close this side panel'}>
<LemonButton size="small" sideIcon={<IconX />} onClick={() => closeSidePanel()} />
</Tooltip>
<LemonButton
size="small"
sideIcon={<IconX />}
onClick={() => closeSidePanel()}
tooltip={modalMode ? 'Close' : 'Close this side panel'}
tooltipPlacement={modalMode ? 'top' : 'bottom-end'}
/>
</header>
)
}
43 changes: 21 additions & 22 deletions frontend/src/layout/navigation/TopBar/AccountPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import clsx from 'clsx'
import { useActions, useValues } from 'kea'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { ProfilePicture } from 'lib/lemon-ui/ProfilePicture'
import { Tooltip } from 'lib/lemon-ui/Tooltip'
import { UploadedLogo } from 'lib/lemon-ui/UploadedLogo'
import { eventUsageLogic } from 'lib/utils/eventUsageLogic'
import { inviteLogic } from 'scenes/settings/organization/inviteLogic'
Expand Down Expand Up @@ -85,27 +84,27 @@ function CurrentOrganization({ organization }: { organization: OrganizationBasic
const { closeAccountPopover } = useActions(navigationLogic)

return (
<Tooltip title="Organization settings" placement="left">
<LemonButton
data-attr="top-menu-item-org-settings"
icon={
<UploadedLogo
name={organization.name}
entityId={organization.id}
mediaId={organization.logo_media_id}
/>
}
sideIcon={<IconGear />}
fullWidth
to={urls.settings('organization')}
onClick={closeAccountPopover}
>
<div className="grow">
<span className="font-medium">{organization.name}</span>
<AccessLevelIndicator organization={organization} />
</div>
</LemonButton>
</Tooltip>
<LemonButton
data-attr="top-menu-item-org-settings"
icon={
<UploadedLogo
name={organization.name}
entityId={organization.id}
mediaId={organization.logo_media_id}
/>
}
sideIcon={<IconGear />}
fullWidth
to={urls.settings('organization')}
onClick={closeAccountPopover}
tooltip="Organization settings"
tooltipPlacement="left"
>
<div className="grow">
<span className="font-medium">{organization.name}</span>
<AccessLevelIndicator organization={organization} />
</div>
</LemonButton>
)
}

Expand Down
55 changes: 40 additions & 15 deletions frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,11 @@ import {
} from '~/types'

import { AlertType, AlertTypeWrite } from './components/Alerts/types'
import { ErrorTrackingStackFrameContext } from './components/Errors/types'
import {
ErrorTrackingStackFrame,
ErrorTrackingStackFrameRecord,
ErrorTrackingSymbolSet,
} from './components/Errors/types'
import {
ACTIVITY_PAGE_SIZE,
DashboardPrivilegeLevel,
Expand Down Expand Up @@ -709,23 +713,33 @@ class ApiRequest {
}

public errorTrackingGroup(fingerprint: ErrorTrackingGroup['fingerprint'], teamId?: TeamType['id']): ApiRequest {
return this.errorTracking(teamId).addPathComponent(stringifiedFingerprint(fingerprint))
return this.errorTracking(teamId)
.addPathComponent('group')
.addPathComponent(stringifiedFingerprint(fingerprint))
}

public errorTrackingMerge(fingerprint: ErrorTrackingGroup['fingerprint']): ApiRequest {
public errorTrackingGroupMerge(fingerprint: ErrorTrackingGroup['fingerprint']): ApiRequest {
return this.errorTrackingGroup(fingerprint).addPathComponent('merge')
}

public errorTrackingUploadSourceMaps(): ApiRequest {
return this.errorTracking().addPathComponent('upload_source_maps')
public errorTrackingSymbolSets(teamId?: TeamType['id']): ApiRequest {
return this.errorTracking(teamId).addPathComponent('symbol_sets')
}

public errorTrackingStackFrames(): ApiRequest {
return this.errorTracking().addPathComponent('stack_frames')
public errorTrackingSymbolSet(id: ErrorTrackingSymbolSet['id']): ApiRequest {
return this.errorTrackingSymbolSets().addPathComponent(id)
}

public errorTrackingStackFrameContexts(ids: string[]): ApiRequest {
return this.errorTrackingStackFrames().addPathComponent('contexts').withQueryString(toParams({ ids }, true))
public errorTrackingStackFrames({
raw_ids,
symbol_set,
}: {
raw_ids?: ErrorTrackingStackFrame['raw_id'][]
symbol_set?: ErrorTrackingSymbolSet['id']
}): ApiRequest {
return this.errorTracking()
.addPathComponent('stack_frames')
.withQueryString(toParams({ raw_ids, symbol_set }, true))
}

// # Warehouse
Expand Down Expand Up @@ -1847,7 +1861,7 @@ const api = {
},

errorTracking: {
async update(
async updateIssue(
fingerprint: ErrorTrackingGroup['fingerprint'],
data: Partial<Pick<ErrorTrackingGroup, 'assignee' | 'status'>>
): Promise<ErrorTrackingGroup> {
Expand All @@ -1859,16 +1873,27 @@ const api = {
mergingFingerprints: ErrorTrackingGroup['fingerprint'][]
): Promise<{ content: string }> {
return await new ApiRequest()
.errorTrackingMerge(primaryFingerprint)
.errorTrackingGroup(primaryFingerprint)
.create({ data: { merging_fingerprints: mergingFingerprints } })
},
async updateSymbolSet(id: ErrorTrackingSymbolSet['id'], data: FormData): Promise<ErrorTrackingGroup> {
return await new ApiRequest().errorTrackingSymbolSet(id).update({ data })
},

async deleteSymbolSet(id: ErrorTrackingSymbolSet['id']): Promise<void> {
return await new ApiRequest().errorTrackingSymbolSet(id).delete()
},

async symbolSets(): Promise<{ results: ErrorTrackingSymbolSet[] }> {
return await new ApiRequest().errorTrackingSymbolSets().get()
},

async uploadSourceMaps(data: FormData): Promise<{ content: string }> {
return await new ApiRequest().errorTrackingUploadSourceMaps().create({ data })
async symbolSetStackFrames(id: ErrorTrackingSymbolSet['id']): Promise<ErrorTrackingStackFrameRecord[]> {
return await new ApiRequest().errorTrackingStackFrames({ symbol_set: id }).get()
},

async fetchStackFrames(ids: string[]): Promise<Record<string, ErrorTrackingStackFrameContext>> {
return await new ApiRequest().errorTrackingStackFrameContexts(ids).get()
async stackFrames(raw_ids: ErrorTrackingStackFrame['raw_id'][]): Promise<ErrorTrackingStackFrameRecord[]> {
return await new ApiRequest().errorTrackingStackFrames({ raw_ids }).get()
},
},

Expand Down
76 changes: 45 additions & 31 deletions frontend/src/lib/components/Errors/ErrorDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import './ErrorDisplay.scss'

import { IconFlag } from '@posthog/icons'
import { LemonBanner, LemonCollapse } from '@posthog/lemon-ui'
import { LemonBanner, LemonCollapse, Tooltip } from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { TitledSnack } from 'lib/components/TitledSnack'
import { LemonDivider } from 'lib/lemon-ui/LemonDivider'
Expand All @@ -28,44 +28,58 @@ function StackTrace({
frames: ErrorTrackingStackFrame[]
showAllFrames: boolean
}): JSX.Element | null {
const { frameContexts } = useValues(stackFrameLogic)
const { loadFrameContexts } = useActions(stackFrameLogic)
const { stackFrameRecords } = useValues(stackFrameLogic)
const { loadFromRawIds } = useActions(stackFrameLogic)
const displayFrames = showAllFrames ? frames : frames.filter((f) => f.in_app)

useEffect(() => {
loadFrameContexts({ frames })
}, [frames, loadFrameContexts])
loadFromRawIds(frames.map(({ raw_id }) => raw_id))
}, [frames, loadFromRawIds])

const initiallyActiveIndex = displayFrames.findIndex((f) => f.in_app) || 0

const panels = displayFrames.map(({ raw_id, source, line, column, resolved_name, lang }, index) => {
const frameContext = frameContexts[raw_id]
return {
key: index,
header: (
<div className="flex flex-wrap space-x-0.5">
<span>{source}</span>
{resolved_name ? (
<div className="flex space-x-0.5">
<span className="text-muted">in</span>
<span>{resolved_name}</span>
const panels = displayFrames.map(
({ raw_id, source, line, column, resolved_name, lang, resolved, resolve_failure }, index) => {
const record = stackFrameRecords[raw_id]
return {
key: index,
header: (
<div className="flex flex-1 justify-between items-center">
<div className="flex flex-wrap space-x-0.5">
<span>{source}</span>
{resolved_name ? (
<div className="flex space-x-0.5">
<span className="text-muted">in</span>
<span>{resolved_name}</span>
</div>
) : null}
{line ? (
<div className="flex space-x-0.5">
<span className="text-muted">@</span>
<span>
{line}
{column && `:${column}`}
</span>
</div>
) : null}
</div>
) : null}
{line ? (
<div className="flex space-x-0.5">
<span className="text-muted">@</span>
<span>
{line}
{column && `:${column}`}
</span>
</div>
) : null}
</div>
),
content: frameContext ? <FrameContext context={frameContext} language={getLanguage(lang)} /> : null,
className: 'p-0',
{!resolved && (
<div className="flex items-center space-x-1">
<Tooltip title={resolve_failure}>
<LemonTag>Unresolved</LemonTag>
</Tooltip>
</div>
)}
</div>
),
content:
record && record.context ? (
<FrameContext context={record.context} language={getLanguage(lang)} />
) : null,
className: 'p-0',
}
}
})
)

return <LemonCollapse defaultActiveKeys={[initiallyActiveIndex]} multiple panels={panels} size="xsmall" />
}
Expand Down
39 changes: 28 additions & 11 deletions frontend/src/lib/components/Errors/stackFrameLogic.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
import { kea, path } from 'kea'
import { actions, kea, path } from 'kea'
import { loaders } from 'kea-loaders'
import api from 'lib/api'

import type { stackFrameLogicType } from './stackFrameLogicType'
import { ErrorTrackingStackFrame, ErrorTrackingStackFrameContext } from './types'
import { ErrorTrackingStackFrame, ErrorTrackingStackFrameRecord, ErrorTrackingSymbolSet } from './types'

export type KeyedStackFrameRecords = Record<ErrorTrackingStackFrameRecord['raw_id'], ErrorTrackingStackFrameRecord>

function mapStackFrameRecords(
newRecords: ErrorTrackingStackFrameRecord[],
initialRecords: KeyedStackFrameRecords
): KeyedStackFrameRecords {
return newRecords.reduce((frames, record) => ({ ...frames, [record.raw_id]: record }), initialRecords)
}

export const stackFrameLogic = kea<stackFrameLogicType>([
path(['components', 'Errors', 'stackFrameLogic']),

actions({
loadFromRawIds: (rawIds: ErrorTrackingStackFrame['raw_id'][]) => ({ rawIds }),
loadForSymbolSet: (symbolSetId: ErrorTrackingSymbolSet['id']) => ({ symbolSetId }),
}),

loaders(({ values }) => ({
frameContexts: [
{} as Record<string, ErrorTrackingStackFrameContext>,
stackFrameRecords: [
{} as KeyedStackFrameRecords,
{
loadFrameContexts: async ({ frames }: { frames: ErrorTrackingStackFrame[] }) => {
const loadedFrameIds = Object.keys(values.frameContexts)
const ids = frames
.filter(({ raw_id }) => !loadedFrameIds.includes(raw_id))
.map(({ raw_id }) => raw_id)
const response = await api.errorTracking.fetchStackFrames(ids)
return { ...values.frameContexts, ...response }
loadFromRawIds: async ({ rawIds }) => {
const loadedRawIds = Object.keys(values.stackFrameRecords)
rawIds = rawIds.filter((rawId) => !loadedRawIds.includes(rawId))
const response = await api.errorTracking.stackFrames(rawIds)
return mapStackFrameRecords(response, values.stackFrameRecords)
},
loadForSymbolSet: async ({ symbolSetId }) => {
const response = await api.errorTracking.symbolSetStackFrames(symbolSetId)
return mapStackFrameRecords(response, values.stackFrameRecords)
},
},
],
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/lib/components/Errors/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ export interface ErrorTrackingStackFrameRecord {
id: string
raw_id: string
created_at: string
symbol_set: string
resolved: boolean
context: ErrorTrackingStackFrameContext | null
contents: ErrorTrackingStackFrame // For now, while we're not 100% on content structure
symbol_set_ref: ErrorTrackingSymbolSet['ref']
}

export type ErrorTrackingStackFrameContext = {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/scenes/appScenes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const appScenes: Record<Scene, () => any> = {
[Scene.EarlyAccessFeatures]: () => import('./early-access-features/EarlyAccessFeatures'),
[Scene.EarlyAccessFeature]: () => import('./early-access-features/EarlyAccessFeature'),
[Scene.ErrorTracking]: () => import('./error-tracking/ErrorTrackingScene'),
[Scene.ErrorTrackingConfiguration]: () => import('./error-tracking/ErrorTrackingConfigurationScene'),
[Scene.ErrorTrackingGroup]: () => import('./error-tracking/ErrorTrackingGroupScene'),
[Scene.Surveys]: () => import('./surveys/Surveys'),
[Scene.Survey]: () => import('./surveys/Survey'),
Expand Down
Loading
Loading