mirror of
https://github.com/MarSeventh/CloudFlare-ImgBed.git
synced 2026-04-27 15:45:07 +00:00
init
This commit is contained in:
812
node_modules/@sentry/core/cjs/baseclient.js
generated
vendored
Normal file
812
node_modules/@sentry/core/cjs/baseclient.js
generated
vendored
Normal file
@@ -0,0 +1,812 @@
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
const utils = require('@sentry/utils');
|
||||
const api = require('./api.js');
|
||||
const debugBuild = require('./debug-build.js');
|
||||
const envelope = require('./envelope.js');
|
||||
const exports$1 = require('./exports.js');
|
||||
const hub = require('./hub.js');
|
||||
const integration = require('./integration.js');
|
||||
const envelope$1 = require('./metrics/envelope.js');
|
||||
const session = require('./session.js');
|
||||
const dynamicSamplingContext = require('./tracing/dynamicSamplingContext.js');
|
||||
const prepareEvent = require('./utils/prepareEvent.js');
|
||||
|
||||
const ALREADY_SEEN_ERROR = "Not capturing exception because it's already been captured.";
|
||||
|
||||
/**
|
||||
* Base implementation for all JavaScript SDK clients.
|
||||
*
|
||||
* Call the constructor with the corresponding options
|
||||
* specific to the client subclass. To access these options later, use
|
||||
* {@link Client.getOptions}.
|
||||
*
|
||||
* If a Dsn is specified in the options, it will be parsed and stored. Use
|
||||
* {@link Client.getDsn} to retrieve the Dsn at any moment. In case the Dsn is
|
||||
* invalid, the constructor will throw a {@link SentryException}. Note that
|
||||
* without a valid Dsn, the SDK will not send any events to Sentry.
|
||||
*
|
||||
* Before sending an event, it is passed through
|
||||
* {@link BaseClient._prepareEvent} to add SDK information and scope data
|
||||
* (breadcrumbs and context). To add more custom information, override this
|
||||
* method and extend the resulting prepared event.
|
||||
*
|
||||
* To issue automatically created events (e.g. via instrumentation), use
|
||||
* {@link Client.captureEvent}. It will prepare the event and pass it through
|
||||
* the callback lifecycle. To issue auto-breadcrumbs, use
|
||||
* {@link Client.addBreadcrumb}.
|
||||
*
|
||||
* @example
|
||||
* class NodeClient extends BaseClient<NodeOptions> {
|
||||
* public constructor(options: NodeOptions) {
|
||||
* super(options);
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
* }
|
||||
*/
|
||||
class BaseClient {
|
||||
/**
|
||||
* A reference to a metrics aggregator
|
||||
*
|
||||
* @experimental Note this is alpha API. It may experience breaking changes in the future.
|
||||
*/
|
||||
|
||||
/** Options passed to the SDK. */
|
||||
|
||||
/** The client Dsn, if specified in options. Without this Dsn, the SDK will be disabled. */
|
||||
|
||||
/** Array of set up integrations. */
|
||||
|
||||
/** Indicates whether this client's integrations have been set up. */
|
||||
|
||||
/** Number of calls being processed */
|
||||
|
||||
/** Holds flushable */
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
|
||||
/**
|
||||
* Initializes this client instance.
|
||||
*
|
||||
* @param options Options for the client.
|
||||
*/
|
||||
constructor(options) {
|
||||
this._options = options;
|
||||
this._integrations = {};
|
||||
this._integrationsInitialized = false;
|
||||
this._numProcessing = 0;
|
||||
this._outcomes = {};
|
||||
this._hooks = {};
|
||||
this._eventProcessors = [];
|
||||
|
||||
if (options.dsn) {
|
||||
this._dsn = utils.makeDsn(options.dsn);
|
||||
} else {
|
||||
debugBuild.DEBUG_BUILD && utils.logger.warn('No DSN provided, client will not send events.');
|
||||
}
|
||||
|
||||
if (this._dsn) {
|
||||
const url = api.getEnvelopeEndpointWithUrlEncodedAuth(this._dsn, options);
|
||||
this._transport = options.transport({
|
||||
tunnel: this._options.tunnel,
|
||||
recordDroppedEvent: this.recordDroppedEvent.bind(this),
|
||||
...options.transportOptions,
|
||||
url,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
|
||||
captureException(exception, hint, scope) {
|
||||
// ensure we haven't captured this very object before
|
||||
if (utils.checkOrSetAlreadyCaught(exception)) {
|
||||
debugBuild.DEBUG_BUILD && utils.logger.log(ALREADY_SEEN_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
let eventId = hint && hint.event_id;
|
||||
|
||||
this._process(
|
||||
this.eventFromException(exception, hint)
|
||||
.then(event => this._captureEvent(event, hint, scope))
|
||||
.then(result => {
|
||||
eventId = result;
|
||||
}),
|
||||
);
|
||||
|
||||
return eventId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
captureMessage(
|
||||
message,
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
level,
|
||||
hint,
|
||||
scope,
|
||||
) {
|
||||
let eventId = hint && hint.event_id;
|
||||
|
||||
const eventMessage = utils.isParameterizedString(message) ? message : String(message);
|
||||
|
||||
const promisedEvent = utils.isPrimitive(message)
|
||||
? this.eventFromMessage(eventMessage, level, hint)
|
||||
: this.eventFromException(message, hint);
|
||||
|
||||
this._process(
|
||||
promisedEvent
|
||||
.then(event => this._captureEvent(event, hint, scope))
|
||||
.then(result => {
|
||||
eventId = result;
|
||||
}),
|
||||
);
|
||||
|
||||
return eventId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
captureEvent(event, hint, scope) {
|
||||
// ensure we haven't captured this very object before
|
||||
if (hint && hint.originalException && utils.checkOrSetAlreadyCaught(hint.originalException)) {
|
||||
debugBuild.DEBUG_BUILD && utils.logger.log(ALREADY_SEEN_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
let eventId = hint && hint.event_id;
|
||||
|
||||
const sdkProcessingMetadata = event.sdkProcessingMetadata || {};
|
||||
const capturedSpanScope = sdkProcessingMetadata.capturedSpanScope;
|
||||
|
||||
this._process(
|
||||
this._captureEvent(event, hint, capturedSpanScope || scope).then(result => {
|
||||
eventId = result;
|
||||
}),
|
||||
);
|
||||
|
||||
return eventId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
captureSession(session$1) {
|
||||
if (!(typeof session$1.release === 'string')) {
|
||||
debugBuild.DEBUG_BUILD && utils.logger.warn('Discarded session because of missing or non-string release');
|
||||
} else {
|
||||
this.sendSession(session$1);
|
||||
// After sending, we set init false to indicate it's not the first occurrence
|
||||
session.updateSession(session$1, { init: false });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getDsn() {
|
||||
return this._dsn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getOptions() {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SdkMetadata in @sentry/types
|
||||
*
|
||||
* @return The metadata of the SDK
|
||||
*/
|
||||
getSdkMetadata() {
|
||||
return this._options._metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getTransport() {
|
||||
return this._transport;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
flush(timeout) {
|
||||
const transport = this._transport;
|
||||
if (transport) {
|
||||
if (this.metricsAggregator) {
|
||||
this.metricsAggregator.flush();
|
||||
}
|
||||
return this._isClientDoneProcessing(timeout).then(clientFinished => {
|
||||
return transport.flush(timeout).then(transportFlushed => clientFinished && transportFlushed);
|
||||
});
|
||||
} else {
|
||||
return utils.resolvedSyncPromise(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
close(timeout) {
|
||||
return this.flush(timeout).then(result => {
|
||||
this.getOptions().enabled = false;
|
||||
if (this.metricsAggregator) {
|
||||
this.metricsAggregator.close();
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/** Get all installed event processors. */
|
||||
getEventProcessors() {
|
||||
return this._eventProcessors;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
addEventProcessor(eventProcessor) {
|
||||
this._eventProcessors.push(eventProcessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is an internal function to setup all integrations that should run on the client.
|
||||
* @deprecated Use `client.init()` instead.
|
||||
*/
|
||||
setupIntegrations(forceInitialize) {
|
||||
if ((forceInitialize && !this._integrationsInitialized) || (this._isEnabled() && !this._integrationsInitialized)) {
|
||||
this._setupIntegrations();
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
init() {
|
||||
if (this._isEnabled()) {
|
||||
this._setupIntegrations();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an installed integration by its `id`.
|
||||
*
|
||||
* @returns The installed integration or `undefined` if no integration with that `id` was installed.
|
||||
* @deprecated Use `getIntegrationByName()` instead.
|
||||
*/
|
||||
getIntegrationById(integrationId) {
|
||||
return this.getIntegrationByName(integrationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an installed integration by its name.
|
||||
*
|
||||
* @returns The installed integration or `undefined` if no integration with that `name` was installed.
|
||||
*/
|
||||
getIntegrationByName(integrationName) {
|
||||
return this._integrations[integrationName] ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the client's instance of the given integration class, it any.
|
||||
* @deprecated Use `getIntegrationByName()` instead.
|
||||
*/
|
||||
getIntegration(integration) {
|
||||
try {
|
||||
return (this._integrations[integration.id] ) || null;
|
||||
} catch (_oO) {
|
||||
debugBuild.DEBUG_BUILD && utils.logger.warn(`Cannot retrieve integration ${integration.id} from the current Client`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
addIntegration(integration$1) {
|
||||
const isAlreadyInstalled = this._integrations[integration$1.name];
|
||||
|
||||
// This hook takes care of only installing if not already installed
|
||||
integration.setupIntegration(this, integration$1, this._integrations);
|
||||
// Here we need to check manually to make sure to not run this multiple times
|
||||
if (!isAlreadyInstalled) {
|
||||
integration.afterSetupIntegrations(this, [integration$1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
sendEvent(event, hint = {}) {
|
||||
this.emit('beforeSendEvent', event, hint);
|
||||
|
||||
let env = envelope.createEventEnvelope(event, this._dsn, this._options._metadata, this._options.tunnel);
|
||||
|
||||
for (const attachment of hint.attachments || []) {
|
||||
env = utils.addItemToEnvelope(
|
||||
env,
|
||||
utils.createAttachmentEnvelopeItem(
|
||||
attachment,
|
||||
this._options.transportOptions && this._options.transportOptions.textEncoder,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const promise = this._sendEnvelope(env);
|
||||
if (promise) {
|
||||
promise.then(sendResponse => this.emit('afterSendEvent', event, sendResponse), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
sendSession(session) {
|
||||
const env = envelope.createSessionEnvelope(session, this._dsn, this._options._metadata, this._options.tunnel);
|
||||
|
||||
// _sendEnvelope should not throw
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this._sendEnvelope(env);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
recordDroppedEvent(reason, category, _event) {
|
||||
// Note: we use `event` in replay, where we overwrite this hook.
|
||||
|
||||
if (this._options.sendClientReports) {
|
||||
// We want to track each category (error, transaction, session, replay_event) separately
|
||||
// but still keep the distinction between different type of outcomes.
|
||||
// We could use nested maps, but it's much easier to read and type this way.
|
||||
// A correct type for map-based implementation if we want to go that route
|
||||
// would be `Partial<Record<SentryRequestType, Partial<Record<Outcome, number>>>>`
|
||||
// With typescript 4.1 we could even use template literal types
|
||||
const key = `${reason}:${category}`;
|
||||
debugBuild.DEBUG_BUILD && utils.logger.log(`Adding outcome: "${key}"`);
|
||||
|
||||
// The following works because undefined + 1 === NaN and NaN is falsy
|
||||
this._outcomes[key] = this._outcomes[key] + 1 || 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
captureAggregateMetrics(metricBucketItems) {
|
||||
debugBuild.DEBUG_BUILD && utils.logger.log(`Flushing aggregated metrics, number of metrics: ${metricBucketItems.length}`);
|
||||
const metricsEnvelope = envelope$1.createMetricEnvelope(
|
||||
metricBucketItems,
|
||||
this._dsn,
|
||||
this._options._metadata,
|
||||
this._options.tunnel,
|
||||
);
|
||||
|
||||
// _sendEnvelope should not throw
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this._sendEnvelope(metricsEnvelope);
|
||||
}
|
||||
|
||||
// Keep on() & emit() signatures in sync with types' client.ts interface
|
||||
/* eslint-disable @typescript-eslint/unified-signatures */
|
||||
|
||||
/** @inheritdoc */
|
||||
|
||||
/** @inheritdoc */
|
||||
on(hook, callback) {
|
||||
if (!this._hooks[hook]) {
|
||||
this._hooks[hook] = [];
|
||||
}
|
||||
|
||||
// @ts-expect-error We assue the types are correct
|
||||
this._hooks[hook].push(callback);
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
|
||||
/** @inheritdoc */
|
||||
emit(hook, ...rest) {
|
||||
if (this._hooks[hook]) {
|
||||
this._hooks[hook].forEach(callback => callback(...rest));
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-enable @typescript-eslint/unified-signatures */
|
||||
|
||||
/** Setup integrations for this client. */
|
||||
_setupIntegrations() {
|
||||
const { integrations } = this._options;
|
||||
this._integrations = integration.setupIntegrations(this, integrations);
|
||||
integration.afterSetupIntegrations(this, integrations);
|
||||
|
||||
// TODO v8: We don't need this flag anymore
|
||||
this._integrationsInitialized = true;
|
||||
}
|
||||
|
||||
/** Updates existing session based on the provided event */
|
||||
_updateSessionFromEvent(session$1, event) {
|
||||
let crashed = false;
|
||||
let errored = false;
|
||||
const exceptions = event.exception && event.exception.values;
|
||||
|
||||
if (exceptions) {
|
||||
errored = true;
|
||||
|
||||
for (const ex of exceptions) {
|
||||
const mechanism = ex.mechanism;
|
||||
if (mechanism && mechanism.handled === false) {
|
||||
crashed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A session is updated and that session update is sent in only one of the two following scenarios:
|
||||
// 1. Session with non terminal status and 0 errors + an error occurred -> Will set error count to 1 and send update
|
||||
// 2. Session with non terminal status and 1 error + a crash occurred -> Will set status crashed and send update
|
||||
const sessionNonTerminal = session$1.status === 'ok';
|
||||
const shouldUpdateAndSend = (sessionNonTerminal && session$1.errors === 0) || (sessionNonTerminal && crashed);
|
||||
|
||||
if (shouldUpdateAndSend) {
|
||||
session.updateSession(session$1, {
|
||||
...(crashed && { status: 'crashed' }),
|
||||
errors: session$1.errors || Number(errored || crashed),
|
||||
});
|
||||
this.captureSession(session$1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the client is finished processing. Returns a promise because it will wait `timeout` ms before saying
|
||||
* "no" (resolving to `false`) in order to give the client a chance to potentially finish first.
|
||||
*
|
||||
* @param timeout The time, in ms, after which to resolve to `false` if the client is still busy. Passing `0` (or not
|
||||
* passing anything) will make the promise wait as long as it takes for processing to finish before resolving to
|
||||
* `true`.
|
||||
* @returns A promise which will resolve to `true` if processing is already done or finishes before the timeout, and
|
||||
* `false` otherwise
|
||||
*/
|
||||
_isClientDoneProcessing(timeout) {
|
||||
return new utils.SyncPromise(resolve => {
|
||||
let ticked = 0;
|
||||
const tick = 1;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
if (this._numProcessing == 0) {
|
||||
clearInterval(interval);
|
||||
resolve(true);
|
||||
} else {
|
||||
ticked += tick;
|
||||
if (timeout && ticked >= timeout) {
|
||||
clearInterval(interval);
|
||||
resolve(false);
|
||||
}
|
||||
}
|
||||
}, tick);
|
||||
});
|
||||
}
|
||||
|
||||
/** Determines whether this SDK is enabled and a transport is present. */
|
||||
_isEnabled() {
|
||||
return this.getOptions().enabled !== false && this._transport !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds common information to events.
|
||||
*
|
||||
* The information includes release and environment from `options`,
|
||||
* breadcrumbs and context (extra, tags and user) from the scope.
|
||||
*
|
||||
* Information that is already present in the event is never overwritten. For
|
||||
* nested objects, such as the context, keys are merged.
|
||||
*
|
||||
* @param event The original event.
|
||||
* @param hint May contain additional information about the original exception.
|
||||
* @param scope A scope containing event metadata.
|
||||
* @returns A new event with more information.
|
||||
*/
|
||||
_prepareEvent(
|
||||
event,
|
||||
hint,
|
||||
scope,
|
||||
isolationScope = hub.getIsolationScope(),
|
||||
) {
|
||||
const options = this.getOptions();
|
||||
const integrations = Object.keys(this._integrations);
|
||||
if (!hint.integrations && integrations.length > 0) {
|
||||
hint.integrations = integrations;
|
||||
}
|
||||
|
||||
this.emit('preprocessEvent', event, hint);
|
||||
|
||||
return prepareEvent.prepareEvent(options, event, hint, scope, this, isolationScope).then(evt => {
|
||||
if (evt === null) {
|
||||
return evt;
|
||||
}
|
||||
|
||||
const propagationContext = {
|
||||
...isolationScope.getPropagationContext(),
|
||||
...(scope ? scope.getPropagationContext() : undefined),
|
||||
};
|
||||
|
||||
const trace = evt.contexts && evt.contexts.trace;
|
||||
if (!trace && propagationContext) {
|
||||
const { traceId: trace_id, spanId, parentSpanId, dsc } = propagationContext;
|
||||
evt.contexts = {
|
||||
trace: {
|
||||
trace_id,
|
||||
span_id: spanId,
|
||||
parent_span_id: parentSpanId,
|
||||
},
|
||||
...evt.contexts,
|
||||
};
|
||||
|
||||
const dynamicSamplingContext$1 = dsc ? dsc : dynamicSamplingContext.getDynamicSamplingContextFromClient(trace_id, this, scope);
|
||||
|
||||
evt.sdkProcessingMetadata = {
|
||||
dynamicSamplingContext: dynamicSamplingContext$1,
|
||||
...evt.sdkProcessingMetadata,
|
||||
};
|
||||
}
|
||||
return evt;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the event and logs an error in case of rejection
|
||||
* @param event
|
||||
* @param hint
|
||||
* @param scope
|
||||
*/
|
||||
_captureEvent(event, hint = {}, scope) {
|
||||
return this._processEvent(event, hint, scope).then(
|
||||
finalEvent => {
|
||||
return finalEvent.event_id;
|
||||
},
|
||||
reason => {
|
||||
if (debugBuild.DEBUG_BUILD) {
|
||||
// If something's gone wrong, log the error as a warning. If it's just us having used a `SentryError` for
|
||||
// control flow, log just the message (no stack) as a log-level log.
|
||||
const sentryError = reason ;
|
||||
if (sentryError.logLevel === 'log') {
|
||||
utils.logger.log(sentryError.message);
|
||||
} else {
|
||||
utils.logger.warn(sentryError);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an event (either error or message) and sends it to Sentry.
|
||||
*
|
||||
* This also adds breadcrumbs and context information to the event. However,
|
||||
* platform specific meta data (such as the User's IP address) must be added
|
||||
* by the SDK implementor.
|
||||
*
|
||||
*
|
||||
* @param event The event to send to Sentry.
|
||||
* @param hint May contain additional information about the original exception.
|
||||
* @param scope A scope containing event metadata.
|
||||
* @returns A SyncPromise that resolves with the event or rejects in case event was/will not be send.
|
||||
*/
|
||||
_processEvent(event, hint, scope) {
|
||||
const options = this.getOptions();
|
||||
const { sampleRate } = options;
|
||||
|
||||
const isTransaction = isTransactionEvent(event);
|
||||
const isError = isErrorEvent(event);
|
||||
const eventType = event.type || 'error';
|
||||
const beforeSendLabel = `before send for type \`${eventType}\``;
|
||||
|
||||
// 1.0 === 100% events are sent
|
||||
// 0.0 === 0% events are sent
|
||||
// Sampling for transaction happens somewhere else
|
||||
if (isError && typeof sampleRate === 'number' && Math.random() > sampleRate) {
|
||||
this.recordDroppedEvent('sample_rate', 'error', event);
|
||||
return utils.rejectedSyncPromise(
|
||||
new utils.SentryError(
|
||||
`Discarding event because it's not included in the random sample (sampling rate = ${sampleRate})`,
|
||||
'log',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const dataCategory = eventType === 'replay_event' ? 'replay' : eventType;
|
||||
|
||||
const sdkProcessingMetadata = event.sdkProcessingMetadata || {};
|
||||
const capturedSpanIsolationScope = sdkProcessingMetadata.capturedSpanIsolationScope;
|
||||
|
||||
return this._prepareEvent(event, hint, scope, capturedSpanIsolationScope)
|
||||
.then(prepared => {
|
||||
if (prepared === null) {
|
||||
this.recordDroppedEvent('event_processor', dataCategory, event);
|
||||
throw new utils.SentryError('An event processor returned `null`, will not send event.', 'log');
|
||||
}
|
||||
|
||||
const isInternalException = hint.data && (hint.data ).__sentry__ === true;
|
||||
if (isInternalException) {
|
||||
return prepared;
|
||||
}
|
||||
|
||||
const result = processBeforeSend(options, prepared, hint);
|
||||
return _validateBeforeSendResult(result, beforeSendLabel);
|
||||
})
|
||||
.then(processedEvent => {
|
||||
if (processedEvent === null) {
|
||||
this.recordDroppedEvent('before_send', dataCategory, event);
|
||||
throw new utils.SentryError(`${beforeSendLabel} returned \`null\`, will not send event.`, 'log');
|
||||
}
|
||||
|
||||
const session = scope && scope.getSession();
|
||||
if (!isTransaction && session) {
|
||||
this._updateSessionFromEvent(session, processedEvent);
|
||||
}
|
||||
|
||||
// None of the Sentry built event processor will update transaction name,
|
||||
// so if the transaction name has been changed by an event processor, we know
|
||||
// it has to come from custom event processor added by a user
|
||||
const transactionInfo = processedEvent.transaction_info;
|
||||
if (isTransaction && transactionInfo && processedEvent.transaction !== event.transaction) {
|
||||
const source = 'custom';
|
||||
processedEvent.transaction_info = {
|
||||
...transactionInfo,
|
||||
source,
|
||||
};
|
||||
}
|
||||
|
||||
this.sendEvent(processedEvent, hint);
|
||||
return processedEvent;
|
||||
})
|
||||
.then(null, reason => {
|
||||
if (reason instanceof utils.SentryError) {
|
||||
throw reason;
|
||||
}
|
||||
|
||||
this.captureException(reason, {
|
||||
data: {
|
||||
__sentry__: true,
|
||||
},
|
||||
originalException: reason,
|
||||
});
|
||||
throw new utils.SentryError(
|
||||
`Event processing pipeline threw an error, original event will not be sent. Details have been sent as a new event.\nReason: ${reason}`,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Occupies the client with processing and event
|
||||
*/
|
||||
_process(promise) {
|
||||
this._numProcessing++;
|
||||
void promise.then(
|
||||
value => {
|
||||
this._numProcessing--;
|
||||
return value;
|
||||
},
|
||||
reason => {
|
||||
this._numProcessing--;
|
||||
return reason;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
_sendEnvelope(envelope) {
|
||||
this.emit('beforeEnvelope', envelope);
|
||||
|
||||
if (this._isEnabled() && this._transport) {
|
||||
return this._transport.send(envelope).then(null, reason => {
|
||||
debugBuild.DEBUG_BUILD && utils.logger.error('Error while sending event:', reason);
|
||||
});
|
||||
} else {
|
||||
debugBuild.DEBUG_BUILD && utils.logger.error('Transport disabled');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears outcomes on this client and returns them.
|
||||
*/
|
||||
_clearOutcomes() {
|
||||
const outcomes = this._outcomes;
|
||||
this._outcomes = {};
|
||||
return Object.keys(outcomes).map(key => {
|
||||
const [reason, category] = key.split(':') ;
|
||||
return {
|
||||
reason,
|
||||
category,
|
||||
quantity: outcomes[key],
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that return value of configured `beforeSend` or `beforeSendTransaction` is of expected type, and returns the value if so.
|
||||
*/
|
||||
function _validateBeforeSendResult(
|
||||
beforeSendResult,
|
||||
beforeSendLabel,
|
||||
) {
|
||||
const invalidValueError = `${beforeSendLabel} must return \`null\` or a valid event.`;
|
||||
if (utils.isThenable(beforeSendResult)) {
|
||||
return beforeSendResult.then(
|
||||
event => {
|
||||
if (!utils.isPlainObject(event) && event !== null) {
|
||||
throw new utils.SentryError(invalidValueError);
|
||||
}
|
||||
return event;
|
||||
},
|
||||
e => {
|
||||
throw new utils.SentryError(`${beforeSendLabel} rejected with ${e}`);
|
||||
},
|
||||
);
|
||||
} else if (!utils.isPlainObject(beforeSendResult) && beforeSendResult !== null) {
|
||||
throw new utils.SentryError(invalidValueError);
|
||||
}
|
||||
return beforeSendResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the matching `beforeSendXXX` callback.
|
||||
*/
|
||||
function processBeforeSend(
|
||||
options,
|
||||
event,
|
||||
hint,
|
||||
) {
|
||||
const { beforeSend, beforeSendTransaction } = options;
|
||||
|
||||
if (isErrorEvent(event) && beforeSend) {
|
||||
return beforeSend(event, hint);
|
||||
}
|
||||
|
||||
if (isTransactionEvent(event) && beforeSendTransaction) {
|
||||
return beforeSendTransaction(event, hint);
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
function isErrorEvent(event) {
|
||||
return event.type === undefined;
|
||||
}
|
||||
|
||||
function isTransactionEvent(event) {
|
||||
return event.type === 'transaction';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an event processor to the current client.
|
||||
* This event processor will run for all events processed by this client.
|
||||
*/
|
||||
function addEventProcessor(callback) {
|
||||
const client = exports$1.getClient();
|
||||
|
||||
if (!client || !client.addEventProcessor) {
|
||||
return;
|
||||
}
|
||||
|
||||
client.addEventProcessor(callback);
|
||||
}
|
||||
|
||||
exports.BaseClient = BaseClient;
|
||||
exports.addEventProcessor = addEventProcessor;
|
||||
//# sourceMappingURL=baseclient.js.map
|
||||
Reference in New Issue
Block a user