@sentry/core
Version:
Base implementation for all Sentry JavaScript SDKs
102 lines (86 loc) • 3.4 kB
JavaScript
import { makePromiseBuffer, forEachEnvelopeItem, envelopeItemTypeToDataCategory, isRateLimited, resolvedSyncPromise, createEnvelope, SentryError, logger, serializeEnvelope, updateRateLimits } from '@sentry/utils';
const DEFAULT_TRANSPORT_BUFFER_SIZE = 30;
/**
* Creates an instance of a Sentry `Transport`
*
* @param options
* @param makeRequest
*/
function createTransport(
options,
makeRequest,
buffer = makePromiseBuffer(
options.bufferSize || DEFAULT_TRANSPORT_BUFFER_SIZE,
),
) {
let rateLimits = {};
const flush = (timeout) => buffer.drain(timeout);
function send(envelope) {
const filteredEnvelopeItems = [];
// Drop rate limited items from envelope
forEachEnvelopeItem(envelope, (item, type) => {
const envelopeItemDataCategory = envelopeItemTypeToDataCategory(type);
if (isRateLimited(rateLimits, envelopeItemDataCategory)) {
const event = 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 = createEnvelope(envelope[0], filteredEnvelopeItems );
// Creates client report for each item in an envelope
const recordEnvelopeLoss = (reason) => {
forEachEnvelopeItem(filteredEnvelope, (item, type) => {
const event = getEventForEnvelopeItem(item, type);
options.recordDroppedEvent(reason, envelopeItemTypeToDataCategory(type), event);
});
};
const requestTask = () =>
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)) {
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && 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) {
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('Skipped sending event because buffer is full.');
recordEnvelopeLoss('queue_overflow');
return resolvedSyncPromise();
} else {
throw error;
}
},
);
}
// We use this to identifify if the transport is the base transport
// TODO (v8): Remove this again as we'll no longer need it
send.__sentry__baseTransport__ = true;
return {
send,
flush,
};
}
function getEventForEnvelopeItem(item, type) {
if (type !== 'event' && type !== 'transaction') {
return undefined;
}
return Array.isArray(item) ? (item )[1] : undefined;
}
export { DEFAULT_TRANSPORT_BUFFER_SIZE, createTransport };
//# sourceMappingURL=base.js.map