aggregateFlamegraphPanel.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import {useEffect} from 'react';
  2. import styled from '@emotion/styled';
  3. import * as Sentry from '@sentry/react';
  4. import EmptyStateWarning from 'sentry/components/emptyStateWarning';
  5. import LoadingIndicator from 'sentry/components/loadingIndicator';
  6. import Panel from 'sentry/components/panels/panel';
  7. import {DeprecatedAggregateFlamegraph} from 'sentry/components/profiling/flamegraph/deprecatedAggregateFlamegraph';
  8. import {Flex} from 'sentry/components/profiling/flex';
  9. import QuestionTooltip from 'sentry/components/questionTooltip';
  10. import {t} from 'sentry/locale';
  11. import {space} from 'sentry/styles/space';
  12. import {DeepPartial} from 'sentry/types/utils';
  13. import type {FlamegraphState} from 'sentry/utils/profiling/flamegraph/flamegraphStateProvider/flamegraphContext';
  14. import {FlamegraphStateProvider} from 'sentry/utils/profiling/flamegraph/flamegraphStateProvider/flamegraphContextProvider';
  15. import {FlamegraphThemeProvider} from 'sentry/utils/profiling/flamegraph/flamegraphThemeProvider';
  16. import {Frame} from 'sentry/utils/profiling/frame';
  17. import {useAggregateFlamegraphQuery} from 'sentry/utils/profiling/hooks/useAggregateFlamegraphQuery';
  18. import {useLocalStorageState} from 'sentry/utils/useLocalStorageState';
  19. import usePageFilters from 'sentry/utils/usePageFilters';
  20. import {ProfileGroupProvider} from 'sentry/views/profiling/profileGroupProvider';
  21. const DEFAULT_AGGREGATE_FLAMEGRAPH_PREFERENCES: DeepPartial<FlamegraphState> = {
  22. preferences: {
  23. sorting: 'alphabetical',
  24. view: 'bottom up',
  25. },
  26. };
  27. class EmptyFlamegraphException extends Error {}
  28. export function AggregateFlamegraphPanel({transaction}: {transaction: string}) {
  29. const {selection} = usePageFilters();
  30. const [hideSystemFrames, setHideSystemFrames] = useLocalStorageState(
  31. 'profiling-flamegraph-collapsed-frames',
  32. true
  33. );
  34. const {data, isLoading, isError} = useAggregateFlamegraphQuery({
  35. transaction,
  36. environments: selection.environments,
  37. projects: selection.projects,
  38. datetime: selection.datetime,
  39. });
  40. const isEmpty = data?.shared.frames.length === 0;
  41. useEffect(() => {
  42. if (isLoading || isError || data.shared.frames.length > 0) {
  43. return;
  44. }
  45. Sentry.captureException(new EmptyFlamegraphException('Empty aggregate flamegraph'));
  46. }, [data, isLoading, isError]);
  47. return (
  48. <Flex column gap={space(1)}>
  49. <Flex align="center" gap={space(0.5)}>
  50. <HeaderTitle>{t('Aggregate Flamegraph')}</HeaderTitle>
  51. <QuestionTooltip
  52. size="sm"
  53. position="right"
  54. isHoverable
  55. title={
  56. <TooltipContent>
  57. <p>{t('An aggregate of profiles for this transaction.')}</p>
  58. <p>
  59. {t(
  60. 'Navigate the aggregate flamegraph by scrolling and by double clicking a frame to zoom.'
  61. )}
  62. </p>
  63. </TooltipContent>
  64. }
  65. />
  66. </Flex>
  67. <ProfileGroupProvider
  68. type="flamegraph"
  69. input={data ?? null}
  70. traceID=""
  71. frameFilter={hideSystemFrames ? applicationFrameOnly : undefined}
  72. >
  73. <FlamegraphStateProvider initialState={DEFAULT_AGGREGATE_FLAMEGRAPH_PREFERENCES}>
  74. <FlamegraphThemeProvider>
  75. <Panel>
  76. <Flex h={400} column justify="center">
  77. {isLoading ? (
  78. <LoadingIndicator>{t('Loading Aggregate Flamegraph')}</LoadingIndicator>
  79. ) : isEmpty ? (
  80. <EmptyStateWarning>
  81. <p>{t(`Aggregate flamegraph isn't available for your query`)}</p>
  82. </EmptyStateWarning>
  83. ) : (
  84. <DeprecatedAggregateFlamegraph
  85. hideSystemFrames={hideSystemFrames}
  86. setHideSystemFrames={setHideSystemFrames}
  87. />
  88. )}
  89. </Flex>
  90. </Panel>
  91. </FlamegraphThemeProvider>
  92. </FlamegraphStateProvider>
  93. </ProfileGroupProvider>
  94. </Flex>
  95. );
  96. }
  97. function applicationFrameOnly(frame: Frame): boolean {
  98. return frame.is_application;
  99. }
  100. export const HeaderTitle = styled('span')`
  101. ${p => p.theme.text.cardTitle};
  102. color: ${p => p.theme.headingColor};
  103. font-size: ${p => p.theme.fontSizeMedium};
  104. `;
  105. export const TooltipContent = styled('div')`
  106. & p {
  107. text-align: left;
  108. }
  109. & p:last-child {
  110. margin-bottom: 0;
  111. }
  112. `;