Skip to content

Commit f802790

Browse files
authored
fix(trace): track data quality from frontend (#69907)
Afaik we dont have tracking about the actual data quality that our users experience in its final state. This PR adds such tracking via amplitude and Sentry metrics
1 parent 1c39139 commit f802790

File tree

5 files changed

+68
-1
lines changed

5 files changed

+68
-1
lines changed

static/app/utils/analytics/tracingEventMap.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
export type TracingEventParameters = {
2+
'trace.shape': {
3+
shape: string;
4+
};
25
'trace.trace_layout.change': {
36
layout: string;
47
};
@@ -21,6 +24,7 @@ export type TracingEventParameters = {
2124
export type TracingEventKey = keyof TracingEventParameters;
2225

2326
export const tracingEventMap: Record<TracingEventKey, string | null> = {
27+
'trace.shape': 'Trace Shape',
2428
'trace.trace_layout.change': 'Changed Trace Layout',
2529
'trace.trace_layout.drawer_minimize': 'Minimized Trace Drawer',
2630
'trace.trace_layout.show_in_view': 'Clicked Show in View Action',

static/app/views/performance/newTraceDetails/index.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import {
5555
loadTraceViewPreferences,
5656
storeTraceViewPreferences,
5757
} from 'sentry/views/performance/newTraceDetails/traceState/tracePreferences';
58+
import {TraceType} from 'sentry/views/performance/traceDetails/newTraceDetailsContent';
5859

5960
import {useTrace} from './traceApi/useTrace';
6061
import {useTraceMeta} from './traceApi/useTraceMeta';
@@ -71,6 +72,22 @@ import {TraceReducer, type TraceReducerState} from './traceState';
7172
import {TraceUXChangeAlert} from './traceUXChangeBanner';
7273
import {useTraceQueryParamStateSync} from './useTraceQueryParamStateSync';
7374

75+
function logTraceType(type: TraceType, organization: Organization) {
76+
switch (type) {
77+
case TraceType.BROKEN_SUBTRACES:
78+
case TraceType.EMPTY_TRACE:
79+
case TraceType.MULTIPLE_ROOTS:
80+
case TraceType.ONE_ROOT:
81+
case TraceType.NO_ROOT:
82+
case TraceType.ONLY_ERRORS:
83+
traceAnalytics.trackTraceShape(type, organization);
84+
break;
85+
default: {
86+
Sentry.captureMessage('Unknown trace type');
87+
}
88+
}
89+
}
90+
7491
export function TraceView() {
7592
const params = useParams<{traceSlug?: string}>();
7693
const organization = useOrganization();
@@ -719,6 +736,17 @@ function TraceViewContent(props: TraceViewContentProps) {
719736

720737
const [traceGridRef, setTraceGridRef] = useState<HTMLElement | null>(null);
721738

739+
// Memoized because it requires tree traversal
740+
const shape = useMemo(() => tree.shape, [tree]);
741+
742+
useEffect(() => {
743+
if (tree.type !== 'trace') {
744+
return;
745+
}
746+
747+
logTraceType(shape, organization);
748+
}, [tree, shape, organization]);
749+
722750
return (
723751
<TraceExternalLayout>
724752
<TraceUXChangeAlert />
@@ -772,6 +800,7 @@ function TraceViewContent(props: TraceViewContentProps) {
772800
) : null}
773801

774802
<TraceDrawer
803+
traceType={shape}
775804
trace={tree}
776805
traceGridRef={traceGridRef}
777806
traces={props.trace}
@@ -934,6 +963,11 @@ function TraceLoading() {
934963
function TraceError() {
935964
const linkref = useRef<HTMLAnchorElement>(null);
936965
const feedback = useFeedbackWidget({buttonRef: linkref});
966+
967+
useEffect(() => {
968+
traceAnalytics.trackFailedToFetchTraceState();
969+
}, []);
970+
937971
return (
938972
<LoadingContainer animate error>
939973
<div>{t('Ughhhhh, we failed to load your trace...')}</div>
@@ -956,6 +990,11 @@ function TraceError() {
956990
function TraceEmpty() {
957991
const linkref = useRef<HTMLAnchorElement>(null);
958992
const feedback = useFeedbackWidget({buttonRef: linkref});
993+
994+
useEffect(() => {
995+
traceAnalytics.trackEmptyTraceState();
996+
}, []);
997+
959998
return (
960999
<LoadingContainer animate>
9611000
<div>{t('This trace does not contain any data?!')}</div>

static/app/views/performance/newTraceDetails/traceAnalytics.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
1+
import * as Sentry from '@sentry/react';
2+
13
import type {Organization} from 'sentry/types/organization';
24
import {trackAnalytics} from 'sentry/utils/analytics';
35
import type {TraceType} from 'sentry/views/performance/traceDetails/newTraceDetailsContent';
46

7+
const trackTraceShape = (shape: TraceType, organization: Organization) => {
8+
Sentry.metrics.increment(`trace.trace_shape.${shape}`);
9+
trackAnalytics('trace.shape', {
10+
shape,
11+
organization,
12+
});
13+
};
14+
15+
const trackFailedToFetchTraceState = () =>
16+
Sentry.metrics.increment('trace.failed_to_fetch_trace');
17+
18+
const trackEmptyTraceState = () => Sentry.metrics.increment('trace.empty_trace');
19+
520
const trackLayoutChange = (layout: string, organization: Organization) =>
621
trackAnalytics('trace.trace_layout.change', {
722
layout,
@@ -61,6 +76,10 @@ const trackTraceWarningType = (type: TraceType, organization: Organization) =>
6176
});
6277

6378
const traceAnalytics = {
79+
// Trace shape
80+
trackTraceShape,
81+
trackEmptyTraceState,
82+
trackFailedToFetchTraceState,
6483
// Drawer actions
6584
trackShowInView,
6685
trackViewEventDetails,

static/app/views/performance/newTraceDetails/traceDrawer/tabs/trace.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {useLocation} from 'sentry/utils/useLocation';
1515
import useOrganization from 'sentry/utils/useOrganization';
1616
import Tags from 'sentry/views/discover/tags';
1717
import {TraceWarnings} from 'sentry/views/performance/newTraceDetails/traceWarnings';
18+
import type {TraceType} from 'sentry/views/performance/traceDetails/newTraceDetailsContent';
1819

1920
import {isTraceNode} from '../../guards';
2021
import type {TraceTree, TraceTreeNode} from '../../traceModels/traceTree';
@@ -25,6 +26,7 @@ type TraceDetailsProps = {
2526
rootEventResults: UseApiQueryResult<EventTransaction, RequestError>;
2627
tagsQueryResults: UseApiQueryResult<Tag[], RequestError>;
2728
traceEventView: EventView;
29+
traceType: TraceType;
2830
traces: TraceSplitResults<TraceFullDetailed> | null;
2931
tree: TraceTree;
3032
};
@@ -52,7 +54,7 @@ export function TraceDetails(props: TraceDetailsProps) {
5254

5355
return (
5456
<Fragment>
55-
{props.tree.type === 'trace' ? <TraceWarnings type={props.tree.shape} /> : null}
57+
{props.tree.type === 'trace' ? <TraceWarnings type={props.traceType} /> : null}
5658
<IssueList issues={issues} node={props.node} organization={organization} />
5759
{rootEvent ? (
5860
<Tags

static/app/views/performance/newTraceDetails/traceDrawer/traceDrawer.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
getTraceTabTitle,
4343
type TraceTabsReducerState,
4444
} from 'sentry/views/performance/newTraceDetails/traceState/traceTabs';
45+
import type {TraceType} from 'sentry/views/performance/traceDetails/newTraceDetailsContent';
4546

4647
import {
4748
makeTraceNodeBarColor,
@@ -62,6 +63,7 @@ type TraceDrawerProps = {
6263
trace: TraceTree;
6364
traceEventView: EventView;
6465
traceGridRef: HTMLElement | null;
66+
traceType: TraceType;
6567
trace_dispatch: React.Dispatch<TraceReducerAction>;
6668
trace_state: TraceReducerState;
6769
traces: TraceSplitResults<TraceFullDetailed> | null;
@@ -433,6 +435,7 @@ export function TraceDrawer(props: TraceDrawerProps) {
433435
{props.trace_state.tabs.current_tab ? (
434436
props.trace_state.tabs.current_tab.node === 'trace' ? (
435437
<TraceDetails
438+
traceType={props.traceType}
436439
tree={props.trace}
437440
node={props.trace.root.children[0]}
438441
rootEventResults={props.rootEventResults}

0 commit comments

Comments
 (0)