123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- import {Fragment, useState} from 'react';
- import styled from '@emotion/styled';
- import isNil from 'lodash/isNil';
- import Pill from 'sentry/components/pill';
- import Pills from 'sentry/components/pills';
- import {t} from 'sentry/locale';
- import {
- Event,
- Frame,
- PlatformType,
- Project,
- STACK_TYPE,
- STACK_VIEW,
- Thread,
- } from 'sentry/types';
- import {TraceEventDataSection} from '../traceEventDataSection';
- import Exception from './crashContent/exception';
- import StackTrace from './crashContent/stackTrace';
- import ThreadSelector from './threads/threadSelector';
- import findBestThread from './threads/threadSelector/findBestThread';
- import getThreadException from './threads/threadSelector/getThreadException';
- import getThreadStacktrace from './threads/threadSelector/getThreadStacktrace';
- import NoStackTraceMessage from './noStackTraceMessage';
- import {isStacktraceNewestFirst} from './utils';
- type ExceptionProps = React.ComponentProps<typeof Exception>;
- type Props = Pick<ExceptionProps, 'groupingCurrentLevel' | 'hasHierarchicalGrouping'> & {
- data: {
- values?: Array<Thread>;
- };
- event: Event;
- projectId: Project['id'];
- type: string;
- };
- type State = {
- activeThread?: Thread;
- };
- function getIntendedStackView(thread: Thread, event: Event) {
- const exception = getThreadException(event, thread);
- if (exception) {
- return !!exception.values.find(value => !!value.stacktrace?.hasSystemFrames)
- ? STACK_VIEW.APP
- : STACK_VIEW.FULL;
- }
- const stacktrace = getThreadStacktrace(false, thread);
- return stacktrace?.hasSystemFrames ? STACK_VIEW.APP : STACK_VIEW.FULL;
- }
- function Threads({
- data,
- event,
- projectId,
- type,
- hasHierarchicalGrouping,
- groupingCurrentLevel,
- }: Props) {
- const threads = data.values ?? [];
- const [state, setState] = useState<State>(() => {
- const thread = !!threads.length ? findBestThread(threads) : undefined;
- return {activeThread: thread};
- });
- const stackTraceNotFound = !threads.length;
- const {activeThread} = state;
- const hasMoreThanOneThread = threads.length > 1;
- const exception = getThreadException(event, activeThread);
- const stackView = activeThread ? getIntendedStackView(activeThread, event) : undefined;
- function getPlatform(): PlatformType {
- let exceptionFramePlatform: Frame | undefined = undefined;
- for (const value of exception?.values ?? []) {
- exceptionFramePlatform = value.stacktrace?.frames?.find(frame => !!frame.platform);
- if (exceptionFramePlatform) {
- break;
- }
- }
- if (exceptionFramePlatform?.platform) {
- return exceptionFramePlatform.platform;
- }
- const threadFramePlatform = activeThread?.stacktrace?.frames?.find(
- frame => !!frame.platform
- );
- if (threadFramePlatform?.platform) {
- return threadFramePlatform.platform;
- }
- return event.platform ?? 'other';
- }
- function renderPills() {
- const {id, name, current, crashed} = activeThread ?? {};
- if (isNil(id) || !name) {
- return null;
- }
- return (
- <Pills>
- {!isNil(id) && <Pill name={t('id')} value={String(id)} />}
- {!!name?.trim() && <Pill name={t('name')} value={name} />}
- {current !== undefined && <Pill name={t('was active')} value={current} />}
- {crashed !== undefined && (
- <Pill name={t('errored')} className={crashed ? 'false' : 'true'}>
- {crashed ? t('yes') : t('no')}
- </Pill>
- )}
- </Pills>
- );
- }
- function renderContent({
- display,
- recentFirst,
- fullStackTrace,
- }: Parameters<React.ComponentProps<typeof TraceEventDataSection>['children']>[0]) {
- const stackType = display.includes('minified')
- ? STACK_TYPE.MINIFIED
- : STACK_TYPE.ORIGINAL;
- if (exception) {
- return (
- <Exception
- stackType={stackType}
- stackView={
- display.includes('raw-stack-trace')
- ? STACK_VIEW.RAW
- : fullStackTrace
- ? STACK_VIEW.FULL
- : STACK_VIEW.APP
- }
- projectId={projectId}
- newestFirst={recentFirst}
- event={event}
- platform={platform}
- values={exception.values}
- groupingCurrentLevel={groupingCurrentLevel}
- hasHierarchicalGrouping={hasHierarchicalGrouping}
- />
- );
- }
- const stackTrace = getThreadStacktrace(
- stackType !== STACK_TYPE.ORIGINAL,
- activeThread
- );
- if (stackTrace) {
- return (
- <StackTrace
- stacktrace={stackTrace}
- stackView={
- display.includes('raw-stack-trace')
- ? STACK_VIEW.RAW
- : fullStackTrace
- ? STACK_VIEW.FULL
- : STACK_VIEW.APP
- }
- newestFirst={recentFirst}
- event={event}
- platform={platform}
- groupingCurrentLevel={groupingCurrentLevel}
- hasHierarchicalGrouping={hasHierarchicalGrouping}
- nativeV2
- />
- );
- }
- return (
- <NoStackTraceMessage
- message={activeThread?.crashed ? t('Thread Errored') : undefined}
- />
- );
- }
- function getTitle() {
- if (hasMoreThanOneThread && activeThread) {
- return (
- <ThreadSelector
- threads={threads}
- activeThread={activeThread}
- event={event}
- onChange={thread => {
- setState({
- ...state,
- activeThread: thread,
- });
- }}
- exception={exception}
- fullWidth
- />
- );
- }
- return <Title>{t('Stack Trace')}</Title>;
- }
- const platform = getPlatform();
- return (
- <TraceEventDataSection
- type={type}
- stackType={STACK_TYPE.ORIGINAL}
- projectId={projectId}
- eventId={event.id}
- recentFirst={isStacktraceNewestFirst()}
- fullStackTrace={stackView === STACK_VIEW.FULL}
- title={getTitle()}
- platform={platform}
- showPermalink={!hasMoreThanOneThread}
- hasMinified={
- !!exception?.values?.find(value => value.rawStacktrace) ||
- !!activeThread?.rawStacktrace
- }
- hasVerboseFunctionNames={
- !!exception?.values?.some(
- value =>
- !!value.stacktrace?.frames?.some(
- frame =>
- !!frame.rawFunction &&
- !!frame.function &&
- frame.rawFunction !== frame.function
- )
- ) ||
- !!activeThread?.stacktrace?.frames?.some(
- frame =>
- !!frame.rawFunction &&
- !!frame.function &&
- frame.rawFunction !== frame.function
- )
- }
- hasAbsoluteFilePaths={
- !!exception?.values?.some(
- value => !!value.stacktrace?.frames?.some(frame => !!frame.filename)
- ) || !!activeThread?.stacktrace?.frames?.some(frame => !!frame.filename)
- }
- hasAbsoluteAddresses={
- !!exception?.values?.some(
- value => !!value.stacktrace?.frames?.some(frame => !!frame.instructionAddr)
- ) || !!activeThread?.stacktrace?.frames?.some(frame => !!frame.instructionAddr)
- }
- hasAppOnlyFrames={
- !!exception?.values?.some(
- value => !!value.stacktrace?.frames?.some(frame => frame.inApp !== true)
- ) || !!activeThread?.stacktrace?.frames?.some(frame => frame.inApp !== true)
- }
- hasNewestFirst={
- !!exception?.values?.some(value => (value.stacktrace?.frames ?? []).length > 1) ||
- (activeThread?.stacktrace?.frames ?? []).length > 1
- }
- stackTraceNotFound={stackTraceNotFound}
- wrapTitle={false}
- >
- {childrenProps => (
- <Fragment>
- {renderPills()}
- {renderContent(childrenProps)}
- </Fragment>
- )}
- </TraceEventDataSection>
- );
- }
- export default Threads;
- const Title = styled('h3')`
- margin-bottom: 0;
- `;
|