flamegraphProvider.tsx 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import {createContext, useContext, useMemo} from 'react';
  2. import * as Sentry from '@sentry/react';
  3. import {Flamegraph} from 'sentry/utils/profiling/flamegraph';
  4. import {useFlamegraphPreferences} from 'sentry/utils/profiling/flamegraph/hooks/useFlamegraphPreferences';
  5. import {useFlamegraphProfiles} from 'sentry/utils/profiling/flamegraph/hooks/useFlamegraphProfiles';
  6. import {useProfileGroup} from 'sentry/views/profiling/profileGroupProvider';
  7. const LOADING_OR_FALLBACK_FLAMEGRAPH = Flamegraph.Empty();
  8. const FlamegraphContext = createContext<Flamegraph | null>(null);
  9. export const useFlamegraph = () => {
  10. const context = useContext(FlamegraphContext);
  11. if (!context) {
  12. throw new Error('useFlamegraph was called outside of FlamegraphProvider');
  13. }
  14. return context;
  15. };
  16. interface FlamegraphProviderProps {
  17. children: React.ReactNode;
  18. }
  19. export function FlamegraphProvider(props: FlamegraphProviderProps) {
  20. const profileGroup = useProfileGroup();
  21. const {threadId} = useFlamegraphProfiles();
  22. const {sorting, view} = useFlamegraphPreferences();
  23. const activeProfile = useMemo(() => {
  24. return profileGroup.profiles.find(p => p.threadId === threadId);
  25. }, [profileGroup, threadId]);
  26. const flamegraph = useMemo(() => {
  27. if (typeof threadId !== 'number') {
  28. return LOADING_OR_FALLBACK_FLAMEGRAPH;
  29. }
  30. // This could happen if threadId was initialized from query string, but for some
  31. // reason the profile was removed from the list of profiles.
  32. if (!activeProfile) {
  33. return LOADING_OR_FALLBACK_FLAMEGRAPH;
  34. }
  35. const transaction = Sentry.startTransaction({
  36. op: 'import',
  37. name: 'flamegraph.constructor',
  38. });
  39. transaction.setTag('sorting', sorting.split(' ').join('_'));
  40. transaction.setTag('view', view.split(' ').join('_'));
  41. const newFlamegraph = new Flamegraph(activeProfile, threadId, {
  42. inverted: view === 'bottom up',
  43. sort: sorting,
  44. configSpace: undefined,
  45. });
  46. transaction.finish();
  47. return newFlamegraph;
  48. }, [activeProfile, sorting, threadId, view]);
  49. return (
  50. <FlamegraphContext.Provider value={flamegraph}>
  51. {props.children}
  52. </FlamegraphContext.Provider>
  53. );
  54. }