Skip to content

Commit 432495d

Browse files
authored
feat(replay): Add feedback breadcrumb to replay (#9495)
Add feedback breadcrumb to replay when a feedback is sent (and if replays are enabled).
1 parent 4fc2e7e commit 432495d

File tree

4 files changed

+61
-4
lines changed

4 files changed

+61
-4
lines changed

packages/replay/src/coreHandlers/handleGlobalEvent.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import type { Event, EventHint } from '@sentry/types';
22
import { logger } from '@sentry/utils';
33

44
import type { ReplayContainer } from '../types';
5-
import { isErrorEvent, isReplayEvent, isTransactionEvent } from '../util/eventUtils';
5+
import { isErrorEvent, isFeedbackEvent, isReplayEvent, isTransactionEvent } from '../util/eventUtils';
66
import { isRrwebError } from '../util/isRrwebError';
77
import { handleAfterSendEvent } from './handleAfterSendEvent';
8+
import { addFeedbackBreadcrumb } from './util/addFeedbackBreadcrumb';
89
import { shouldSampleForBufferEvent } from './util/shouldSampleForBufferEvent';
910

1011
/**
@@ -30,8 +31,8 @@ export function handleGlobalEventListener(
3031
return event;
3132
}
3233

33-
// We only want to handle errors & transactions, nothing else
34-
if (!isErrorEvent(event) && !isTransactionEvent(event)) {
34+
// We only want to handle errors, transactions, and feedbacks, nothing else
35+
if (!isErrorEvent(event) && !isTransactionEvent(event) && !isFeedbackEvent(event)) {
3536
return event;
3637
}
3738

@@ -41,6 +42,12 @@ export function handleGlobalEventListener(
4142
return event;
4243
}
4344

45+
if (isFeedbackEvent(event)) {
46+
// Add a replay breadcrumb for this piece of feedback
47+
addFeedbackBreadcrumb(replay, event);
48+
return event;
49+
}
50+
4451
// Unless `captureExceptions` is enabled, we want to ignore errors coming from rrweb
4552
// As there can be a bunch of stuff going wrong in internals there, that we don't want to bubble up to users
4653
if (isRrwebError(event, hint) && !replay.getOptions()._experiments.captureExceptions) {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { EventType } from '@sentry-internal/rrweb';
2+
import type { FeedbackEvent } from '@sentry/types';
3+
4+
import type { ReplayContainer } from '../../types';
5+
6+
/**
7+
* Add a feedback breadcrumb event to replay.
8+
*/
9+
export function addFeedbackBreadcrumb(replay: ReplayContainer, event: FeedbackEvent): void {
10+
replay.triggerUserActivity();
11+
replay.addUpdate(() => {
12+
if (!event.timestamp) {
13+
// Ignore events that don't have timestamps (this shouldn't happen, more of a typing issue)
14+
// Return true here so that we don't flush
15+
return true;
16+
}
17+
18+
void replay.throttledAddEvent({
19+
type: EventType.Custom,
20+
timestamp: event.timestamp * 1000,
21+
data: {
22+
timestamp: event.timestamp,
23+
tag: 'breadcrumb',
24+
payload: {
25+
category: 'sentry.feedback',
26+
data: {
27+
feedbackId: event.event_id,
28+
},
29+
},
30+
},
31+
});
32+
33+
return false;
34+
});
35+
}

packages/replay/src/types/replayFrame.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,15 @@ interface ReplayOptionFrame {
126126
useCompressionOption: boolean;
127127
}
128128

129+
interface ReplayFeedbackFrameData {
130+
feedback_id: string;
131+
}
132+
133+
interface ReplayFeedbackFrame extends ReplayBaseBreadcrumbFrame {
134+
category: 'sentry.feedback';
135+
data: ReplayFeedbackFrameData;
136+
}
137+
129138
export type ReplayBreadcrumbFrame =
130139
| ReplayConsoleFrame
131140
| ReplayClickFrame
@@ -136,6 +145,7 @@ export type ReplayBreadcrumbFrame =
136145
| ReplaySlowClickFrame
137146
| ReplayMultiClickFrame
138147
| ReplayMutationFrame
148+
| ReplayFeedbackFrame
139149
| ReplayBaseBreadcrumbFrame;
140150

141151
interface ReplayBaseSpanFrame {

packages/replay/src/util/eventUtils.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ErrorEvent, Event, ReplayEvent, TransactionEvent } from '@sentry/types';
1+
import type { ErrorEvent, Event, FeedbackEvent, ReplayEvent, TransactionEvent } from '@sentry/types';
22

33
/** If the event is an error event */
44
export function isErrorEvent(event: Event): event is ErrorEvent {
@@ -14,3 +14,8 @@ export function isTransactionEvent(event: Event): event is TransactionEvent {
1414
export function isReplayEvent(event: Event): event is ReplayEvent {
1515
return event.type === 'replay_event';
1616
}
17+
18+
/** If the event is a feedback event */
19+
export function isFeedbackEvent(event: Event): event is FeedbackEvent {
20+
return event.type === 'feedback';
21+
}

0 commit comments

Comments
 (0)