traceAnalytics.tsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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 type {TraceDrawerActionKind} from './traceDrawer/details/utils';
  7. import {TraceShape, type TraceTree} from './traceModels/traceTree';
  8. const trackTraceMetadata = (
  9. tree: TraceTree,
  10. projects: Project[],
  11. organization: Organization,
  12. hasExceededPerformanceUsageLimit: boolean | null
  13. ) => {
  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 trackLayoutChange = (layout: string, organization: Organization) =>
  38. trackAnalytics('trace.trace_layout.change', {
  39. layout,
  40. organization,
  41. });
  42. const trackDrawerMinimize = (organization: Organization) =>
  43. trackAnalytics('trace.trace_layout.drawer_minimize', {
  44. organization,
  45. });
  46. const trackExploreSearch = (
  47. organization: Organization,
  48. key: string,
  49. value: string | number,
  50. kind: TraceDrawerActionKind
  51. ) =>
  52. trackAnalytics('trace.trace_drawer_explore_search', {
  53. organization,
  54. key,
  55. value,
  56. kind,
  57. });
  58. const trackShowInView = (organization: Organization) =>
  59. trackAnalytics('trace.trace_layout.show_in_view', {
  60. organization,
  61. });
  62. const trackViewEventJSON = (organization: Organization) =>
  63. trackAnalytics('trace.trace_layout.view_event_json', {
  64. organization,
  65. });
  66. const trackViewContinuousProfile = (organization: Organization) =>
  67. trackAnalytics('trace.trace_layout.view_continuous_profile', {
  68. organization,
  69. });
  70. const trackViewTransactionProfile = (organization: Organization) =>
  71. trackAnalytics('trace.trace_layout.view_transaction_profile', {
  72. organization,
  73. });
  74. const trackTabPin = (organization: Organization) =>
  75. trackAnalytics('trace.trace_layout.tab_pin', {
  76. organization,
  77. });
  78. const trackTabView = (tab: string, organization: Organization) =>
  79. trackAnalytics('trace.trace_layout.tab_view', {
  80. organization,
  81. tab,
  82. });
  83. const trackSearchFocus = (organization: Organization) =>
  84. trackAnalytics('trace.trace_layout.search_focus', {
  85. organization,
  86. });
  87. const trackResetZoom = (organization: Organization) =>
  88. trackAnalytics('trace.trace_layout.reset_zoom', {
  89. organization,
  90. });
  91. const trackPerformanceSetupChecklistTriggered = (organization: Organization) =>
  92. trackAnalytics('trace.quality.performance_setup.checklist_triggered', {
  93. organization,
  94. });
  95. const trackPerformanceSetupBannerLoaded = (organization: Organization) =>
  96. trackAnalytics('trace.quality.performance_setup.banner_loaded', {
  97. organization,
  98. });
  99. const trackQuotaExceededIncreaseBudgetClicked = (
  100. organization: Organization,
  101. traceType: string
  102. ) =>
  103. trackAnalytics('trace.quality.quota_exceeded.increase_budget_clicked', {
  104. organization,
  105. traceType,
  106. });
  107. const trackMissingSpansDocLinkClicked = (organization: Organization) =>
  108. trackAnalytics('trace.quality.missing_spans.doc_link_clicked', {
  109. organization,
  110. });
  111. const trackQuotaExceededLearnMoreClicked = (
  112. organization: Organization,
  113. traceType: string
  114. ) =>
  115. trackAnalytics('trace.quality.quota_exceeded.learn_more_clicked', {
  116. organization,
  117. traceType,
  118. });
  119. const trackQuotaExceededBannerLoaded = (organization: Organization, traceType: string) =>
  120. trackAnalytics('trace.quality.quota_exceeded.banner_loaded', {
  121. organization,
  122. traceType,
  123. });
  124. const trackPerformanceSetupLearnMoreClicked = (organization: Organization) =>
  125. trackAnalytics('trace.quality.performance_setup.learn_more_clicked', {
  126. organization,
  127. });
  128. const trackViewShortcuts = (organization: Organization) =>
  129. trackAnalytics('trace.trace_layout.view_shortcuts', {
  130. organization,
  131. });
  132. const trackTraceWarningType = (type: TraceShape, organization: Organization) =>
  133. trackAnalytics('trace.trace_warning_type', {
  134. organization,
  135. type,
  136. });
  137. const trackTraceConfigurationsDocsClicked = (organization: Organization, title: string) =>
  138. trackAnalytics('trace.configurations_docs_link_clicked', {
  139. organization,
  140. title,
  141. });
  142. const trackAutogroupingPreferenceChange = (
  143. organization: Organization,
  144. enabled: boolean
  145. ) =>
  146. trackAnalytics('trace.preferences.autogrouping_change', {
  147. organization,
  148. enabled,
  149. });
  150. const trackMissingInstrumentationPreferenceChange = (
  151. organization: Organization,
  152. enabled: boolean
  153. ) =>
  154. trackAnalytics('trace.preferences.missing_instrumentation_change', {
  155. organization,
  156. enabled,
  157. });
  158. function trackTraceShape(
  159. tree: TraceTree,
  160. projects: Project[],
  161. organization: Organization,
  162. hasExceededPerformanceUsageLimit: boolean | null
  163. ) {
  164. switch (tree.shape) {
  165. case TraceShape.BROKEN_SUBTRACES:
  166. case TraceShape.EMPTY_TRACE:
  167. case TraceShape.MULTIPLE_ROOTS:
  168. case TraceShape.ONE_ROOT:
  169. case TraceShape.NO_ROOT:
  170. case TraceShape.ONLY_ERRORS:
  171. case TraceShape.BROWSER_MULTIPLE_ROOTS:
  172. traceAnalytics.trackTraceMetadata(
  173. tree,
  174. projects,
  175. organization,
  176. hasExceededPerformanceUsageLimit
  177. );
  178. break;
  179. default: {
  180. Sentry.captureMessage('Unknown trace type');
  181. }
  182. }
  183. }
  184. const traceAnalytics = {
  185. // Trace shape
  186. trackTraceMetadata,
  187. trackTraceShape,
  188. // Drawer actions
  189. trackExploreSearch,
  190. trackShowInView,
  191. trackViewEventJSON,
  192. trackViewContinuousProfile,
  193. trackViewTransactionProfile,
  194. // Layout actions
  195. trackLayoutChange,
  196. trackDrawerMinimize,
  197. trackSearchFocus,
  198. trackTabPin,
  199. trackTabView,
  200. // Toolbar actions
  201. trackResetZoom,
  202. trackViewShortcuts,
  203. trackTraceWarningType,
  204. // Trace Quality Improvement
  205. trackPerformanceSetupChecklistTriggered,
  206. trackPerformanceSetupLearnMoreClicked,
  207. trackPerformanceSetupBannerLoaded,
  208. trackQuotaExceededIncreaseBudgetClicked,
  209. trackQuotaExceededLearnMoreClicked,
  210. trackQuotaExceededBannerLoaded,
  211. trackTraceConfigurationsDocsClicked,
  212. trackMissingSpansDocLinkClicked,
  213. // Trace Preferences
  214. trackAutogroupingPreferenceChange,
  215. trackMissingInstrumentationPreferenceChange,
  216. };
  217. export {traceAnalytics};