Skip to content

Commit

Permalink
feat(source-map-debug): Connect source map debug modal to backend (#5…
Browse files Browse the repository at this point in the history
  • Loading branch information
lforst authored Sep 25, 2023
1 parent e4a6931 commit 9ec3aa8
Show file tree
Hide file tree
Showing 6 changed files with 364 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import {useState} from 'react';
import styled from '@emotion/styled';

import {Button} from 'sentry/components/button';
import {
prepareSourceMapDebuggerFrameInformation,
useSourceMapDebuggerData,
} from 'sentry/components/events/interfaces/crashContent/exception/useSourceMapDebuggerData';
import {AnnotatedText} from 'sentry/components/events/meta/annotatedText';
import {Tooltip} from 'sentry/components/tooltip';
import {tct, tn} from 'sentry/locale';
Expand Down Expand Up @@ -121,6 +125,7 @@ export function Content({
groupingCurrentLevel,
hasHierarchicalGrouping,
platform,
projectSlug,
values,
type,
meta,
Expand All @@ -129,6 +134,8 @@ export function Content({
const {collapsedExceptions, toggleException, expandException} =
useCollapsedExceptions(values);

const sourceMapDebuggerData = useSourceMapDebuggerData(event, projectSlug);

// Organization context may be unavailable for the shared event view, so we
// avoid using the `useOrganization` hook here and directly useContext
// instead.
Expand All @@ -141,6 +148,12 @@ export function Content({
? `exception-${exc.mechanism?.exception_id}`
: undefined;

const frameSourceMapDebuggerData = sourceMapDebuggerData?.exceptions[
excIdx
].frames.map(debuggerFrame =>
prepareSourceMapDebuggerFrameInformation(sourceMapDebuggerData, debuggerFrame)
);

if (exc.mechanism?.parent_id && collapsedExceptions[exc.mechanism.parent_id]) {
return null;
}
Expand Down Expand Up @@ -190,6 +203,7 @@ export function Content({
groupingCurrentLevel={groupingCurrentLevel}
meta={meta?.[excIdx]?.stacktrace}
threadId={threadId}
frameSourceMapDebuggerData={frameSourceMapDebuggerData}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import EmptyMessage from 'sentry/components/emptyMessage';
import {FrameSourceMapDebuggerData} from 'sentry/components/events/interfaces/sourceMapsDebuggerModal';
import Panel from 'sentry/components/panels/panel';
import {IconWarning} from 'sentry/icons';
import {t} from 'sentry/locale';
Expand All @@ -20,6 +21,7 @@ type Props = {
platform: PlatformType;
stacktrace: ExceptionValue['stacktrace'];
expandFirstFrame?: boolean;
frameSourceMapDebuggerData?: FrameSourceMapDebuggerData[];
groupingCurrentLevel?: Group['metadata']['current_level'];
meta?: Record<any, any>;
newestFirst?: boolean;
Expand All @@ -40,6 +42,7 @@ function StackTrace({
event,
meta,
threadId,
frameSourceMapDebuggerData,
}: Props) {
if (!defined(stacktrace)) {
return null;
Expand Down Expand Up @@ -121,6 +124,7 @@ function StackTrace({
event={event}
meta={meta}
threadId={threadId}
frameSourceMapDebuggerData={frameSourceMapDebuggerData}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import {FrameSourceMapDebuggerData} from 'sentry/components/events/interfaces/sourceMapsDebuggerModal';
import {Event} from 'sentry/types/event';
import {useApiQuery} from 'sentry/utils/queryClient';
import useOrganization from 'sentry/utils/useOrganization';

interface SourceMapDebugBlueThunderResponseFrame {
debug_id_process: {
debug_id: string | null;
uploaded_source_file_with_correct_debug_id: boolean;
uploaded_source_map_with_correct_debug_id: boolean;
};
release_process: {
abs_path: string;
matching_source_file_names: string[];
matching_source_map_name: string | null;
source_file_lookup_result: 'found' | 'wrong-dist' | 'unsuccessful';
source_map_lookup_result: 'found' | 'wrong-dist' | 'unsuccessful';
source_map_reference: string | null;
} | null;
}

interface SourceMapDebugBlueThunderResponse {
dist: string | null;
exceptions: {
frames: SourceMapDebugBlueThunderResponseFrame[];
}[];
has_debug_ids: boolean;
has_uploaded_some_artifact_with_a_debug_id: boolean;
project_has_some_artifact_bundle: boolean;
release: string | null;
release_has_some_artifact: boolean;
sdk_debug_id_support: 'not-supported' | 'unofficial-sdk' | 'needs-upgrade' | 'full';
sdk_version: string | null;
}

export function useSourceMapDebuggerData(event: Event, projectSlug: string) {
const isSdkThatShouldShowSourceMapsDebugger =
!!event.sdk?.name.startsWith('sentry.javascript.');
const organization = useOrganization({allowNull: true});
const {data: sourceMapDebuggerData} = useApiQuery<SourceMapDebugBlueThunderResponse>(
[
`/projects/${organization!.slug}/${projectSlug}/events/${
event.id
}/source-map-debug-blue-thunder-edition/`,
],
{
enabled:
isSdkThatShouldShowSourceMapsDebugger &&
organization !== null &&
organization.features.includes('source-maps-debugger-blue-thunder-edition'),
staleTime: Infinity,
retry: false,
refetchOnWindowFocus: false,
}
);
return sourceMapDebuggerData;
}

function getDebugIdProgress(
sourceMapDebuggerData: SourceMapDebugBlueThunderResponse,
debuggerFrame: SourceMapDebugBlueThunderResponseFrame
) {
let debugIdProgress = 0;
if (sourceMapDebuggerData.sdk_debug_id_support === 'full') {
debugIdProgress++;
}
if (debuggerFrame.debug_id_process.debug_id !== null) {
debugIdProgress++;
}
if (debuggerFrame.debug_id_process.uploaded_source_file_with_correct_debug_id) {
debugIdProgress++;
}
if (debuggerFrame.debug_id_process.uploaded_source_map_with_correct_debug_id) {
debugIdProgress++;
}
return {debugIdProgress, debugIdProgressPercent: debugIdProgress / 4};
}

function getReleaseProgress(
sourceMapDebuggerData: SourceMapDebugBlueThunderResponse,
debuggerFrame: SourceMapDebugBlueThunderResponseFrame
) {
let releaseProgress = 0;
if (sourceMapDebuggerData.release !== null) {
releaseProgress++;
}
if (sourceMapDebuggerData.release_has_some_artifact) {
releaseProgress++;
}
if (debuggerFrame.release_process?.source_file_lookup_result === 'found') {
releaseProgress++;
}
if (debuggerFrame.release_process?.source_map_lookup_result === 'found') {
releaseProgress++;
}
return {releaseProgress, releaseProgressPercent: releaseProgress / 4};
}

function getScrapingProgress() {
const scrapingProgress = 0;

// TODO: Once we have data on scraping uncomment below and add logic to track progress.

// if (sourceResolutionResults.sourceFileScrapingStatus.status === 'found') {
// scrapingProgress++;
// }
// if (todo === 'found') {
// // We give this step a relative weight of 4/5ths because this is actually way
// // harder than step 1 and we want do deprioritize this tab over the others
// // because the scraping process comes with a few downsides that aren't immediately
// // obvious.
// scrapingProgress += 4;
// }
return {scrapingProgress, scrapingProgressPercent: scrapingProgress / 5};
}

export function prepareSourceMapDebuggerFrameInformation(
sourceMapDebuggerData: SourceMapDebugBlueThunderResponse,
debuggerFrame: SourceMapDebugBlueThunderResponseFrame
): FrameSourceMapDebuggerData {
const {debugIdProgressPercent, debugIdProgress} = getDebugIdProgress(
sourceMapDebuggerData,
debuggerFrame
);
const {releaseProgressPercent, releaseProgress} = getReleaseProgress(
sourceMapDebuggerData,
debuggerFrame
);
const {scrapingProgressPercent, scrapingProgress} = getScrapingProgress();

const frameIsResolved =
debugIdProgressPercent === 1 ||
releaseProgressPercent === 1 ||
scrapingProgressPercent === 1;

return {
dist: sourceMapDebuggerData.dist,
eventHasDebugIds: sourceMapDebuggerData.has_debug_ids,
matchingSourceFileNames:
debuggerFrame.release_process?.matching_source_file_names ?? [],
release: sourceMapDebuggerData.release,
releaseHasSomeArtifact: sourceMapDebuggerData.release_has_some_artifact,
releaseSourceMapReference:
debuggerFrame.release_process?.source_map_reference ?? null,
sdkDebugIdSupport: sourceMapDebuggerData.sdk_debug_id_support,
sourceFileReleaseNameFetchingResult:
debuggerFrame.release_process?.source_file_lookup_result ?? 'unsuccessful',
sourceFileScrapingStatus: {status: 'none'},
sourceMapReleaseNameFetchingResult:
debuggerFrame.release_process?.source_map_lookup_result ?? 'unsuccessful',
sourceMapScrapingStatus: {status: 'none'},
stackFrameDebugId: debuggerFrame.debug_id_process.debug_id,
stackFramePath: debuggerFrame.release_process?.abs_path ?? null,
uploadedSomeArtifactWithDebugId:
sourceMapDebuggerData.has_uploaded_some_artifact_with_a_debug_id,
uploadedSourceFileWithCorrectDebugId:
debuggerFrame.debug_id_process.uploaded_source_file_with_correct_debug_id,
uploadedSourceMapWithCorrectDebugId:
debuggerFrame.debug_id_process.uploaded_source_map_with_correct_debug_id,
sdkVersion: sourceMapDebuggerData.sdk_version,
matchingSourceMapName:
debuggerFrame.release_process?.matching_source_map_name ?? null,
debugIdProgressPercent,
debugIdProgress,
releaseProgressPercent,
releaseProgress,
scrapingProgressPercent,
scrapingProgress,
frameIsResolved,
} satisfies FrameSourceMapDebuggerData;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {cloneElement, Fragment, useState} from 'react';
import styled from '@emotion/styled';

import GuideAnchor from 'sentry/components/assistant/guideAnchor';
import {FrameSourceMapDebuggerData} from 'sentry/components/events/interfaces/sourceMapsDebuggerModal';
import Panel from 'sentry/components/panels/panel';
import {t} from 'sentry/locale';
import {Frame, Organization, PlatformType} from 'sentry/types';
Expand Down Expand Up @@ -32,6 +33,7 @@ type Props = {
event: Event;
platform: PlatformType;
className?: string;
frameSourceMapDebuggerData?: FrameSourceMapDebuggerData[];
hideIcon?: boolean;
isHoverPreviewed?: boolean;
lockAddress?: string;
Expand All @@ -58,6 +60,7 @@ function Content({
threadId,
lockAddress,
organization,
frameSourceMapDebuggerData,
}: Props) {
const [showingAbsoluteAddresses, setShowingAbsoluteAddresses] = useState(false);
const [showCompleteFunctionName, setShowCompleteFunctionName] = useState(false);
Expand Down Expand Up @@ -244,6 +247,7 @@ function Content({
lockAddress,
hiddenFrameCount: frameCountMap[frameIndex],
organization,
frameSourceResolutionResults: frameSourceMapDebuggerData?.[frameIndex],
};

nRepeats = 0;
Expand Down
48 changes: 47 additions & 1 deletion static/app/components/events/interfaces/frame/deprecatedLine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ import styled from '@emotion/styled';
import classNames from 'classnames';
import scrollToElement from 'scroll-to-element';

import {openModal} from 'sentry/actionCreators/modal';
import {Button} from 'sentry/components/button';
import {analyzeFrameForRootCause} from 'sentry/components/events/interfaces/analyzeFrames';
import LeadHint from 'sentry/components/events/interfaces/frame/line/leadHint';
import {
FrameSourceMapDebuggerData,
SourceMapsDebuggerModal,
} from 'sentry/components/events/interfaces/sourceMapsDebuggerModal';
import {getThreadById} from 'sentry/components/events/interfaces/utils';
import StrictClick from 'sentry/components/strictClick';
import Tag from 'sentry/components/tag';
import {SLOW_TOOLTIP_DELAY} from 'sentry/constants';
import {IconChevron, IconRefresh} from 'sentry/icons';
import {IconChevron, IconFlag, IconRefresh} from 'sentry/icons';
import {t, tn} from 'sentry/locale';
import DebugMetaStore from 'sentry/stores/debugMetaStore';
import {space} from 'sentry/styles/space';
Expand Down Expand Up @@ -50,6 +55,7 @@ export interface DeprecatedLineProps {
registers: Record<string, string>;
emptySourceNotation?: boolean;
frameMeta?: Record<any, any>;
frameSourceResolutionResults?: FrameSourceMapDebuggerData;
hiddenFrameCount?: number;
image?: React.ComponentProps<typeof DebugImage>['image'];
includeSystemFrames?: boolean;
Expand Down Expand Up @@ -308,6 +314,12 @@ export class DeprecatedLine extends Component<Props, State> {
lockAddress
);

const shouldShowSourceMapDebuggerToggle =
data.inApp &&
this.props.frameSourceResolutionResults &&
(!this.props.frameSourceResolutionResults.frameIsResolved ||
!hasContextSource(data));

return (
<StrictClick onClick={this.isExpandable() ? this.toggleContext : undefined}>
<DefaultLine
Expand Down Expand Up @@ -341,6 +353,28 @@ export class DeprecatedLine extends Component<Props, State> {
</Tag>
) : null}
{stacktraceChangesEnabled ? this.renderShowHideToggle() : null}
{shouldShowSourceMapDebuggerToggle ? (
<SourceMapDebuggerToggle
icon={<IconFlag />}
to=""
tooltipText={t(
'Learn how to show the original source code for this stack frame.'
)}
onClick={e => {
e.stopPropagation();
openModal(modalProps => (
<SourceMapsDebuggerModal
sourceResolutionResults={this.props.frameSourceResolutionResults!}
{...modalProps}
/>
));
}}
>
{hasContextSource(data)
? t('Not your source code?')
: t('No source code?')}
</SourceMapDebuggerToggle>
) : null}
{!data.inApp ? (
stacktraceChangesEnabled ? null : (
<Tag>{t('System')}</Tag>
Expand Down Expand Up @@ -611,3 +645,15 @@ const ToggleButton = styled(Button)`
color: ${p => p.theme.subText};
}
`;

const SourceMapDebuggerToggle = styled(Tag)`
cursor: pointer;
span {
color: ${p => p.theme.gray300};
&:hover {
text-decoration: underline;
text-decoration-color: ${p => p.theme.gray200};
}
}
`;
Loading

0 comments on commit 9ec3aa8

Please sign in to comment.