threadsV2.tsx 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. import {Fragment, useState} from 'react';
  2. import isNil from 'lodash/isNil';
  3. import Pill from 'sentry/components/pill';
  4. import Pills from 'sentry/components/pills';
  5. import {t} from 'sentry/locale';
  6. import {
  7. EntryType,
  8. Event,
  9. Frame,
  10. PlatformType,
  11. Project,
  12. STACK_TYPE,
  13. STACK_VIEW,
  14. Thread,
  15. } from 'sentry/types';
  16. import {PermalinkTitle, TraceEventDataSection} from '../traceEventDataSection';
  17. import Exception from './crashContent/exception';
  18. import StackTrace from './crashContent/stackTrace';
  19. import ThreadSelector from './threads/threadSelector';
  20. import findBestThread from './threads/threadSelector/findBestThread';
  21. import getThreadException from './threads/threadSelector/getThreadException';
  22. import getThreadStacktrace from './threads/threadSelector/getThreadStacktrace';
  23. import NoStackTraceMessage from './noStackTraceMessage';
  24. import {isStacktraceNewestFirst} from './utils';
  25. type ExceptionProps = React.ComponentProps<typeof Exception>;
  26. type Props = Pick<ExceptionProps, 'groupingCurrentLevel' | 'hasHierarchicalGrouping'> & {
  27. data: {
  28. values?: Array<Thread>;
  29. };
  30. event: Event;
  31. projectSlug: Project['slug'];
  32. };
  33. type State = {
  34. activeThread?: Thread;
  35. };
  36. function getIntendedStackView(
  37. thread: Thread,
  38. exception: ReturnType<typeof getThreadException>
  39. ): STACK_VIEW {
  40. if (exception) {
  41. return exception.values.find(value => !!value.stacktrace?.hasSystemFrames)
  42. ? STACK_VIEW.APP
  43. : STACK_VIEW.FULL;
  44. }
  45. const stacktrace = getThreadStacktrace(false, thread);
  46. return stacktrace?.hasSystemFrames ? STACK_VIEW.APP : STACK_VIEW.FULL;
  47. }
  48. export function ThreadsV2({
  49. data,
  50. event,
  51. projectSlug,
  52. hasHierarchicalGrouping,
  53. groupingCurrentLevel,
  54. }: Props) {
  55. const threads = data.values ?? [];
  56. const [state, setState] = useState<State>(() => {
  57. const thread = threads.length ? findBestThread(threads) : undefined;
  58. return {activeThread: thread};
  59. });
  60. const stackTraceNotFound = !threads.length;
  61. const {activeThread} = state;
  62. const hasMoreThanOneThread = threads.length > 1;
  63. const exception = getThreadException(event, activeThread);
  64. const entryIndex = exception
  65. ? event.entries.findIndex(entry => entry.type === EntryType.EXCEPTION)
  66. : event.entries.findIndex(entry => entry.type === EntryType.THREADS);
  67. const meta = event._meta?.entries?.[entryIndex]?.data?.values;
  68. const stackView = activeThread
  69. ? getIntendedStackView(activeThread, exception)
  70. : undefined;
  71. function getPlatform(): PlatformType {
  72. let exceptionFramePlatform: Frame | undefined = undefined;
  73. for (const value of exception?.values ?? []) {
  74. exceptionFramePlatform = value.stacktrace?.frames?.find(frame => !!frame.platform);
  75. if (exceptionFramePlatform) {
  76. break;
  77. }
  78. }
  79. if (exceptionFramePlatform?.platform) {
  80. return exceptionFramePlatform.platform;
  81. }
  82. const threadFramePlatform = activeThread?.stacktrace?.frames?.find(
  83. frame => !!frame.platform
  84. );
  85. if (threadFramePlatform?.platform) {
  86. return threadFramePlatform.platform;
  87. }
  88. return event.platform ?? 'other';
  89. }
  90. function renderPills() {
  91. const {id, name, current, crashed} = activeThread ?? {};
  92. if (isNil(id) || !name) {
  93. return null;
  94. }
  95. return (
  96. <Pills>
  97. {!isNil(id) && <Pill name={t('id')} value={String(id)} />}
  98. {!!name?.trim() && <Pill name={t('name')} value={name} />}
  99. {current !== undefined && <Pill name={t('was active')} value={current} />}
  100. {crashed !== undefined && (
  101. <Pill name={t('errored')} className={crashed ? 'false' : 'true'}>
  102. {crashed ? t('yes') : t('no')}
  103. </Pill>
  104. )}
  105. </Pills>
  106. );
  107. }
  108. function renderContent({
  109. display,
  110. recentFirst,
  111. fullStackTrace,
  112. }: Parameters<React.ComponentProps<typeof TraceEventDataSection>['children']>[0]) {
  113. const stackType = display.includes('minified')
  114. ? STACK_TYPE.MINIFIED
  115. : STACK_TYPE.ORIGINAL;
  116. if (exception) {
  117. return (
  118. <Exception
  119. stackType={stackType}
  120. stackView={
  121. display.includes('raw-stack-trace')
  122. ? STACK_VIEW.RAW
  123. : fullStackTrace
  124. ? STACK_VIEW.FULL
  125. : STACK_VIEW.APP
  126. }
  127. projectSlug={projectSlug}
  128. newestFirst={recentFirst}
  129. event={event}
  130. platform={platform}
  131. values={exception.values}
  132. groupingCurrentLevel={groupingCurrentLevel}
  133. hasHierarchicalGrouping={hasHierarchicalGrouping}
  134. meta={meta}
  135. />
  136. );
  137. }
  138. const stackTrace = getThreadStacktrace(
  139. stackType !== STACK_TYPE.ORIGINAL,
  140. activeThread
  141. );
  142. if (stackTrace) {
  143. return (
  144. <StackTrace
  145. stacktrace={stackTrace}
  146. stackView={
  147. display.includes('raw-stack-trace')
  148. ? STACK_VIEW.RAW
  149. : fullStackTrace
  150. ? STACK_VIEW.FULL
  151. : STACK_VIEW.APP
  152. }
  153. newestFirst={recentFirst}
  154. event={event}
  155. platform={platform}
  156. groupingCurrentLevel={groupingCurrentLevel}
  157. hasHierarchicalGrouping={hasHierarchicalGrouping}
  158. meta={meta}
  159. nativeV2
  160. />
  161. );
  162. }
  163. return (
  164. <NoStackTraceMessage
  165. message={activeThread?.crashed ? t('Thread Errored') : undefined}
  166. />
  167. );
  168. }
  169. const platform = getPlatform();
  170. return (
  171. <TraceEventDataSection
  172. type={EntryType.THREADS}
  173. stackType={STACK_TYPE.ORIGINAL}
  174. projectSlug={projectSlug}
  175. eventId={event.id}
  176. recentFirst={isStacktraceNewestFirst()}
  177. fullStackTrace={stackView === STACK_VIEW.FULL}
  178. title={
  179. hasMoreThanOneThread && activeThread ? (
  180. <ThreadSelector
  181. threads={threads}
  182. activeThread={activeThread}
  183. event={event}
  184. onChange={thread => {
  185. setState({
  186. ...state,
  187. activeThread: thread,
  188. });
  189. }}
  190. exception={exception}
  191. fullWidth
  192. />
  193. ) : (
  194. <PermalinkTitle>{t('Stack Trace')}</PermalinkTitle>
  195. )
  196. }
  197. platform={platform}
  198. hasMinified={
  199. !!exception?.values?.find(value => value.rawStacktrace) ||
  200. !!activeThread?.rawStacktrace
  201. }
  202. hasVerboseFunctionNames={
  203. !!exception?.values?.some(
  204. value =>
  205. !!value.stacktrace?.frames?.some(
  206. frame =>
  207. !!frame.rawFunction &&
  208. !!frame.function &&
  209. frame.rawFunction !== frame.function
  210. )
  211. ) ||
  212. !!activeThread?.stacktrace?.frames?.some(
  213. frame =>
  214. !!frame.rawFunction &&
  215. !!frame.function &&
  216. frame.rawFunction !== frame.function
  217. )
  218. }
  219. hasAbsoluteFilePaths={
  220. !!exception?.values?.some(
  221. value => !!value.stacktrace?.frames?.some(frame => !!frame.filename)
  222. ) || !!activeThread?.stacktrace?.frames?.some(frame => !!frame.filename)
  223. }
  224. hasAbsoluteAddresses={
  225. !!exception?.values?.some(
  226. value => !!value.stacktrace?.frames?.some(frame => !!frame.instructionAddr)
  227. ) || !!activeThread?.stacktrace?.frames?.some(frame => !!frame.instructionAddr)
  228. }
  229. hasAppOnlyFrames={
  230. !!exception?.values?.some(
  231. value => !!value.stacktrace?.frames?.some(frame => frame.inApp !== true)
  232. ) || !!activeThread?.stacktrace?.frames?.some(frame => frame.inApp !== true)
  233. }
  234. hasNewestFirst={
  235. !!exception?.values?.some(value => (value.stacktrace?.frames ?? []).length > 1) ||
  236. (activeThread?.stacktrace?.frames ?? []).length > 1
  237. }
  238. stackTraceNotFound={stackTraceNotFound}
  239. wrapTitle={false}
  240. >
  241. {childrenProps => (
  242. <Fragment>
  243. {renderPills()}
  244. {renderContent(childrenProps)}
  245. </Fragment>
  246. )}
  247. </TraceEventDataSection>
  248. );
  249. }