traceAnalytics.tsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import * as Sentry from '@sentry/react';
  2. import * as qs from 'query-string';
  3. import type {Organization} from 'sentry/types/organization';
  4. import type {Project} from 'sentry/types/project';
  5. import {trackAnalytics} from 'sentry/utils/analytics';
  6. import {TraceShape, type TraceTree} from './traceModels/traceTree';
  7. const trackTraceMetadata = (
  8. tree: TraceTree,
  9. projects: Project[],
  10. organization: Organization,
  11. hasExceededPerformanceUsageLimit: boolean | null
  12. ) => {
  13. Sentry.metrics.increment(`trace.trace_shape.${tree.shape}`);
  14. // space[1] represents the node duration (in milliseconds)
  15. const trace_duration_seconds = (tree.root.space?.[1] ?? 0) / 1000;
  16. const projectSlugs = [
  17. ...new Set(
  18. tree.list.map(node => node.metadata.project_slug).filter(slug => slug !== undefined)
  19. ),
  20. ];
  21. const projectPlatforms = projects
  22. .filter(p => projectSlugs.includes(p.slug))
  23. .map(project => project?.platform ?? '');
  24. const query = qs.parse(location.search);
  25. trackAnalytics('trace.metadata', {
  26. shape: tree.shape,
  27. // round trace_duration_seconds to nearest two decimal places
  28. trace_duration_seconds: Math.round(trace_duration_seconds * 100) / 100,
  29. has_exceeded_performance_usage_limit: hasExceededPerformanceUsageLimit,
  30. referrer: query.source?.toString() || null,
  31. num_root_children: tree.root.children.length,
  32. num_nodes: tree.list.length,
  33. project_platforms: projectPlatforms,
  34. organization,
  35. });
  36. };
  37. const trackFailedToFetchTraceState = () =>
  38. Sentry.metrics.increment('trace.failed_to_fetch_trace');
  39. const trackEmptyTraceState = () => Sentry.metrics.increment('trace.empty_trace');
  40. const trackLayoutChange = (layout: string, organization: Organization) =>
  41. trackAnalytics('trace.trace_layout.change', {
  42. layout,
  43. organization,
  44. });
  45. const trackDrawerMinimize = (organization: Organization) =>
  46. trackAnalytics('trace.trace_layout.drawer_minimize', {
  47. organization,
  48. });
  49. const trackShowInView = (organization: Organization) =>
  50. trackAnalytics('trace.trace_layout.show_in_view', {
  51. organization,
  52. });
  53. const trackViewEventJSON = (organization: Organization) =>
  54. trackAnalytics('trace.trace_layout.view_event_json', {
  55. organization,
  56. });
  57. const trackViewContinuousProfile = (organization: Organization) =>
  58. trackAnalytics('trace.trace_layout.view_continuous_profile', {
  59. organization,
  60. });
  61. const trackViewTransactionProfile = (organization: Organization) =>
  62. trackAnalytics('trace.trace_layout.view_transaction_profile', {
  63. organization,
  64. });
  65. const trackTabPin = (organization: Organization) =>
  66. trackAnalytics('trace.trace_layout.tab_pin', {
  67. organization,
  68. });
  69. const trackTabView = (tab: string, organization: Organization) =>
  70. trackAnalytics('trace.trace_layout.tab_view', {
  71. organization,
  72. tab,
  73. });
  74. const trackSearchFocus = (organization: Organization) =>
  75. trackAnalytics('trace.trace_layout.search_focus', {
  76. organization,
  77. });
  78. const trackResetZoom = (organization: Organization) =>
  79. trackAnalytics('trace.trace_layout.reset_zoom', {
  80. organization,
  81. });
  82. const trackPerformanceSetupChecklistTriggered = (organization: Organization) =>
  83. trackAnalytics('trace.quality.performance_setup.checklist_triggered', {
  84. organization,
  85. });
  86. const trackPerformanceSetupBannerLoaded = (organization: Organization) =>
  87. trackAnalytics('trace.quality.performance_setup.banner_loaded', {
  88. organization,
  89. });
  90. const trackQuotaExceededIncreaseBudgetClicked = (
  91. organization: Organization,
  92. traceType: string
  93. ) =>
  94. trackAnalytics('trace.quality.quota_exceeded.increase_budget_clicked', {
  95. organization,
  96. traceType,
  97. });
  98. const trackMissingSpansDocLinkClicked = (organization: Organization) =>
  99. trackAnalytics('trace.quality.missing_spans.doc_link_clicked', {
  100. organization,
  101. });
  102. const trackQuotaExceededLearnMoreClicked = (
  103. organization: Organization,
  104. traceType: string
  105. ) =>
  106. trackAnalytics('trace.quality.quota_exceeded.learn_more_clicked', {
  107. organization,
  108. traceType,
  109. });
  110. const trackQuotaExceededBannerLoaded = (organization: Organization, traceType: string) =>
  111. trackAnalytics('trace.quality.quota_exceeded.banner_loaded', {
  112. organization,
  113. traceType,
  114. });
  115. const trackPerformanceSetupLearnMoreClicked = (organization: Organization) =>
  116. trackAnalytics('trace.quality.performance_setup.learn_more_clicked', {
  117. organization,
  118. });
  119. const trackViewShortcuts = (organization: Organization) =>
  120. trackAnalytics('trace.trace_layout.view_shortcuts', {
  121. organization,
  122. });
  123. const trackTraceWarningType = (type: TraceShape, organization: Organization) =>
  124. trackAnalytics('trace.trace_warning_type', {
  125. organization,
  126. type,
  127. });
  128. const trackTraceConfigurationsDocsClicked = (organization: Organization, title: string) =>
  129. trackAnalytics('trace.configurations_docs_link_clicked', {
  130. organization,
  131. title,
  132. });
  133. const trackAutogroupingPreferenceChange = (
  134. organization: Organization,
  135. enabled: boolean
  136. ) =>
  137. trackAnalytics('trace.preferences.autogrouping_change', {
  138. organization,
  139. enabled,
  140. });
  141. const trackMissingInstrumentationPreferenceChange = (
  142. organization: Organization,
  143. enabled: boolean
  144. ) =>
  145. trackAnalytics('trace.preferences.missing_instrumentation_change', {
  146. organization,
  147. enabled,
  148. });
  149. function trackTraceShape(
  150. tree: TraceTree,
  151. projects: Project[],
  152. organization: Organization,
  153. hasExceededPerformanceUsageLimit: boolean | null
  154. ) {
  155. switch (tree.shape) {
  156. case TraceShape.BROKEN_SUBTRACES:
  157. case TraceShape.EMPTY_TRACE:
  158. case TraceShape.MULTIPLE_ROOTS:
  159. case TraceShape.ONE_ROOT:
  160. case TraceShape.NO_ROOT:
  161. case TraceShape.ONLY_ERRORS:
  162. case TraceShape.BROWSER_MULTIPLE_ROOTS:
  163. traceAnalytics.trackTraceMetadata(
  164. tree,
  165. projects,
  166. organization,
  167. hasExceededPerformanceUsageLimit
  168. );
  169. break;
  170. default: {
  171. Sentry.captureMessage('Unknown trace type');
  172. }
  173. }
  174. }
  175. const traceAnalytics = {
  176. // Trace shape
  177. trackTraceMetadata,
  178. trackTraceShape,
  179. trackEmptyTraceState,
  180. trackFailedToFetchTraceState,
  181. // Drawer actions
  182. trackShowInView,
  183. trackViewEventJSON,
  184. trackViewContinuousProfile,
  185. trackViewTransactionProfile,
  186. // Layout actions
  187. trackLayoutChange,
  188. trackDrawerMinimize,
  189. trackSearchFocus,
  190. trackTabPin,
  191. trackTabView,
  192. // Toolbar actions
  193. trackResetZoom,
  194. trackViewShortcuts,
  195. trackTraceWarningType,
  196. // Trace Quality Improvement
  197. trackPerformanceSetupChecklistTriggered,
  198. trackPerformanceSetupLearnMoreClicked,
  199. trackPerformanceSetupBannerLoaded,
  200. trackQuotaExceededIncreaseBudgetClicked,
  201. trackQuotaExceededLearnMoreClicked,
  202. trackQuotaExceededBannerLoaded,
  203. trackTraceConfigurationsDocsClicked,
  204. trackMissingSpansDocLinkClicked,
  205. // Trace Preferences
  206. trackAutogroupingPreferenceChange,
  207. trackMissingInstrumentationPreferenceChange,
  208. };
  209. export {traceAnalytics};