index.tsx 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. import {useMemo} from 'react';
  2. import styled from '@emotion/styled';
  3. import Alert from 'sentry/components/alert';
  4. import {EventContexts} from 'sentry/components/events/contexts';
  5. import {EventAttachments} from 'sentry/components/events/eventAttachments';
  6. import {EventEvidence} from 'sentry/components/events/eventEvidence';
  7. import {EventViewHierarchy} from 'sentry/components/events/eventViewHierarchy';
  8. import {EventRRWebIntegration} from 'sentry/components/events/rrwebIntegration';
  9. import ProjectBadge from 'sentry/components/idBadge/projectBadge';
  10. import type {LazyRenderProps} from 'sentry/components/lazyRender';
  11. import ExternalLink from 'sentry/components/links/externalLink';
  12. import LoadingError from 'sentry/components/loadingError';
  13. import LoadingIndicator from 'sentry/components/loadingIndicator';
  14. import {CustomMetricsEventData} from 'sentry/components/metrics/customMetricsEventData';
  15. import {Tooltip} from 'sentry/components/tooltip';
  16. import {t, tct} from 'sentry/locale';
  17. import type {EventTransaction} from 'sentry/types/event';
  18. import type {Organization} from 'sentry/types/organization';
  19. import type {Project} from 'sentry/types/project';
  20. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  21. import {useLocation} from 'sentry/utils/useLocation';
  22. import useProjects from 'sentry/utils/useProjects';
  23. import {useSpanMetrics} from 'sentry/views/insights/common/queries/useDiscover';
  24. import type {SpanMetricsQueryFilters} from 'sentry/views/insights/types';
  25. import {Referrer} from 'sentry/views/performance/newTraceDetails/referrers';
  26. import {useTransaction} from 'sentry/views/performance/newTraceDetails/traceApi/useTransaction';
  27. import {CacheMetrics} from 'sentry/views/performance/newTraceDetails/traceDrawer/details/transaction/sections/cacheMetrics';
  28. import type {TraceTreeNodeDetailsProps} from 'sentry/views/performance/newTraceDetails/traceDrawer/tabs/traceTreeNodeDetails';
  29. import type {
  30. TraceTree,
  31. TraceTreeNode,
  32. } from 'sentry/views/performance/newTraceDetails/traceModels/traceTree';
  33. import {getCustomInstrumentationLink} from '../../../traceConfigurations';
  34. import {IssueList} from '../issues/issues';
  35. import {TraceDrawerComponents} from '../styles';
  36. import {AdditionalData} from './sections/additionalData';
  37. import {BreadCrumbs} from './sections/breadCrumbs';
  38. import {Entries} from './sections/entries';
  39. import GeneralInfo from './sections/generalInfo';
  40. import {Measurements} from './sections/measurements';
  41. import ReplayPreview from './sections/replayPreview';
  42. import {Request} from './sections/request';
  43. import {Sdk} from './sections/sdk';
  44. export const LAZY_RENDER_PROPS: Partial<LazyRenderProps> = {
  45. observerOptions: {rootMargin: '50px'},
  46. };
  47. type TransactionNodeDetailHeaderProps = {
  48. event: EventTransaction;
  49. node: TraceTreeNode<TraceTree.Transaction>;
  50. onTabScrollToNode: (node: TraceTreeNode<any>) => void;
  51. organization: Organization;
  52. project: Project | undefined;
  53. };
  54. function TransactionNodeDetailHeader({
  55. node,
  56. organization,
  57. project,
  58. onTabScrollToNode,
  59. event,
  60. }: TransactionNodeDetailHeaderProps) {
  61. return (
  62. <TraceDrawerComponents.HeaderContainer>
  63. <TraceDrawerComponents.Title>
  64. <Tooltip title={node.value.project_slug}>
  65. <ProjectBadge
  66. project={project ? project : {slug: node.value.project_slug}}
  67. avatarSize={30}
  68. hideName
  69. />
  70. </Tooltip>
  71. <TraceDrawerComponents.TitleText>
  72. <div>{t('transaction')}</div>
  73. <TraceDrawerComponents.TitleOp
  74. text={node.value['transaction.op'] + ' - ' + node.value.transaction}
  75. />
  76. </TraceDrawerComponents.TitleText>
  77. </TraceDrawerComponents.Title>
  78. <TraceDrawerComponents.NodeActions
  79. node={node}
  80. organization={organization}
  81. onTabScrollToNode={onTabScrollToNode}
  82. eventSize={event?.size}
  83. />
  84. </TraceDrawerComponents.HeaderContainer>
  85. );
  86. }
  87. export function TransactionNodeDetails({
  88. node,
  89. organization,
  90. onTabScrollToNode,
  91. onParentClick,
  92. replayRecord,
  93. }: TraceTreeNodeDetailsProps<TraceTreeNode<TraceTree.Transaction>>) {
  94. const location = useLocation();
  95. const {projects} = useProjects();
  96. const issues = useMemo(() => {
  97. return [...node.errors, ...node.performance_issues];
  98. }, [node.errors, node.performance_issues]);
  99. const {
  100. data: event,
  101. isError,
  102. isPending,
  103. } = useTransaction({
  104. node,
  105. organization,
  106. });
  107. const {data: cacheMetrics} = useSpanMetrics(
  108. {
  109. search: MutableSearch.fromQueryObject({
  110. transaction: node.value.transaction,
  111. } satisfies SpanMetricsQueryFilters),
  112. fields: ['avg(cache.item_size)', 'cache_miss_rate()'],
  113. },
  114. Referrer.TRACE_DRAWER_TRANSACTION_CACHE_METRICS
  115. );
  116. if (isPending) {
  117. return <LoadingIndicator />;
  118. }
  119. if (isError) {
  120. return <LoadingError message={t('Failed to fetch transaction details')} />;
  121. }
  122. const project = projects.find(proj => proj.slug === event?.projectSlug);
  123. return (
  124. <TraceDrawerComponents.DetailContainer>
  125. {!node.canFetch ? (
  126. <StyledAlert type="info" showIcon>
  127. {tct(
  128. 'This transaction does not have any child spans. You can add more child spans via [customInstrumentationLink:custom instrumentation].',
  129. {
  130. customInstrumentationLink: (
  131. <ExternalLink href={getCustomInstrumentationLink(project)} />
  132. ),
  133. }
  134. )}
  135. </StyledAlert>
  136. ) : null}
  137. <TransactionNodeDetailHeader
  138. node={node}
  139. organization={organization}
  140. project={project}
  141. event={event}
  142. onTabScrollToNode={onTabScrollToNode}
  143. />
  144. <IssueList node={node} organization={organization} issues={issues} />
  145. <TraceDrawerComponents.SectionCardGroup>
  146. <GeneralInfo
  147. node={node}
  148. onParentClick={onParentClick}
  149. organization={organization}
  150. event={event}
  151. location={location}
  152. />
  153. <AdditionalData event={event} />
  154. <Measurements event={event} location={location} organization={organization} />
  155. {cacheMetrics.length > 0 ? <CacheMetrics cacheMetrics={cacheMetrics} /> : null}
  156. <Sdk event={event} />
  157. <CustomMetricsEventData
  158. metricsSummary={event._metrics_summary}
  159. startTimestamp={event.startTimestamp}
  160. projectId={event.projectID}
  161. />
  162. <TraceDrawerComponents.TraceDataSection event={event} />
  163. </TraceDrawerComponents.SectionCardGroup>
  164. <Request event={event} />
  165. {event.projectSlug ? (
  166. <Entries
  167. definedEvent={event}
  168. projectSlug={event.projectSlug}
  169. group={undefined}
  170. organization={organization}
  171. />
  172. ) : null}
  173. <TraceDrawerComponents.EventTags
  174. projectSlug={node.value.project_slug}
  175. event={event}
  176. />
  177. <EventContexts event={event} />
  178. {project ? <EventEvidence event={event} project={project} /> : null}
  179. {replayRecord ? null : <ReplayPreview event={event} organization={organization} />}
  180. <BreadCrumbs event={event} organization={organization} />
  181. {event.projectSlug ? (
  182. <EventAttachments event={event} projectSlug={event.projectSlug} />
  183. ) : null}
  184. {project ? <EventViewHierarchy event={event} project={project} /> : null}
  185. {event.projectSlug ? (
  186. <EventRRWebIntegration
  187. event={event}
  188. orgId={organization.slug}
  189. projectSlug={event.projectSlug}
  190. />
  191. ) : null}
  192. </TraceDrawerComponents.DetailContainer>
  193. );
  194. }
  195. const StyledAlert = styled(Alert)`
  196. margin: 0;
  197. `;