in lib/stacktraces.js [134:348]
filename: getRelativeFileName(filename, cwd),
function: frame.getFunctionName(),
lineno: frame.getLineNumber(),
library_frame: !isStackFrameApp(frame),
abs_path: filename,
});
}
}
return stacktrace;
}
const NODE_MODULES_PATH_SEG = 'node_modules' + path.sep;
// Return true iff the given StackFrame
// (https://github.com/stacktracejs/stackframe) is an application frame.
function isStackFrameApp(stackframe) {
if (isStackFrameNode(stackframe)) {
return false;
} else {
const fileName = filePathFromCallSite(stackframe);
if (!fileName) {
return true;
} else if (fileName.indexOf(NODE_MODULES_PATH_SEG) === -1) {
return true;
} else {
return false;
}
}
}
// Return true iff the given StackFrame
// (https://github.com/stacktracejs/stackframe) is a Node frame.
function isStackFrameNode(stackframe) {
if (stackframe.isNative) {
return true;
} else {
const fileName = filePathFromCallSite(stackframe);
if (!fileName) {
return true;
} else {
return !path.isAbsolute(fileName) && fileName[0] !== '.';
}
}
}
function isCallSiteApp(callsite) {
if (isCallSiteNode(callsite)) {
return false;
} else {
const fileName = filePathFromCallSite(callsite);
if (!fileName) {
return true;
} else if (fileName.indexOf(NODE_MODULES_PATH_SEG) === -1) {
return true;
} else {
return false;
}
}
}
function isCallSiteNode(callsite) {
if (callsite.isNative()) {
return true;
} else {
const fileName = filePathFromCallSite(callsite);
if (!fileName) {
return true;
} else {
return !path.isAbsolute(fileName) && fileName[0] !== '.';
}
}
}
function isValidCallsites(callsites) {
return (
Array.isArray(callsites) &&
callsites.length > 0 &&
typeof callsites[0] === 'object' &&
typeof callsites[0].getFileName === 'function'
);
}
// From stackman getTypeNameSafely().
function getCallSiteTypeNameSafely(callsite) {
try {
return callsite.getTypeName();
} catch (e) {
// This seems to happen sometimes when using 'use strict',
// stemming from `getTypeName`.
// [TypeError: Cannot read property 'constructor' of undefined]
return null;
}
}
// From stackman getFunctionNameSanitized().
function getCallSiteFunctionNameSanitized(callsite) {
var fnName = callsite.getFunctionName();
if (fnName) return fnName;
var typeName = getCallSiteTypeNameSafely(callsite);
if (typeName)
return typeName + '.' + (callsite.getMethodName() || '<anonymous>');
return '<anonymous>';
}
function addSourceContextToFrame(frame, lines, lineNum, n) {
var index = lineNum - 1; // lines 1-based -> index 0-based
var nBefore = Math.ceil((n - 1) / 2);
var nAfter = Math.floor((n - 1) / 2);
frame.pre_context = lines.slice(Math.max(0, index - nBefore), index);
frame.context_line = lines[index];
frame.post_context = lines.slice(index + 1, index + 1 + nAfter);
}
// Get the path of `filename` relative to `relTo` -- which should be a directory
// path *without* a trailing path separator.
function getRelativeFileName(filename, relTo) {
if (filename.startsWith(relTo + path.sep)) {
return filename.slice(relTo.length + 1);
} else {
return filename;
}
}
async function getSourceMapConsumer(callsite) {
if (isCallSiteNode(callsite)) {
return null;
} else {
var filename = filePathFromCallSite(callsite);
if (!filename) {
return null;
} else {
return sourceMapCache.fetch(filename);
}
}
}
// Put together an APM stacktrace frame object:
// {
// "filename": "...",
// "lineno": 65,
// "function": "...",
// "library_frame": <bool>,
// "abs_path": "...",
// "pre_context": [ ... ],
// "context_line": "...",
// "post_context": [ ... ],
// },
// from a v8 CallSite object
// (https://v8.dev/docs/stack-trace-api#customizing-stack-traces).
//
// This asynchronously returns the call frame object. Getting source context
// is best-effort, so the returned Promise never rejects.
async function frameFromCallSite(
log,
callsite,
cwd,
sourceLinesAppFrames,
sourceLinesLibraryFrames,
) {
// getFileName can return null, e.g. with a `at Generator.next (<anonymous>)` frame.
const filename = filePathFromCallSite(callsite) || '';
const lineno = callsite.getLineNumber();
const colno = callsite.getColumnNumber();
// Caching
const cacheKey = [
filename,
lineno,
colno,
sourceLinesAppFrames,
sourceLinesLibraryFrames,
].join(':');
const cachedFrame = frameCache.get(cacheKey);
if (cachedFrame !== undefined) {
frameCacheStats.hits++;
// Guard against later JSON serialization mistakenly changing duplicate
// frames in a stacktrace (a totally legal thing) into '[Circular]' as a
// guard against serializing an object with circular references.
const clonedFrame = Object.assign({}, cachedFrame);
if (clonedFrame.pre_context) {
clonedFrame.pre_context = clonedFrame.pre_context.slice();
}
if (clonedFrame.post_context) {
clonedFrame.post_context = clonedFrame.post_context.slice();
}
return clonedFrame;
}
function cacheIt(frame) {
frameCacheStats.misses++;
frameCache.set(cacheKey, frame);
}
let mappedFilename = null;
let absMappedFilename = null;
let mappedLineno = null;
// If the file has a sourcemap, we use that for: filename, lineno, source
// context.
let sourceMapConsumer = null;
try {
sourceMapConsumer = await getSourceMapConsumer(callsite);
} catch (sourceMapErr) {
log.debug(
{ filename, err: sourceMapErr },
'could not process file source map',
);
}
if (sourceMapConsumer) {
let pos;
try {
pos = sourceMapConsumer.originalPositionFor({