Browse Source

feat(insights): add analytics to insight sample panels (#70822)

Continuation of https://github.com/getsentry/sentry/pull/70769. Adds
analytics to the span sample panel to track:
- How often the panels are opened
- How often spans are clicked
- How often “Try different samples” is clicked
- How often specific filters are interacted with

Modules to add analytics to:
- [x] HTTP
- [x] Database
- [x] Cache
- [x] Queues
- [x] Screen Loads
- [x] App Starts
- [x] Resources

Note: Web Vitals does not have a sample panel

---------

Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
Kevin Liu 10 months ago
parent
commit
7fbe058bc1

+ 14 - 1
static/app/views/performance/browser/resources/resourceSummaryPage/resourceSummaryTable.tsx

@@ -9,8 +9,10 @@ import type {CursorHandler} from 'sentry/components/pagination';
 import Pagination from 'sentry/components/pagination';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
+import {trackAnalytics} from 'sentry/utils/analytics';
 import {decodeScalar} from 'sentry/utils/queryString';
 import {useLocation} from 'sentry/utils/useLocation';
+import useOrganization from 'sentry/utils/useOrganization';
 import {useParams} from 'sentry/utils/useParams';
 import {RESOURCE_THROUGHPUT_UNIT} from 'sentry/views/performance/browser/resources';
 import {useResourceModuleFilters} from 'sentry/views/performance/browser/resources/utils/useResourceFilters';
@@ -22,7 +24,11 @@ import {renderHeadCell} from 'sentry/views/starfish/components/tableCells/render
 import ResourceSizeCell from 'sentry/views/starfish/components/tableCells/resourceSizeCell';
 import {WiderHovercard} from 'sentry/views/starfish/components/tableCells/spanDescriptionCell';
 import {ThroughputCell} from 'sentry/views/starfish/components/tableCells/throughputCell';
-import {SpanIndexedField, SpanMetricsField} from 'sentry/views/starfish/types';
+import {
+  ModuleName,
+  SpanIndexedField,
+  SpanMetricsField,
+} from 'sentry/views/starfish/types';
 import {QueryParameterNames} from 'sentry/views/starfish/views/queryParameters';
 import {DataTitles, getThroughputTitle} from 'sentry/views/starfish/views/spans/types';
 
@@ -44,6 +50,7 @@ type Row = {
 type Column = GridColumnHeader<keyof Row>;
 
 function ResourceSummaryTable() {
+  const organization = useOrganization();
   const location = useLocation();
   const {groupId} = useParams();
   const sort = useResourceSummarySort();
@@ -99,6 +106,12 @@ function ResourceSummaryTable() {
 
       const link = (
         <Link
+          onClick={() =>
+            trackAnalytics('performance_views.sample_spans.opened', {
+              organization,
+              source: ModuleName.RESOURCE,
+            })
+          }
           to={{
             pathname: location.pathname,
             query: {

+ 13 - 1
static/app/views/performance/cache/samplePanel/samplePanel.tsx

@@ -8,6 +8,7 @@ import {Button} from 'sentry/components/button';
 import Link from 'sentry/components/links/link';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
+import {trackAnalytics} from 'sentry/utils/analytics';
 import {DurationUnit, RateUnit, SizeUnit} from 'sentry/utils/discover/fields';
 import {PageAlertProvider} from 'sentry/utils/performance/contexts/pageAlert';
 import {decodeScalar} from 'sentry/utils/queryString';
@@ -34,6 +35,7 @@ import {useTransactions} from 'sentry/views/starfish/queries/useTransactions';
 import {
   MetricsFields,
   type MetricsQueryFilters,
+  ModuleName,
   SpanFunction,
   SpanIndexedField,
   type SpanIndexedQueryFilters,
@@ -346,7 +348,17 @@ export function CacheSamplePanel() {
 
           <Fragment>
             <ModuleLayout.Full>
-              <Button onClick={handleRefetch}>{t('Try Different Samples')}</Button>
+              <Button
+                onClick={() => {
+                  trackAnalytics(
+                    'performance_views.sample_spans.try_different_samples_clicked',
+                    {organization, source: ModuleName.CACHE}
+                  );
+                  handleRefetch();
+                }}
+              >
+                {t('Try Different Samples')}
+              </Button>
             </ModuleLayout.Full>
           </Fragment>
         </ModuleLayout.Layout>

+ 2 - 1
static/app/views/performance/cache/tables/spanSamplesTable.tsx

@@ -16,7 +16,7 @@ import {CacheHitMissCell} from 'sentry/views/performance/cache/tables/cacheHitMi
 import {renderHeadCell} from 'sentry/views/starfish/components/tableCells/renderHeadCell';
 import {SpanIdCell} from 'sentry/views/starfish/components/tableCells/spanIdCell';
 import type {IndexedResponse} from 'sentry/views/starfish/types';
-import {SpanIndexedField} from 'sentry/views/starfish/types';
+import {ModuleName, SpanIndexedField} from 'sentry/views/starfish/types';
 
 type DataRowKeys =
   | SpanIndexedField.PROJECT
@@ -126,6 +126,7 @@ function renderBodyCell(
   if (column.key === SpanIndexedField.ID) {
     return (
       <SpanIdCell
+        moduleName={ModuleName.CACHE}
         projectSlug={row.project}
         traceId={row.trace}
         timestamp={row.timestamp}

+ 15 - 1
static/app/views/performance/cache/tables/transactionCell.tsx

@@ -1,9 +1,12 @@
 import * as qs from 'query-string';
 
 import Link from 'sentry/components/links/link';
+import {trackAnalytics} from 'sentry/utils/analytics';
 import {useLocation} from 'sentry/utils/useLocation';
+import useOrganization from 'sentry/utils/useOrganization';
 import {useCacheUrl} from 'sentry/views/performance/cache/utils';
 import {OverflowEllipsisTextContainer} from 'sentry/views/starfish/components/textAlign';
+import {ModuleName} from 'sentry/views/starfish/types';
 
 interface Props {
   project?: string;
@@ -12,6 +15,7 @@ interface Props {
 }
 
 export function TransactionCell({project, transaction}: Props) {
+  const organization = useOrganization();
   const location = useLocation();
   const cacheUrl = useCacheUrl();
 
@@ -27,7 +31,17 @@ export function TransactionCell({project, transaction}: Props) {
 
   return (
     <OverflowEllipsisTextContainer>
-      <Link to={`${cacheUrl}/?${qs.stringify(query)}`}>{transaction}</Link>
+      <Link
+        onClick={() =>
+          trackAnalytics('performance_views.sample_spans.opened', {
+            organization,
+            source: ModuleName.CACHE,
+          })
+        }
+        to={`${cacheUrl}/?${qs.stringify(query)}`}
+      >
+        {transaction}
+      </Link>
     </OverflowEllipsisTextContainer>
   );
 }

+ 32 - 2
static/app/views/performance/http/httpSamplesPanel.tsx

@@ -9,6 +9,7 @@ import Link from 'sentry/components/links/link';
 import {SegmentedControl} from 'sentry/components/segmentedControl';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
+import {trackAnalytics} from 'sentry/utils/analytics';
 import {DurationUnit, RateUnit} from 'sentry/utils/discover/fields';
 import {PageAlertProvider} from 'sentry/utils/performance/contexts/pageAlert';
 import {decodeScalar} from 'sentry/utils/queryString';
@@ -44,6 +45,7 @@ import {useSpanMetricsSeries} from 'sentry/views/starfish/queries/useDiscoverSer
 import {useIndexedSpans} from 'sentry/views/starfish/queries/useIndexedSpans';
 import {useSpanMetricsTopNSeries} from 'sentry/views/starfish/queries/useSpanMetricsTopNSeries';
 import {
+  ModuleName,
   SpanFunction,
   SpanIndexedField,
   SpanMetricsField,
@@ -86,6 +88,12 @@ export function HTTPSamplesPanel() {
     : undefined;
 
   const handlePanelChange = newPanelName => {
+    trackAnalytics('performance_views.sample_spans.filter_updated', {
+      filter: 'panel',
+      new_state: newPanelName,
+      organization,
+      source: ModuleName.HTTP,
+    });
     router.replace({
       pathname: location.pathname,
       query: {
@@ -96,6 +104,12 @@ export function HTTPSamplesPanel() {
   };
 
   const handleResponseCodeClassChange = newResponseCodeClass => {
+    trackAnalytics('performance_views.sample_spans.filter_updated', {
+      filter: 'status_code',
+      new_state: newResponseCodeClass.value,
+      organization,
+      source: ModuleName.HTTP,
+    });
     router.replace({
       pathname: location.pathname,
       query: {
@@ -435,7 +449,15 @@ export function HTTPSamplesPanel() {
               </ModuleLayout.Full>
 
               <ModuleLayout.Full>
-                <Button onClick={() => refetchDurationSpanSamples()}>
+                <Button
+                  onClick={() => {
+                    trackAnalytics(
+                      'performance_views.sample_spans.try_different_samples_clicked',
+                      {organization, source: ModuleName.HTTP}
+                    );
+                    refetchDurationSpanSamples();
+                  }}
+                >
                   {t('Try Different Samples')}
                 </Button>
               </ModuleLayout.Full>
@@ -468,7 +490,15 @@ export function HTTPSamplesPanel() {
               </ModuleLayout.Full>
 
               <ModuleLayout.Full>
-                <Button onClick={() => refetchResponseCodeSpanSamples()}>
+                <Button
+                  onClick={() => {
+                    trackAnalytics(
+                      'performance_views.sample_spans.try_different_samples_clicked',
+                      {organization, source: ModuleName.HTTP}
+                    );
+                    refetchResponseCodeSpanSamples();
+                  }}
+                >
                   {t('Try Different Samples')}
                 </Button>
               </ModuleLayout.Full>

+ 2 - 1
static/app/views/performance/http/tables/spanSamplesTable.tsx

@@ -15,7 +15,7 @@ import useOrganization from 'sentry/utils/useOrganization';
 import {renderHeadCell} from 'sentry/views/starfish/components/tableCells/renderHeadCell';
 import {SpanIdCell} from 'sentry/views/starfish/components/tableCells/spanIdCell';
 import type {IndexedResponse} from 'sentry/views/starfish/types';
-import {SpanIndexedField} from 'sentry/views/starfish/types';
+import {ModuleName, SpanIndexedField} from 'sentry/views/starfish/types';
 
 type DataRowKeys =
   | SpanIndexedField.PROJECT
@@ -110,6 +110,7 @@ function renderBodyCell(
   if (column.key === SpanIndexedField.ID) {
     return (
       <SpanIdCell
+        moduleName={ModuleName.HTTP}
         projectSlug={row.project}
         traceId={row.trace}
         timestamp={row.timestamp}

+ 13 - 1
static/app/views/performance/http/tables/transactionCell.tsx

@@ -1,10 +1,12 @@
 import * as qs from 'query-string';
 
 import Link from 'sentry/components/links/link';
+import {trackAnalytics} from 'sentry/utils/analytics';
 import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
 import {normalizeUrl} from 'sentry/utils/withDomainRequired';
 import {OverflowEllipsisTextContainer} from 'sentry/views/starfish/components/textAlign';
+import {ModuleName} from 'sentry/views/starfish/types';
 
 interface Props {
   domain?: string;
@@ -46,7 +48,17 @@ export function TransactionCell({
 
   return (
     <OverflowEllipsisTextContainer>
-      <Link to={`${pathname}?${qs.stringify(query)}`}>{label}</Link>
+      <Link
+        onClick={() =>
+          trackAnalytics('performance_views.sample_spans.opened', {
+            organization,
+            source: ModuleName.HTTP,
+          })
+        }
+        to={`${pathname}?${qs.stringify(query)}`}
+      >
+        {label}
+      </Link>
     </OverflowEllipsisTextContainer>
   );
 }

+ 1 - 1
static/app/views/performance/mobile/appStarts/screenSummary/index.tsx

@@ -193,7 +193,7 @@ export function ScreenSummary() {
                   ...(deviceClass ? {[SpanMetricsField.DEVICE_CLASS]: deviceClass} : {}),
                 }}
                 groupId={spanGroup}
-                moduleName={ModuleName.STARTUP}
+                moduleName={ModuleName.APP_START}
                 transactionName={transactionName}
                 spanDescription={spanDescription}
                 spanOp={spanOp}

+ 11 - 2
static/app/views/performance/mobile/appStarts/screenSummary/spanOperationTable.tsx

@@ -10,6 +10,7 @@ import type {CursorHandler} from 'sentry/components/pagination';
 import Pagination from 'sentry/components/pagination';
 import {t} from 'sentry/locale';
 import type {NewQuery} from 'sentry/types/organization';
+import {trackAnalytics} from 'sentry/utils/analytics';
 import {browserHistory} from 'sentry/utils/browserHistory';
 import type {TableDataRow} from 'sentry/utils/discover/discoverQuery';
 import type {MetaType} from 'sentry/utils/discover/eventView';
@@ -37,7 +38,7 @@ import {
 } from 'sentry/views/starfish/components/releaseSelector';
 import {PercentChangeCell} from 'sentry/views/starfish/components/tableCells/percentChangeCell';
 import {OverflowEllipsisTextContainer} from 'sentry/views/starfish/components/textAlign';
-import {SpanMetricsField} from 'sentry/views/starfish/types';
+import {ModuleName, SpanMetricsField} from 'sentry/views/starfish/types';
 import {STARFISH_CHART_INTERVAL_FIDELITY} from 'sentry/views/starfish/utils/constants';
 import {appendReleaseFilters} from 'sentry/views/starfish/utils/releaseComparison';
 import {QueryParameterNames} from 'sentry/views/starfish/views/queryParameters';
@@ -159,7 +160,15 @@ export function SpanOperationTable({
       };
 
       return (
-        <Link to={`${pathname}?${qs.stringify(query)}`}>
+        <Link
+          onClick={() =>
+            trackAnalytics('performance_views.sample_spans.opened', {
+              organization,
+              source: ModuleName.APP_START,
+            })
+          }
+          to={`${pathname}?${qs.stringify(query)}`}
+        >
           <OverflowEllipsisTextContainer>{label}</OverflowEllipsisTextContainer>
         </Link>
       );

+ 1 - 1
static/app/views/performance/mobile/screenload/screenLoadSpans/index.tsx

@@ -211,7 +211,7 @@ function ScreenLoadSpans() {
               {spanGroup && (
                 <SpanSamplesPanel
                   groupId={spanGroup}
-                  moduleName={ModuleName.SCREEN}
+                  moduleName={ModuleName.SCREEN_LOAD}
                   transactionName={transactionName}
                   spanDescription={spanDescription}
                   onClose={() => {

Some files were not shown because too many files changed in this diff