mirror of
https://github.com/Unitech/pm2.git
synced 2025-12-08 20:35:53 +00:00
(interactor) find context by finding error callsite with regex
This commit is contained in:
parent
6d5f5bff1e
commit
840865ec1d
@ -92,43 +92,90 @@ function StackTraceParser (opts) {
|
||||
this._context_size = opts.context;
|
||||
}
|
||||
|
||||
StackTraceParser.prototype.attachContext = function (error) {
|
||||
var self = this;
|
||||
if (!error) return error;
|
||||
|
||||
// if pmx attached callsites we can parse them to retrieve the context
|
||||
if (typeof (error.stackframes) === 'object') {
|
||||
var result = self.parse(error.stackframes);
|
||||
// no need to send it since there is already the stacktrace
|
||||
delete error.stackframes;
|
||||
delete error.__error_callsites;
|
||||
|
||||
if (result) {
|
||||
error.callsite = result.callsite;
|
||||
error.context = result.context;
|
||||
}
|
||||
}
|
||||
// if the stack is here we can parse it directly from the stack string
|
||||
// only if the context has been retrieved from elsewhere
|
||||
if (typeof error.stack === 'string' && !error.callsite) {
|
||||
var siteRegex = /(\/[^\\\n]*)/g;
|
||||
var tmp;
|
||||
var stack = [];
|
||||
|
||||
// find matching groups
|
||||
while ((tmp = siteRegex.exec(error.stack))) {
|
||||
stack.push(tmp[1]);
|
||||
}
|
||||
|
||||
// parse each callsite to match the format used by the stackParser
|
||||
stack = stack.map(function (callsite) {
|
||||
// remove the trailing ) if present
|
||||
if (callsite[callsite.length - 1] === ')') {
|
||||
callsite = callsite.substr(0, callsite.length - 1);
|
||||
}
|
||||
var location = callsite.split(':');
|
||||
|
||||
return location.length < 3 ? callsite : {
|
||||
file_name: location[0],
|
||||
line_number: parseInt(location[1])
|
||||
};
|
||||
});
|
||||
|
||||
var finalCallsite = self.parse(stack);
|
||||
if (finalCallsite) {
|
||||
error.callsite = finalCallsite.callsite;
|
||||
error.context = finalCallsite.context;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse the stacktrace and return callsite + context if available
|
||||
*/
|
||||
StackTraceParser.prototype.parse = function (stack) {
|
||||
var self = this;
|
||||
if (!stack || stack.length == 0)
|
||||
return false;
|
||||
if (!stack || stack.length === 0) return false;
|
||||
|
||||
for (var i = 0, len = stack.length; i < len; i++) {
|
||||
var callsite = stack[i];
|
||||
|
||||
// avoid null values
|
||||
if (!callsite ||
|
||||
!callsite.file_name ||
|
||||
!callsite.line_number)
|
||||
continue;
|
||||
if (typeof callsite !== 'object') continue;
|
||||
if (!callsite.file_name || !callsite.line_number) continue;
|
||||
|
||||
var type = (!path.isAbsolute(callsite.file_name) && callsite.file_name[0] !== '.') ? 'core' : 'user'
|
||||
var type = path.isAbsolute(callsite.file_name) || callsite.file_name[0] === '.' ? 'user' : 'core';
|
||||
|
||||
// only use the callsite if its inside user space
|
||||
if (!callsite ||
|
||||
type === 'core' ||
|
||||
callsite.file_name.indexOf('node_modules') > -1 ||
|
||||
callsite.file_name.indexOf('vxx') > -1)
|
||||
if (!callsite || type === 'core' || callsite.file_name.indexOf('node_modules') > -1 ||
|
||||
callsite.file_name.indexOf('vxx') > -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the whole context (all lines) and cache them if necessary
|
||||
var context = self._cache.get(callsite.file_name)
|
||||
var source = []
|
||||
var context = self._cache.get(callsite.file_name);
|
||||
var source = [];
|
||||
if (context && context.length > 0) {
|
||||
// get line before the call
|
||||
var preLine = callsite.line_number - self._context_size - 1;
|
||||
var pre = context.slice(preLine > 0 ? preLine : 0, callsite.line_number - 1);
|
||||
if (pre && pre.length > 0) {
|
||||
pre.forEach(function (line) {
|
||||
source.push(line.replace(/\t/g, ' '))
|
||||
})
|
||||
source.push(line.replace(/\t/g, ' '));
|
||||
});
|
||||
}
|
||||
// get the line where the call has been made
|
||||
if (context[callsite.line_number - 1]) {
|
||||
@ -136,23 +183,23 @@ StackTraceParser.prototype.parse = function (stack) {
|
||||
}
|
||||
// and get the line after the call
|
||||
var postLine = callsite.line_number + self._context_size;
|
||||
var post = context.slice(callsite.line_number, postLine)
|
||||
var post = context.slice(callsite.line_number, postLine);
|
||||
if (post && post.length > 0) {
|
||||
post.forEach(function (line) {
|
||||
source.push(line.replace(/\t/g, ' '))
|
||||
})
|
||||
}
|
||||
return {
|
||||
context: source.join('\n'),
|
||||
callsite: [ callsite.file_name, callsite.line_number ].join(':')
|
||||
source.push(line.replace(/\t/g, ' '));
|
||||
});
|
||||
}
|
||||
}
|
||||
return {
|
||||
context: source.length > 0 ? source.join('\n') : 'cannot retrieve source context',
|
||||
callsite: [ callsite.file_name, callsite.line_number ].join(':')
|
||||
};
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
EWMA: EWMA,
|
||||
Cache: Cache,
|
||||
StackTraceParser: StackTraceParser
|
||||
}
|
||||
};
|
||||
|
||||
@ -5,6 +5,7 @@ var Utility = require('../../lib/Interactor/Utility.js');
|
||||
var TraceFactory = require('./misc/trace_factory.js');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var assert = require('assert');
|
||||
|
||||
describe('StackTrace Utility', function() {
|
||||
var aggregator;
|
||||
@ -29,7 +30,7 @@ describe('StackTrace Utility', function() {
|
||||
aggregator = new Aggregator({ stackParser: stackParser});
|
||||
});
|
||||
|
||||
describe('.parseStacktrace', function() {
|
||||
describe('.parse', function() {
|
||||
it('should parse stacktrace and get context', function(done) {
|
||||
var obj = [{
|
||||
labels: {
|
||||
@ -125,4 +126,32 @@ describe('StackTrace Utility', function() {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('.attachContext', function () {
|
||||
it('should extract context from stackframes', function () {
|
||||
var error = stackParser.attachContext({
|
||||
stackframes: [
|
||||
{
|
||||
file_name: '/toto/tmp/lol',
|
||||
line_number: 10
|
||||
}
|
||||
]
|
||||
});
|
||||
assert(error !== undefined);
|
||||
assert(error.stackframes === undefined);
|
||||
assert(error.callsite !== undefined);
|
||||
assert(error.callsite.indexOf('/toto/tmp/lol') >= 0);
|
||||
});
|
||||
|
||||
it('should extract context from the stack string', function () {
|
||||
var error = new Error();
|
||||
// stack is lazy so we need to load it
|
||||
error.stack = error.stack;
|
||||
error = stackParser.attachContext(error);
|
||||
assert(error !== undefined);
|
||||
assert(error.stackframes === undefined);
|
||||
assert(error.callsite.indexOf(__filename) >= 0);
|
||||
assert(error.context.indexOf('var error = new Error()') >= 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user