in lib/stacktraces.js [287:452]
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({
line: lineno,
column: colno,
});
} catch (posErr) {
log.debug(
{ filename, line: lineno, err: posErr },
'could not get position from sourcemap',
);
pos = {
source: null,
line: null,
column: null,
name: null,
};
}
if (pos.source !== null) {
mappedFilename = pos.source;
absMappedFilename = path.resolve(path.dirname(filename), mappedFilename);
}
if (pos.line !== null) {
mappedLineno = pos.line;
}
// TODO: Is `pos.name` relevant for `frame.function` if minifying?
}
const isApp = isCallSiteApp(callsite);
const frame = {
filename: getRelativeFileName(absMappedFilename || filename, cwd),
lineno: mappedLineno || lineno,
function: getCallSiteFunctionNameSanitized(callsite),
library_frame: !isApp,
};
if (!Number.isFinite(frame.lineno)) {
// An early comment in stackman suggested this is "sometimes not" an int.
frame.lineno = 0;
}
if (filename) {
frame.abs_path = absMappedFilename || filename;
}
// Finish early if we do not need to collect source lines of context.
var linesOfContext = isApp ? sourceLinesAppFrames : sourceLinesLibraryFrames;
if (linesOfContext === 0 || !filename || isCallSiteNode(callsite)) {
cacheIt(frame);
return frame;
}
// Attempt to use "sourcesContent" in a sourcemap, if available.
if (sourceMapConsumer && mappedFilename && mappedLineno) {
// To use `sourceMapConsumer.sourceContentFor` we need the filename as
// it is in the "sources" field of the source map. `mappedFilename`,
// from `sourceMapConsume.originalPositionFor` above, was made relative
// to "sourceRoot" -- sourceFilename undoes that.
const sourceFilename = sourceMapConsumer.sourceRoot
? path.relative(sourceMapConsumer.sourceRoot, mappedFilename)
: mappedFilename;
var source = sourceMapConsumer.sourceContentFor(sourceFilename, true);
log.trace(
{
sourceRoot: sourceMapConsumer.sourceRoot,
mappedFilename,
sourceFilename,
haveSourceContent: !!source,
},
'sourcemap sourceContent lookup',
);
if (source) {
addSourceContextToFrame(
frame,
source.split(/\r?\n/g),
mappedLineno,
linesOfContext,
);
cacheIt(frame);
return frame;
}
}
// If the file looks like it minimized (as we didn't have a source-map in
// the processing above), then skip adding source context because it
// is mostly useless and the typically 500-char lines result in over-large
// APM error objects.
if (filename.endsWith('.min.js')) {
cacheIt(frame);
return frame;
}
// Otherwise load the file from disk, if available.
let lines;
try {
lines = await fileCache.fetch(frame.abs_path);
} catch (fileErr) {
log.debug(
{ filename: frame.abs_path, err: fileErr },
'could not read file for source context',
);
}
if (lines) {
addSourceContextToFrame(frame, lines, frame.lineno, linesOfContext);
}
cacheIt(frame);
return frame;
}