Skip to content

Commit

Permalink
feat(errors): Add support for handling chained exceptions (#24572)
Browse files Browse the repository at this point in the history
  • Loading branch information
neilkakkar authored Aug 28, 2024
1 parent a20b54c commit d74ec30
Show file tree
Hide file tree
Showing 15 changed files with 180 additions and 5 deletions.
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.
113 changes: 113 additions & 0 deletions frontend/src/lib/components/Errors/ErrorDisplay.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,116 @@ export function AnonymousErrorWithStackTrace(): JSX.Element {
/>
)
}

export function ChainedErrorStack(): JSX.Element {
return (
<ErrorDisplay
eventProperties={errorProperties({
$exception_type: 'ZeroDivisionError',
$exception_message: 'division by zero',
$exception_list: [
{
module: null,
type: 'ZeroDivisionError',
value: 'division by zero',
stacktrace: {
frames: [
{
filename: 'example2.py',
abs_path: '/posthog-python/example2.py',
function: 'will_raise',
module: '__main__',
lineno: 33,
pre_context: [
'def more_obfuscation():',
' print(3 / 0)',
'',
'def will_raise():',
' try:',
],
context_line: ' more_obfuscation()',
post_context: [
' except Exception as e:',
' raise CustomException("This is a custom exception") from e',
'',
'will_raise()',
'exit()',
],
},
{
filename: 'example2.py',
abs_path: '/posthog-python/example2.py',
function: 'more_obfuscation',
module: '__main__',
lineno: 29,
pre_context: [
'',
'class CustomException(Exception):',
' pass',
'',
'def more_obfuscation():',
],
context_line: ' print(3 / 0)',
post_context: [
'',
'def will_raise():',
' try:',
' more_obfuscation()',
' except Exception as e:',
],
},
],
},
},
{
module: '__main__',
type: 'CustomException',
value: 'This is a custom exception',
stacktrace: {
frames: [
{
filename: 'example2.py',
abs_path: '/Users/neilkakkar/Project/posthog-python/example2.py',
function: '<module>',
module: '__main__',
lineno: 37,
pre_context: [
' try:',
' more_obfuscation()',
' except Exception as e:',
' raise CustomException("This is a custom exception") from e',
'',
],
context_line: 'will_raise()',
post_context: [
'exit()',
'',
'',
'# print(posthog.get_all_flags("distinct_id_random_22"))',
'# print(',
],
},
{
filename: 'example2.py',
abs_path: '/Users/neilkakkar/Project/posthog-python/example2.py',
function: 'will_raise',
module: '__main__',
lineno: 35,
pre_context: [
'',
'def will_raise():',
' try:',
' more_obfuscation()',
' except Exception as e:',
],
context_line: ' raise CustomException("This is a custom exception") from e',
post_context: ['', 'will_raise()', 'exit()', '', ''],
},
],
},
},
],
})}
/>
)
}
51 changes: 46 additions & 5 deletions frontend/src/lib/components/Errors/ErrorDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ interface StackFrame {
lineno: number
colno: number
function: string
context_line?: string
}

interface ExceptionTrace {
stacktrace: {
frames: StackFrame[]
}
module: string
type: string
value: string
}

