useLogReplayDataLoaded.tsx 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import {useEffect} from 'react';
  2. import {trackAnalytics} from 'sentry/utils/analytics';
  3. import type useLoadReplayReader from 'sentry/utils/replays/hooks/useLoadReplayReader';
  4. import type {BreadcrumbFrame} from 'sentry/utils/replays/types';
  5. import useOrganization from 'sentry/utils/useOrganization';
  6. import useProjectFromSlug from 'sentry/utils/useProjectFromSlug';
  7. interface Props
  8. extends Pick<
  9. ReturnType<typeof useLoadReplayReader>,
  10. 'fetchError' | 'fetching' | 'projectSlug' | 'replay'
  11. > {}
  12. function useLogReplayDataLoaded({fetchError, fetching, projectSlug, replay}: Props) {
  13. const organization = useOrganization();
  14. const project = useProjectFromSlug({
  15. organization,
  16. projectSlug: projectSlug ?? undefined,
  17. });
  18. useEffect(() => {
  19. if (fetching || fetchError || !replay || !project || replay.getReplay().is_archived) {
  20. return;
  21. }
  22. const replayRecord = replay.getReplay();
  23. const allErrors = replay.getErrorFrames();
  24. // BUG(replay): This will often report the discrepancy between errors
  25. // accociated with the replay, and errors the replay knows about.
  26. // ie: When an error is filtered server-side, it would count as a replay with 1
  27. // backend error.
  28. const feErrorIds = replayRecord.error_ids || [];
  29. const beErrorCount = allErrors.filter(
  30. error => !feErrorIds.includes(error.data.eventId)
  31. ).length;
  32. trackAnalytics('replay.details-data-loaded', {
  33. organization,
  34. be_errors: beErrorCount,
  35. fe_errors: feErrorIds.length,
  36. project_platform: project.platform!,
  37. replay_errors: 0,
  38. total_errors: allErrors.length,
  39. started_at_delta: replay.timestampDeltas.startedAtDelta,
  40. finished_at_delta: replay.timestampDeltas.finishedAtDelta,
  41. replay_id: replayRecord.id,
  42. });
  43. const hydrationErrorFrames = replay
  44. .getChapterFrames()
  45. .filter(frame => (frame as BreadcrumbFrame)?.category === 'replay.hydrate-error');
  46. if (hydrationErrorFrames.length > 0) {
  47. // Track when a hydration breadcrumb is present but unable to be viewed
  48. trackAnalytics('replay.details-has-hydration-error', {
  49. organization,
  50. num_errors: hydrationErrorFrames.length,
  51. replay_id: replayRecord.id,
  52. });
  53. }
  54. }, [organization, project, fetchError, fetching, projectSlug, replay]);
  55. }
  56. export default useLogReplayDataLoaded;