motion
Version:
motion - moving development forward
180 lines (150 loc) • 5.65 kB
JavaScript
var raven = require('./client');
var fs = require('fs');
var url = require('url');
var transports = require('./transports');
var path = require('path');
var lsmod = require('lsmod');
var stacktrace = require('stack-trace');
var protocolMap = {
'http': 80,
'https': 443
};
module.exports.getAuthHeader = function getAuthHeader(timestamp, api_key, api_secret) {
var header = ['Sentry sentry_version=5'];
header.push('sentry_timestamp='+timestamp);
header.push('sentry_client=raven-node/'+raven.version);
header.push('sentry_key='+api_key);
header.push('sentry_secret='+api_secret);
return header.join(', ');
};
module.exports.parseDSN = function parseDSN(dsn) {
if(!dsn) {
// Let a falsey value return false explicitly
return false;
}
try {
var parsed = url.parse(dsn),
response = {
protocol: parsed.protocol.slice(0, -1),
public_key: parsed.auth.split(':')[0],
private_key: parsed.auth.split(':')[1],
host: parsed.host.split(':')[0]
};
if (~response.protocol.indexOf('+')) {
response.protocol = response.protocol.split('+')[1];
}
if(!transports.hasOwnProperty(response.protocol)) {
throw new Error('Invalid transport');
}
var index = parsed.pathname.lastIndexOf('/');
response.path = parsed.pathname.substr(0, index+1);
response.project_id = parsed.pathname.substr(index+1);
response.port = ~~parsed.port || protocolMap[response.protocol] || 443;
return response;
} catch(e) {
throw new Error('Invalid Sentry DSN: ' + dsn);
}
};
module.exports.getCulprit = function getCulprit(frame) {
if (frame.module || frame['function'])
return (frame.module || '?') + ' at ' + (frame['function'] || '?');
return '<unknown>';
};
var module_cache;
module.exports.getModules = function getModules() {
if (module_cache) {
return module_cache;
}
return module_cache = lsmod();
};
var LINES_OF_CONTEXT = 7;
function getFunction(line) {
try {
return line.getFunctionName() ||
line.getTypeName() + '.' + (line.getMethodName() || '<anonymous>');
} catch(e) {
// This seems to happen sometimes when using 'use strict',
// stemming from `getTypeName`.
// [TypeError: Cannot read property 'constructor' of undefined]
return '<anonymous>';
}
}
var main_module = (require.main && path.dirname(require.main.filename) || process.cwd()) + '/';
function getModule(filename, base) {
if (!base) base = main_module;
// It's specifically a module
var file = path.basename(filename, '.js');
filename = path.dirname(filename);
var n = filename.lastIndexOf('/node_modules/');
if (n > -1) {
// /node_modules/ is 14 chars
return filename.substr(n + 14).replace(/\//g, '.') + ':' + file;
}
// Let's see if it's a part of the main module
// To be a part of main module, it has to share the same base
n = (filename + '/').lastIndexOf(base, 0);
if (n === 0) {
var module = filename.substr(base.length).replace(/\//g, '.');
if (module) module += ':';
module += file;
return module
}
return file;
}
function parseStack(err, cb) {
var frames = [],
cache = {}
if (!err) {
return cb(frames);
}
var stack = stacktrace.parse(err);
// check to make sure that the stack is what we need it to be.
if (!stack || !Array.isArray(stack) || !stack.length || !stack[0].getFileName) {
// lol, stack is fucked
return cb(frames);
}
var callbacks = stack.length;
// Sentry requires the stack trace to be from oldest to newest
stack.reverse();
stack.forEach(function(line, index) {
var frame = {
filename: line.getFileName() || '',
lineno: line.getLineNumber(),
'function': getFunction(line),
}, isInternal = line.isNative() ||
(frame.filename[0] !== '/' &&
frame.filename[0] !== '.');
// in_app is all that's not an internal Node function or a module within node_modules
frame.in_app = !isInternal && !~frame.filename.indexOf('node_modules/');
// Extract a module name based on the filename
if (frame.filename) frame.module = getModule(frame.filename);
// internal Node files are not full path names. Ignore them.
if (isInternal) {
frames[index] = frame;
if (--callbacks === 0) cb(frames);
return;
}
if (frame.filename in cache) {
parseLines(cache[frame.filename]);
if (--callbacks === 0) cb(frames);
return;
}
fs.readFile(frame.filename, function(err, file) {
if (!err) {
file = file.toString().split('\n');
cache[frame.filename] = file;
parseLines(file, frame);
}
frames[index] = frame;
if (--callbacks === 0) cb(frames);
});
function parseLines(lines) {
frame.pre_context = lines.slice(Math.max(0, frame.lineno-(LINES_OF_CONTEXT+1)), frame.lineno-1);
frame.context_line = lines[frame.lineno-1];
frame.post_context = lines.slice(frame.lineno, frame.lineno+LINES_OF_CONTEXT);
}
});
}
// expose basically for testing because I don't know what I'm doing
module.exports.parseStack = parseStack;
module.exports.getModule = getModule;