UNPKG

@sentry/google-cloud-serverless

Version:
86 lines (75 loc) • 3.17 kB
import { _optionalChain } from '@sentry/utils'; import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, setHttpStatus, handleCallbackErrors } from '@sentry/core'; import { continueTrace, startSpanManual, getCurrentScope, flush, captureException } from '@sentry/node'; import { stripUrlQueryAndFragment, isString, logger } from '@sentry/utils'; import { DEBUG_BUILD } from '../debug-build.js'; import { proxyFunction, domainify, markEventUnhandled } from '../utils.js'; /** * Wraps an HTTP function handler adding it error capture and tracing capabilities. * * @param fn HTTP Handler * @param options Options * @returns HTTP handler */ function wrapHttpFunction(fn, wrapOptions = {}) { const wrap = (f) => domainify(_wrapHttpFunction(f, wrapOptions)); let overrides; // Functions emulator from firebase-tools has a hack-ish workaround that saves the actual function // passed to `onRequest(...)` and in fact runs it so we need to wrap it too. // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access const emulatorFunc = (fn ).__emulator_func ; if (emulatorFunc) { overrides = { __emulator_func: proxyFunction(emulatorFunc, wrap) }; } return proxyFunction(fn, wrap, overrides); } /** */ function _wrapHttpFunction(fn, options) { const flushTimeout = options.flushTimeout || 2000; return (req, res) => { const reqMethod = (req.method || '').toUpperCase(); const reqUrl = stripUrlQueryAndFragment(req.originalUrl || req.url || ''); const sentryTrace = req.headers && isString(req.headers['sentry-trace']) ? req.headers['sentry-trace'] : undefined; const baggage = _optionalChain([req, 'access', _ => _.headers, 'optionalAccess', _2 => _2.baggage]); return continueTrace({ sentryTrace, baggage }, () => { return startSpanManual( { name: `${reqMethod} ${reqUrl}`, op: 'function.gcp.http', attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.serverless.gcp_http', }, }, span => { getCurrentScope().setSDKProcessingMetadata({ request: req, }); // eslint-disable-next-line @typescript-eslint/unbound-method const _end = res.end; // eslint-disable-next-line @typescript-eslint/no-explicit-any res.end = function (chunk, encoding, cb) { setHttpStatus(span, res.statusCode); span.end(); // eslint-disable-next-line @typescript-eslint/no-floating-promises flush(flushTimeout) .then(null, e => { DEBUG_BUILD && logger.error(e); }) .then(() => { _end.call(this, chunk, encoding, cb); }); }; return handleCallbackErrors( () => fn(req, res), err => { captureException(err, scope => markEventUnhandled(scope)); }, ); }, ); }); }; } export { wrapHttpFunction }; //# sourceMappingURL=http.js.map