function parseToFrames(rawTrace: string): StackFrame[] {
Expand All @@ -25,7 +35,7 @@ function StackTrace({ rawTrace }: { rawTrace: string }): JSX.Element | null {
<>
{frames.length ? (
frames.map((frame, index) => {
const { filename, lineno, colno, function: functionName } = frame
const { filename, lineno, colno, function: functionName, context_line } = frame

return (
<TitledSnack
Expand All @@ -34,6 +44,7 @@ function StackTrace({ rawTrace }: { rawTrace: string }): JSX.Element | null {
value={
<>
{filename}:{lineno}:{colno}
{context_line ? `:${context_line}` : ''}
</>
}
/>
Expand All @@ -51,6 +62,23 @@ function StackTrace({ rawTrace }: { rawTrace: string }): JSX.Element | null {
}
}

function ChainedStackTraces({ exceptionList }: { exceptionList: ExceptionTrace[] }): JSX.Element {
return (
<>
<LemonDivider dashed={true} />
<h2 className="mb-0">Stack Trace</h2>
{exceptionList.map(({ stacktrace, value }, index) => {
return (
<div key={index} className="flex flex-col gap-1 mt-6">
<h3 className="mb-0">{value}</h3>
<StackTrace rawTrace={JSON.stringify(stacktrace.frames)} />
</div>
)
})}
</>
)
}

function ActiveFlags({ flags }: { flags: string[] }): JSX.Element {
return (
<>
Expand Down Expand Up @@ -91,6 +119,7 @@ export function getExceptionPropertiesFrom(eventProperties: Record<string, any>)
} = eventProperties

let $exception_stack_trace_raw = eventProperties.$exception_stack_trace_raw
let $exception_list = eventProperties.$exception_list
// exception autocapture sets $exception_stack_trace_raw as a string
// if it isn't present then this is probably a sentry exception.
// try and grab the frames from that
Expand All @@ -102,6 +131,14 @@ export function getExceptionPropertiesFrom(eventProperties: Record<string, any>)
}
}
}
// exception autocapture sets $exception_list for chained exceptions.
// If it's not present, get this list from the sentry_exception
if (!$exception_list?.length && $sentry_exception) {
if (Array.isArray($sentry_exception.values)) {
$exception_list = $sentry_exception.values
}
}

return {
$exception_type,
$exception_message,
Expand All @@ -115,6 +152,7 @@ export function getExceptionPropertiesFrom(eventProperties: Record<string, any>)
$active_feature_flags,
$sentry_url,
$exception_stack_trace_raw,
$exception_list,
$level,
}
}
Expand All @@ -133,6 +171,7 @@ export function ErrorDisplay({ eventProperties }: { eventProperties: EventType['
$active_feature_flags,
$sentry_url,
$exception_stack_trace_raw,
$exception_list,
$level,
} = getExceptionPropertiesFrom(eventProperties)

Expand Down Expand Up @@ -162,18 +201,20 @@ export function ErrorDisplay({ eventProperties }: { eventProperties: EventType['
/>
<TitledSnack title="synthetic" value={$exception_synthetic ? 'true' : 'false'} />
<TitledSnack title="library" value={`${$lib} ${$lib_version}`} />
<TitledSnack title="browser" value={`${$browser} ${$browser_version}`} />
<TitledSnack title="os" value={`${$os} ${$os_version}`} />
<TitledSnack title="browser" value={$browser ? `${$browser} ${$browser_version}` : 'unknown'} />
<TitledSnack title="os" value={$os ? `${$os} ${$os_version}` : 'unknown'} />
</div>
{!!$exception_stack_trace_raw?.length && (
{$exception_list?.length ? (
<ChainedStackTraces exceptionList={$exception_list} />
) : $exception_stack_trace_raw?.length ? (
<>
<LemonDivider dashed={true} />
<div className="flex flex-col gap-1 mt-6">
<h2 className="mb-0">Stack Trace</h2>
<StackTrace rawTrace={$exception_stack_trace_raw} />
</div>
</>
)}
) : null}
<LemonDivider dashed={true} />
<div className="flex flex-col gap-1 mt-6">
<h2 className="mb-0">Active Feature Flags</h2>
Expand Down
21 changes: 21 additions & 0 deletions frontend/src/lib/components/Errors/error-display.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,27 @@ describe('Error Display', () => {
$exception_message: 'There was an error creating the support ticket with zendesk.',
$exception_stack_trace_raw:
'[{"colno":220,"filename":"https://app-static-prod.posthog.com/static/chunk-UFQKIDIH.js","function":"submitZendeskTicket","in_app":true,"lineno":25}]',
$exception_list: [
{
mechanism: {
handled: true,
type: 'generic',
},
stacktrace: {
frames: [
{
colno: 220,
filename: 'https://app-static-prod.posthog.com/static/chunk-UFQKIDIH.js',
function: 'submitZendeskTicket',
in_app: true,
lineno: 25,
},
],
},
type: 'Error',
value: 'There was an error creating the support ticket with zendesk.',
},
],
$exception_synthetic: undefined,
$exception_type: 'Error',
$lib: 'posthog-js',
Expand Down

0 comments on commit d74ec30

Please sign in to comment.