-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathbase.ts
119 lines (105 loc) · 3.72 KB
/
base.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import type {
Envelope,
EnvelopeItem,
EnvelopeItemType,
Event,
EventDropReason,
EventItem,
InternalBaseTransportOptions,
Transport,
TransportMakeRequestResponse,
TransportRequestExecutor,
} from '@sentry/types';
import type { PromiseBuffer, RateLimits } from '@sentry/utils';
import {
createEnvelope,
envelopeItemTypeToDataCategory,
forEachEnvelopeItem,
isRateLimited,
logger,
makePromiseBuffer,
resolvedSyncPromise,
SentryError,
serializeEnvelope,
updateRateLimits,
} from '@sentry/utils';
export const DEFAULT_TRANSPORT_BUFFER_SIZE = 30;
/**
* Creates an instance of a Sentry `Transport`
*
* @param options
* @param makeRequest
*/
export function createTransport(
options: InternalBaseTransportOptions,
makeRequest: TransportRequestExecutor,
buffer: PromiseBuffer<void | TransportMakeRequestResponse> = makePromiseBuffer(
options.bufferSize || DEFAULT_TRANSPORT_BUFFER_SIZE,
),
): Transport {
let rateLimits: RateLimits = {};
const flush = (timeout?: number): PromiseLike<boolean> => buffer.drain(timeout);
function send(envelope: Envelope): PromiseLike<void | TransportMakeRequestResponse> {
const filteredEnvelopeItems: EnvelopeItem[] = [];
// Drop rate limited items from envelope
forEachEnvelopeItem(envelope, (item, type) => {
const envelopeItemDataCategory = envelopeItemTypeToDataCategory(type);
if (isRateLimited(rateLimits, envelopeItemDataCategory)) {
const event: Event | undefined = getEventForEnvelopeItem(item, type);
options.recordDroppedEvent('ratelimit_backoff', envelopeItemDataCategory, event);
} else {
filteredEnvelopeItems.push(item);
}
});
// Skip sending if envelope is empty after filtering out rate limited events
if (filteredEnvelopeItems.length === 0) {
return resolvedSyncPromise();
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const filteredEnvelope: Envelope = createEnvelope(envelope[0], filteredEnvelopeItems as any);
// Creates client report for each item in an envelope
const recordEnvelopeLoss = (reason: EventDropReason): void => {
forEachEnvelopeItem(filteredEnvelope, (item, type) => {
const event: Event | undefined = getEventForEnvelopeItem(item, type);
options.recordDroppedEvent(reason, envelopeItemTypeToDataCategory(type), event);
});
};
const requestTask = (): PromiseLike<void | TransportMakeRequestResponse> =>
makeRequest({ body: serializeEnvelope(filteredEnvelope, options.textEncoder) }).then(
response => {
// We don't want to throw on NOK responses, but we want to at least log them
if (response.statusCode !== undefined && (response.statusCode < 200 || response.statusCode >= 300)) {
__DEBUG_BUILD__ && logger.warn(`Sentry responded with status code ${response.statusCode} to sent event.`);
}
rateLimits = updateRateLimits(rateLimits, response);
return response;
},
error => {
recordEnvelopeLoss('network_error');
throw error;
},
);
return buffer.add(requestTask).then(
result => result,
error => {
if (error instanceof SentryError) {
__DEBUG_BUILD__ && logger.error('Skipped sending event because buffer is full.');
recordEnvelopeLoss('queue_overflow');
return resolvedSyncPromise();
} else {
throw error;
}
},
);
}
return {
send,
flush,
};
}
function getEventForEnvelopeItem(item: Envelope[1][number], type: EnvelopeItemType): Event | undefined {
if (type !== 'event' && type !== 'transaction') {
return undefined;
}
return Array.isArray(item) ? (item as EventItem)[1] : undefined;
}