rittenhop-dev/versions/5.94.2/node_modules/@sentry/node/esm/handlers.js
2024-09-23 19:40:12 -04:00

290 lines
10 KiB
JavaScript

import { _optionalChain } from '@sentry/utils';
import { hasTracingEnabled, continueTrace, startTransaction, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getCurrentScope, setHttpStatus, getClient, flush, runWithAsyncContext, withScope, getActiveSpan, captureException } from '@sentry/core';
import { isString, extractPathForTransaction, extractRequestData, addRequestDataToTransaction, logger, dropUndefinedKeys } from '@sentry/utils';
import { DEBUG_BUILD } from './debug-build.js';
import { isAutoSessionTrackingEnabled } from './sdk.js';
import { trpcMiddleware as trpcMiddleware$1 } from './trpc.js';
export { extractRequestData, parseRequest } from './requestDataDeprecated.js';
/**
* Express-compatible tracing handler.
* @see Exposed as `Handlers.tracingHandler`
*/
function tracingHandler()
{
return function sentryTracingMiddleware(
req,
res,
next,
) {
const options = _optionalChain([getClient, 'call', _ => _(), 'optionalAccess', _2 => _2.getOptions, 'call', _3 => _3()]);
if (
!options ||
options.instrumenter !== 'sentry' ||
_optionalChain([req, 'access', _4 => _4.method, 'optionalAccess', _5 => _5.toUpperCase, 'call', _6 => _6()]) === 'OPTIONS' ||
_optionalChain([req, 'access', _7 => _7.method, 'optionalAccess', _8 => _8.toUpperCase, 'call', _9 => _9()]) === 'HEAD'
) {
return next();
}
const sentryTrace = req.headers && isString(req.headers['sentry-trace']) ? req.headers['sentry-trace'] : undefined;
const baggage = _optionalChain([req, 'access', _10 => _10.headers, 'optionalAccess', _11 => _11.baggage]);
if (!hasTracingEnabled(options)) {
return next();
}
const [name, source] = extractPathForTransaction(req, { path: true, method: true });
const transaction = continueTrace({ sentryTrace, baggage }, ctx =>
// TODO: Refactor this to use `startSpan()`
// eslint-disable-next-line deprecation/deprecation
startTransaction(
{
name,
op: 'http.server',
origin: 'auto.http.node.tracingHandler',
...ctx,
data: {
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
},
metadata: {
// eslint-disable-next-line deprecation/deprecation
...ctx.metadata,
// The request should already have been stored in `scope.sdkProcessingMetadata` (which will become
// `event.sdkProcessingMetadata` the same way the metadata here will) by `sentryRequestMiddleware`, but on the
// off chance someone is using `sentryTracingMiddleware` without `sentryRequestMiddleware`, it doesn't hurt to
// be sure
request: req,
},
},
// extra context passed to the tracesSampler
{ request: extractRequestData(req) },
),
);
// We put the transaction on the scope so users can attach children to it
// eslint-disable-next-line deprecation/deprecation
getCurrentScope().setSpan(transaction);
// We also set __sentry_transaction on the response so people can grab the transaction there to add
// spans to it later.
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
(res ).__sentry_transaction = transaction;
res.once('finish', () => {
// Push `transaction.finish` to the next event loop so open spans have a chance to finish before the transaction
// closes
setImmediate(() => {
// eslint-disable-next-line deprecation/deprecation
addRequestDataToTransaction(transaction, req);
setHttpStatus(transaction, res.statusCode);
transaction.end();
});
});
next();
};
}
/**
* Backwards compatibility shim which can be removed in v8. Forces the given options to follow the
* `AddRequestDataToEventOptions` interface.
*
* TODO (v8): Get rid of this, and stop passing `requestDataOptionsFromExpressHandler` to `setSDKProcessingMetadata`.
*/
function convertReqHandlerOptsToAddReqDataOpts(
reqHandlerOptions = {},
) {
let addRequestDataOptions;
if ('include' in reqHandlerOptions) {
addRequestDataOptions = { include: reqHandlerOptions.include };
} else {
// eslint-disable-next-line deprecation/deprecation
const { ip, request, transaction, user } = reqHandlerOptions ;
if (ip || request || transaction || user) {
addRequestDataOptions = { include: dropUndefinedKeys({ ip, request, transaction, user }) };
}
}
return addRequestDataOptions;
}
/**
* Express compatible request handler.
* @see Exposed as `Handlers.requestHandler`
*/
function requestHandler(
options,
) {
// TODO (v8): Get rid of this
const requestDataOptions = convertReqHandlerOptsToAddReqDataOpts(options);
const client = getClient();
// Initialise an instance of SessionFlusher on the client when `autoSessionTracking` is enabled and the
// `requestHandler` middleware is used indicating that we are running in SessionAggregates mode
if (client && isAutoSessionTrackingEnabled(client)) {
client.initSessionFlusher();
// If Scope contains a Single mode Session, it is removed in favor of using Session Aggregates mode
const scope = getCurrentScope();
if (scope.getSession()) {
scope.setSession();
}
}
return function sentryRequestMiddleware(
req,
res,
next,
) {
if (options && options.flushTimeout && options.flushTimeout > 0) {
// eslint-disable-next-line @typescript-eslint/unbound-method
const _end = res.end;
res.end = function (chunk, encoding, cb) {
void flush(options.flushTimeout)
.then(() => {
_end.call(this, chunk, encoding, cb);
})
.then(null, e => {
DEBUG_BUILD && logger.error(e);
_end.call(this, chunk, encoding, cb);
});
};
}
runWithAsyncContext(() => {
const scope = getCurrentScope();
scope.setSDKProcessingMetadata({
request: req,
// TODO (v8): Stop passing this
requestDataOptionsFromExpressHandler: requestDataOptions,
});
const client = getClient();
if (isAutoSessionTrackingEnabled(client)) {
// Set `status` of `RequestSession` to Ok, at the beginning of the request
scope.setRequestSession({ status: 'ok' });
}
res.once('finish', () => {
const client = getClient();
if (isAutoSessionTrackingEnabled(client)) {
setImmediate(() => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (client && (client )._captureRequestSession) {
// Calling _captureRequestSession to capture request session at the end of the request by incrementing
// the correct SessionAggregates bucket i.e. crashed, errored or exited
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
(client )._captureRequestSession();
}
});
}
});
next();
});
};
}
/** JSDoc */
/** JSDoc */
function getStatusCodeFromResponse(error) {
const statusCode = error.status || error.statusCode || error.status_code || (error.output && error.output.statusCode);
return statusCode ? parseInt(statusCode , 10) : 500;
}
/** Returns true if response code is internal server error */
function defaultShouldHandleError(error) {
const status = getStatusCodeFromResponse(error);
return status >= 500;
}
/**
* Express compatible error handler.
* @see Exposed as `Handlers.errorHandler`
*/
function errorHandler(options
)
{
return function sentryErrorMiddleware(
error,
_req,
res,
next,
) {
const shouldHandleError = (options && options.shouldHandleError) || defaultShouldHandleError;
if (shouldHandleError(error)) {
withScope(_scope => {
// The request should already have been stored in `scope.sdkProcessingMetadata` by `sentryRequestMiddleware`,
// but on the off chance someone is using `sentryErrorMiddleware` without `sentryRequestMiddleware`, it doesn't
// hurt to be sure
_scope.setSDKProcessingMetadata({ request: _req });
// For some reason we need to set the transaction on the scope again
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const transaction = (res ).__sentry_transaction ;
if (transaction && !getActiveSpan()) {
// eslint-disable-next-line deprecation/deprecation
_scope.setSpan(transaction);
}
const client = getClient();
if (client && isAutoSessionTrackingEnabled(client)) {
// Check if the `SessionFlusher` is instantiated on the client to go into this branch that marks the
// `requestSession.status` as `Crashed`, and this check is necessary because the `SessionFlusher` is only
// instantiated when the the`requestHandler` middleware is initialised, which indicates that we should be
// running in SessionAggregates mode
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const isSessionAggregatesMode = (client )._sessionFlusher !== undefined;
if (isSessionAggregatesMode) {
const requestSession = _scope.getRequestSession();
// If an error bubbles to the `errorHandler`, then this is an unhandled error, and should be reported as a
// Crashed session. The `_requestSession.status` is checked to ensure that this error is happening within
// the bounds of a request, and if so the status is updated
if (requestSession && requestSession.status !== undefined) {
requestSession.status = 'crashed';
}
}
}
const eventId = captureException(error, { mechanism: { type: 'middleware', handled: false } });
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
(res ).sentry = eventId;
next(error);
});
return;
}
next(error);
};
}
/**
* Sentry tRPC middleware that names the handling transaction after the called procedure.
*
* Use the Sentry tRPC middleware in combination with the Sentry server integration,
* e.g. Express Request Handlers or Next.js SDK.
*
* @deprecated Please use the top level export instead:
* ```
* // OLD
* import * as Sentry from '@sentry/node';
* Sentry.Handlers.trpcMiddleware();
*
* // NEW
* import * as Sentry from '@sentry/node';
* Sentry.trpcMiddleware();
* ```
*/
// eslint-disable-next-line deprecation/deprecation
const trpcMiddleware = trpcMiddleware$1;
export { errorHandler, requestHandler, tracingHandler, trpcMiddleware };
//# sourceMappingURL=handlers.js.map