UNPKG

rollbar

Version:

Effortlessly track and debug errors in your JavaScript applications with Rollbar. This package includes advanced error tracking features and an intuitive interface to help you identify and fix issues more quickly.

198 lines (174 loc) 4.88 kB
var http = require('http'); var https = require('https'); var _ = require('../utility'); var replace = require('../utility/replace'); var urlHelpers = require('./telemetry/urlHelpers'); var defaults = { network: true, networkResponseHeaders: false, networkRequestHeaders: false, log: true, }; function Instrumenter(options, telemeter, rollbar) { this.options = options; var autoInstrument = options.autoInstrument; if (options.enabled === false || autoInstrument === false) { this.autoInstrument = {}; } else { if (!_.isType(autoInstrument, 'object')) { autoInstrument = defaults; } this.autoInstrument = _.merge(defaults, autoInstrument); } this.telemeter = telemeter; this.rollbar = rollbar; this.diagnostic = rollbar.client.notifier.diagnostic; this.replacements = { network: [], log: [], }; } Instrumenter.prototype.configure = function (options) { this.options = _.merge(this.options, options); var autoInstrument = options.autoInstrument; var oldSettings = _.merge(this.autoInstrument); if (options.enabled === false || autoInstrument === false) { this.autoInstrument = {}; } else { if (!_.isType(autoInstrument, 'object')) { autoInstrument = defaults; } this.autoInstrument = _.merge(defaults, autoInstrument); } this.instrument(oldSettings); }; Instrumenter.prototype.instrument = function (oldSettings) { if (this.autoInstrument.network && !(oldSettings && oldSettings.network)) { this.instrumentNetwork(); } else if ( !this.autoInstrument.network && oldSettings && oldSettings.network ) { this.deinstrumentNetwork(); } if (this.autoInstrument.log && !(oldSettings && oldSettings.log)) { this.instrumentConsole(); } else if (!this.autoInstrument.log && oldSettings && oldSettings.log) { this.deinstrumentConsole(); } }; Instrumenter.prototype.deinstrumentNetwork = function () { restore(this.replacements, 'network'); }; Instrumenter.prototype.instrumentNetwork = function () { replace( http, 'request', networkRequestWrapper.bind(this), this.replacements, 'network', ); replace( https, 'request', networkRequestWrapper.bind(this), this.replacements, 'network', ); }; function networkRequestWrapper(orig) { var telemeter = this.telemeter; var self = this; return function (url, options, cb) { var mergedOptions = urlHelpers.mergeOptions(url, options, cb); var metadata = { method: mergedOptions.options.method || 'GET', url: urlHelpers.constructUrl(mergedOptions.options), status_code: null, start_time_ms: _.now(), end_time_ms: null, }; if (self.autoInstrument.networkRequestHeaders) { metadata.request_headers = mergedOptions.options.headers; } telemeter.captureNetwork(metadata, 'http'); // Call the original method with the original arguments and wrapped callback. var wrappedArgs = Array.from(arguments); var wrappedCallback = responseCallbackWrapper( self.autoInstrument, metadata, mergedOptions.cb, ); if (mergedOptions.cb) { wrappedArgs.pop(); } wrappedArgs.push(wrappedCallback); var req = orig.apply(https, wrappedArgs); req.on('error', (err) => { metadata.status_code = 0; metadata.error = [err.name, err.message].join(': '); }); return req; }; } function responseCallbackWrapper(options, metadata, callback) { return function (res) { metadata.end_time_ms = _.now(); metadata.status_code = res.statusCode; metadata.response = {}; if (options.networkResponseHeaders) { metadata.response.headers = res.headers; } if (callback) { return callback.apply(undefined, arguments); } }; } Instrumenter.prototype.captureNetwork = function ( metadata, subtype, rollbarUUID, ) { return this.telemeter.captureNetwork(metadata, subtype, rollbarUUID); }; Instrumenter.prototype.deinstrumentConsole = function () { restore(this.replacements, 'log'); }; Instrumenter.prototype.instrumentConsole = function () { var telemeter = this.telemeter; var stdout = process.stdout; replace( stdout, 'write', function (orig) { return function (string) { telemeter.captureLog(string, 'info'); return orig.apply(stdout, arguments); }; }, this.replacements, 'log', ); var stderr = process.stderr; replace( stderr, 'write', function (orig) { return function (string) { telemeter.captureLog(string, 'error'); return orig.apply(stderr, arguments); }; }, this.replacements, 'log', ); }; function restore(replacements, type) { var b; while (replacements[type].length) { b = replacements[type].shift(); b[0][b[1]] = b[2]; } } module.exports = Instrumenter;