UNPKG

applicationinsights

Version:

Microsoft Application Insights module for Node.js

131 lines 6.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseStack = exports._StackFrame = exports.AutoCollectExceptions = void 0; // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for details. const api_logs_1 = require("@opentelemetry/api-logs"); const util_1 = require("../shared/util"); const UNCAUGHT_EXCEPTION_HANDLER_NAME = "uncaughtException"; const UNHANDLED_REJECTION_HANDLER_NAME = "unhandledRejection"; const FALLBACK_ERROR_MESSAGE = "A promise was rejected without providing an error. Application Insights generated this error stack for you."; class AutoCollectExceptions { constructor(client) { this._client = client; this._exceptionListenerHandle = this._handleException.bind(this, true, UNCAUGHT_EXCEPTION_HANDLER_NAME); this._rejectionListenerHandle = this._handleException.bind(this, false, UNHANDLED_REJECTION_HANDLER_NAME); // never rethrows process.on(UNCAUGHT_EXCEPTION_HANDLER_NAME, this._exceptionListenerHandle); process.on(UNHANDLED_REJECTION_HANDLER_NAME, this._rejectionListenerHandle); } shutdown() { if (this._exceptionListenerHandle) { if (this._exceptionListenerHandle) { process.removeListener(UNCAUGHT_EXCEPTION_HANDLER_NAME, this._exceptionListenerHandle); } if (this._rejectionListenerHandle) { process.removeListener(UNHANDLED_REJECTION_HANDLER_NAME, this._rejectionListenerHandle); } } this._exceptionListenerHandle = undefined; this._rejectionListenerHandle = undefined; delete this._exceptionListenerHandle; delete this._rejectionListenerHandle; } _handleException(reThrow, name, error = new Error(FALLBACK_ERROR_MESSAGE)) { if (this._client) { this._client.trackException({ exception: error }); try { api_logs_1.logs.getLoggerProvider().forceFlush().then(() => { // only rethrow when we are the only listener if (reThrow && name && process.listeners(name).length === 1) { // eslint-disable-next-line no-console console.error(error); // eslint-disable-next-line no-process-exit process.exit(1); } }); } catch (error) { console.error(`Could not get the loggerProvider upon handling a tracked exception: ${error}`); } } else { // eslint-disable-next-line no-console console.error(error); process.exit(1); } } } exports.AutoCollectExceptions = AutoCollectExceptions; // regex to match stack frames from ie/chrome/ff // methodName=$2, fileName=$4, lineNo=$5, column=$6 const stackFramesRegex = /^(\s+at)?(.*?)(\@|\s\(|\s)([^\(\n]+):(\d+):(\d+)(\)?)$/; class _StackFrame { constructor(frame, level) { this.sizeInBytes = 0; this._baseSize = 58; //'{"method":"","level":,"assembly":"","fileName":"","line":}'.length this.level = level; this.method = "<no_method>"; this.assembly = util_1.Util.getInstance().trim(frame); const matches = frame.match(stackFramesRegex); if (matches && matches.length >= 5) { this.method = util_1.Util.getInstance().trim(matches[2]) || this.method; this.fileName = util_1.Util.getInstance().trim(matches[4]) || "<no_filename>"; this.line = parseInt(matches[5]) || 0; } this.sizeInBytes += this.method.length; this.sizeInBytes += this.fileName.length; this.sizeInBytes += this.assembly.length; // todo: these might need to be removed depending on how the back-end settles on their size calculation this.sizeInBytes += this._baseSize; this.sizeInBytes += this.level.toString().length; this.sizeInBytes += this.line.toString().length; } } exports._StackFrame = _StackFrame; function parseStack(stack) { let parsedStack = undefined; if (typeof stack === "string") { const frames = stack.split("\n"); parsedStack = []; let level = 0; let totalSizeInBytes = 0; for (let i = 0; i <= frames.length; i++) { const frame = frames[i]; if (stackFramesRegex.test(frame)) { const parsedFrame = new _StackFrame(frames[i], level++); totalSizeInBytes += parsedFrame.sizeInBytes; parsedStack.push(parsedFrame); } } // DP Constraint - exception parsed stack must be < 32KB // remove frames from the middle to meet the threshold const exceptionParsedStackThreshold = 32 * 1024; if (totalSizeInBytes > exceptionParsedStackThreshold) { let left = 0; let right = parsedStack.length - 1; let size = 0; let acceptedLeft = left; let acceptedRight = right; while (left < right) { // check size const lSize = parsedStack[left].sizeInBytes; const rSize = parsedStack[right].sizeInBytes; size += lSize + rSize; if (size > exceptionParsedStackThreshold) { // remove extra frames from the middle const howMany = acceptedRight - acceptedLeft + 1; parsedStack.splice(acceptedLeft, howMany); break; } // update pointers acceptedLeft = left; acceptedRight = right; left++; right--; } } } return parsedStack; } exports.parseStack = parseStack; //# sourceMappingURL=exceptions.js.map