traceAnalytics.tsx 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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 {PlatformKey, 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. export type TraceWaterFallSource = 'trace_view' | 'replay_details' | 'issue_details';
  9. const trackTraceMetadata = (
  10. tree: TraceTree,
  11. projects: Project[],
  12. organization: Organization,
  13. hasExceededPerformanceUsageLimit: boolean | null,
  14. source: TraceWaterFallSource
  15. ) => {
  16. // space[1] represents the node duration (in milliseconds)
  17. const trace_duration_seconds = (tree.root.space?.[1] ?? 0) / 1000;
  18. const projectSlugs = [
  19. ...new Set(
  20. tree.list.map(node => node.metadata.project_slug).filter(slug => slug !== undefined)
  21. ),
  22. ];
  23. const projectPlatforms = projects
  24. .filter(p => projectSlugs.includes(p.slug))
  25. .map(project => project?.platform ?? '');
  26. const query = qs.parse(location.search);
  27. trackAnalytics('trace.metadata', {
  28. shape: tree.shape,
  29. // round trace_duration_seconds to nearest two decimal places
  30. trace_duration_seconds: Math.round(trace_duration_seconds * 100) / 100,
  31. has_exceeded_performance_usage_limit: hasExceededPerformanceUsageLimit,
  32. referrer: query.source?.toString() || null,
  33. num_root_children: tree.root.children.length,
  34. num_nodes: tree.list.length,
  35. project_platforms: projectPlatforms,
  36. organization,
  37. source,
  38. });
  39. };
  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 trackExploreSearch = (
  50. organization: Organization,
  51. key: string,
  52. value: string | number,
  53. kind: TraceDrawerActionKind,
  54. source: 'drawer' | 'toolbar_menu'
  55. ) =>
  56. trackAnalytics('trace.trace_drawer_explore_search', {
  57. organization,
  58. key,
  59. value,
  60. kind,
  61. source,
  62. });
  63. const trackShowInView = (organization: Organization) =>
  64. trackAnalytics('trace.trace_layout.show_in_view', {
  65. organization,
  66. });
  67. const trackTracingOnboarding = (
  68. organization: Organization,
  69. platform: PlatformKey,
  70. supports_performance: boolean,
  71. supports_onboarding_checklist: boolean
  72. ) =>
  73. trackAnalytics('trace.tracing_onboarding', {
  74. organization,
  75. platform,
  76. supports_performance,
  77. supports_onboarding_checklist,
  78. });
  79. const trackPlatformDocsViewed = (organization: Organization, platform: string) =>
  80. trackAnalytics('trace.tracing_onboarding_platform_docs_viewed', {
  81. organization,
  82. platform,
  83. });
  84. const trackPerformanceSetupDocsViewed = (organization: Organization, platform: string) =>
  85. trackAnalytics('trace.tracing_onboarding_performance_docs_viewed', {
  86. organization,
  87. platform,
  88. });
  89. const trackViewEventJSON = (organization: Organization) =>
  90. trackAnalytics('trace.trace_layout.view_event_json', {
  91. organization,
  92. });
  93. const trackViewContinuousProfile = (organization: Organization) =>
  94. trackAnalytics('trace.trace_layout.view_continuous_profile', {
  95. organization,
  96. });
  97. const trackViewTransactionProfile = (organization: Organization) =>
  98. trackAnalytics('trace.trace_layout.view_transaction_profile', {
  99. organization,
  100. });
  101. const trackTabPin = (organization: Organization) =>
  102. trackAnalytics('trace.trace_layout.tab_pin', {
  103. organization,
  104. });
  105. const trackTabView = (tab: string, organization: Organization) =>
  106. trackAnalytics('trace.trace_layout.tab_view', {
  107. organization,
  108. tab,
  109. });
  110. const trackSearchFocus = (organization: Organization) =>
  111. trackAnalytics('trace.trace_layout.search_focus', {
  112. organization,
  113. });
  114. const trackResetZoom = (organization: Organization) =>
  115. trackAnalytics('trace.trace_layout.reset_zoom', {
  116. organization,
  117. });
  118. const trackPerformanceSetupChecklistTriggered = (organization: Organization) =>
  119. trackAnalytics('trace.quality.performance_setup.checklist_triggered', {
  120. organization,
  121. });
  122. const trackPerformanceSetupBannerLoaded = (organization: Organization) =>
  123. trackAnalytics('trace.quality.performance_setup.banner_loaded', {
  124. organization,
  125. });
  126. const trackQuotaExceededIncreaseBudgetClicked = (
  127. organization: Organization,
  128. traceType: string
  129. ) =>
  130. trackAnalytics('trace.quality.quota_exceeded.increase_budget_clicked', {
  131. organization,
  132. traceType,
  133. });
  134. const trackMissingSpansDocLinkClicked = (organization: Organization) =>
  135. trackAnalytics('trace.quality.missing_spans.doc_link_clicked', {
  136. organization,
  137. });
  138. const trackTraceEmptyState = (organization: Organization, source: TraceWaterFallSource) =>
  139. trackAnalytics('trace.load.empty_state', {
  140. organization,
  141. source,
  142. });
  143. const trackTraceErrorState = (organization: Organization, source: TraceWaterFallSource) =>
  144. trackAnalytics('trace.load.error_state', {
  145. organization,
  146. source,
  147. });
  148. const trackQuotaExceededLearnMoreClicked = (
  149. organization: Organization,
  150. traceType: string
  151. ) =>
  152. trackAnalytics('trace.quality.quota_exceeded.learn_more_clicked', {
  153. organization,
  154. traceType,
  155. });
  156. const trackQuotaExceededBannerLoaded = (organization: Organization, traceType: string) =>
  157. trackAnalytics('trace.quality.quota_exceeded.banner_loaded', {
  158. organization,
  159. traceType,
  160. });
  161. const trackPerformanceSetupLearnMoreClicked = (organization: Organization) =>
  162. trackAnalytics('trace.quality.performance_setup.learn_more_clicked', {
  163. organization,
  164. });
  165. const trackViewShortcuts = (organization: Organization) =>
  166. trackAnalytics('trace.trace_layout.view_shortcuts', {
  167. organization,
  168. });
  169. const trackTraceWarningType = (type: TraceShape, organization: Organization) =>
  170. trackAnalytics('trace.trace_warning_type', {
  171. organization,
  172. type,
  173. });
  174. const trackTraceConfigurationsDocsClicked = (organization: Organization, title: string) =>
  175. trackAnalytics('trace.configurations_docs_link_clicked', {
  176. organization,
  177. title,
  178. });
  179. const trackAutogroupingPreferenceChange = (
  180. organization: Organization,
  181. enabled: boolean
  182. ) =>
  183. trackAnalytics('trace.preferences.autogrouping_change', {
  184. organization,
  185. enabled,
  186. });
  187. const trackMissingInstrumentationPreferenceChange = (
  188. organization: Organization,
  189. enabled: boolean
  190. ) =>
  191. trackAnalytics('trace.preferences.missing_instrumentation_change', {
  192. organization,
  193. enabled,
  194. });
  195. function trackTraceShape(
  196. tree: TraceTree,
  197. projects: Project[],
  198. organization: Organization,
  199. hasExceededPerformanceUsageLimit: boolean | null,
  200. source: TraceWaterFallSource
  201. ) {
  202. switch (tree.shape) {
  203. case TraceShape.BROKEN_SUBTRACES:
  204. case TraceShape.EMPTY_TRACE:
  205. case TraceShape.MULTIPLE_ROOTS:
  206. case TraceShape.ONE_ROOT:
  207. case TraceShape.NO_ROOT:
  208. case TraceShape.ONLY_ERRORS:
  209. case TraceShape.BROWSER_MULTIPLE_ROOTS:
  210. traceAnalytics.trackTraceMetadata(
  211. tree,
  212. projects,
  213. organization,
  214. hasExceededPerformanceUsageLimit,
  215. source
  216. );
  217. break;
  218. default: {
  219. Sentry.captureMessage('Unknown trace type');
  220. }
  221. }
  222. }
  223. const traceAnalytics = {
  224. // Trace Onboarding
  225. trackTracingOnboarding,
  226. trackPlatformDocsViewed,
  227. trackPerformanceSetupDocsViewed,
  228. // Trace shape
  229. trackTraceMetadata,
  230. trackTraceShape,
  231. trackTraceEmptyState,
  232. trackTraceErrorState,
  233. // Drawer actions
  234. trackExploreSearch,
  235. trackShowInView,
  236. trackViewEventJSON,
  237. trackViewContinuousProfile,
  238. trackViewTransactionProfile,
  239. // Layout actions
  240. trackLayoutChange,
  241. trackDrawerMinimize,
  242. trackSearchFocus,
  243. trackTabPin,
  244. trackTabView,
  245. // Toolbar actions
  246. trackResetZoom,
  247. trackViewShortcuts,
  248. trackTraceWarningType,
  249. // Trace Quality Improvement
  250. trackPerformanceSetupChecklistTriggered,
  251. trackPerformanceSetupLearnMoreClicked,
  252. trackPerformanceSetupBannerLoaded,
  253. trackQuotaExceededIncreaseBudgetClicked,
  254. trackQuotaExceededLearnMoreClicked,
  255. trackQuotaExceededBannerLoaded,
  256. trackTraceConfigurationsDocsClicked,
  257. trackMissingSpansDocLinkClicked,
  258. // Trace Preferences
  259. trackAutogroupingPreferenceChange,
  260. trackMissingInstrumentationPreferenceChange,
  261. };
  262. export {traceAnalytics};