@sentry/node
Version:
Sentry Node SDK using OpenTelemetry for performance instrumentation
92 lines (89 loc) • 3.42 kB
JavaScript
import { defineIntegration, getClient, isObjectLike, withActiveSpan, consoleSandbox, captureException, isMatchingPattern } from '@sentry/core';
import { logAndExitProcess } from '../utils/errorhandling.js';
const INTEGRATION_NAME = "OnUnhandledRejection";
const DEFAULT_IGNORES = [
{
name: "AI_NoOutputGeneratedError"
// When stream aborts in Vercel AI SDK V5, Vercel flush() fails with an error
},
{
name: "AbortError"
// When stream aborts in Vercel AI SDK V6
}
];
const _onUnhandledRejectionIntegration = ((options = {}) => {
const opts = {
mode: options.mode ?? "warn",
ignore: [...DEFAULT_IGNORES, ...options.ignore ?? []]
};
return {
name: INTEGRATION_NAME,
setup(client) {
global.process.on("unhandledRejection", makeUnhandledPromiseHandler(client, opts));
}
};
});
const onUnhandledRejectionIntegration = defineIntegration(_onUnhandledRejectionIntegration);
function extractErrorInfo(reason) {
if (!isObjectLike(reason)) {
return { name: "", message: String(reason ?? "") };
}
const errorLike = reason;
const name = typeof errorLike.name === "string" ? errorLike.name : "";
const message = typeof errorLike.message === "string" ? errorLike.message : String(reason);
return { name, message };
}
function isMatchingReason(matcher, errorInfo) {
const nameMatches = matcher.name === void 0 || isMatchingPattern(errorInfo.name, matcher.name, true);
const messageMatches = matcher.message === void 0 || isMatchingPattern(errorInfo.message, matcher.message);
return nameMatches && messageMatches;
}
function matchesIgnore(list, reason) {
const errorInfo = extractErrorInfo(reason);
return list.some((matcher) => isMatchingReason(matcher, errorInfo));
}
function makeUnhandledPromiseHandler(client, options) {
return function sendUnhandledPromise(reason, _promise) {
if (getClient() !== client) {
return;
}
if (matchesIgnore(options.ignore ?? [], reason)) {
return;
}
const level = options.mode === "strict" ? "fatal" : "error";
const activeSpanForError = isObjectLike(reason) ? reason._sentry_active_span : void 0;
const activeSpanWrapper = activeSpanForError ? (fn) => withActiveSpan(activeSpanForError, fn) : (fn) => fn();
activeSpanWrapper(() => {
captureException(reason, {
originalException: reason,
captureContext: {
extra: { unhandledPromiseRejection: true },
level
},
mechanism: {
handled: false,
type: "auto.node.onunhandledrejection"
}
});
});
handleRejection(reason, options.mode);
};
}
function handleRejection(reason, mode) {
const rejectionWarning = "This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:";
if (mode === "warn") {
consoleSandbox(() => {
console.warn(rejectionWarning);
console.error(isObjectLike(reason) && "stack" in reason ? reason.stack : reason);
});
} else if (mode === "strict") {
if (!(isObjectLike(reason) && "stack" in reason)) {
consoleSandbox(() => {
console.warn(rejectionWarning);
});
}
logAndExitProcess(reason);
}
}
export { makeUnhandledPromiseHandler, onUnhandledRejectionIntegration };
//# sourceMappingURL=onunhandledrejection.js.map