threadsV2.tsx 7.8 KB

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