backtrace-node
Version:
Backtrace error reporting tool
294 lines • 12.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var crypto_1 = require("crypto");
var application_1 = require("../const/application");
var machineId_1 = require("../helpers/machineId");
var moduleResolver_1 = require("../helpers/moduleResolver");
var processHelper_1 = require("../helpers/processHelper");
var utils_1 = require("../utils");
var backtraceStackTrace_1 = require("./backtraceStackTrace");
/**
* BacktraceReport describe current exception/message payload message to Backtrace
*/
var BacktraceReport = /** @class */ (function () {
/**
* Create new BacktraceReport - report information that will collect information
* for Backtrace.
*
* Possible existing scenarios:
* arg1: error + arg2: attributes = all required
* arg1: object, arg2: nothing
*
* @param err Error or message - content to report
* @param attributes Report attributes dictionary
* @param attachments Report attachments that Backtrace will send to API
*/
function BacktraceReport(data, clientAttributes, attachments) {
if (data === void 0) { data = ''; }
if (clientAttributes === void 0) { clientAttributes = {}; }
if (attachments === void 0) { attachments = []; }
this.data = data;
this.clientAttributes = clientAttributes;
this.attachments = attachments;
// reprot id
this.uuid = this.generateUuid();
// timestamp
this.timestamp = utils_1.currentTimestamp();
// lang
this.lang = application_1.LANG;
// environment version
this.langVersion = process.version;
// Backtrace-ndoe name
this.agent = application_1.APP_NAME;
// Backtrace-node version
this.agentVersion = application_1.VERSION;
// main thread name
this.mainThread = application_1.THREAD;
this.classifiers = [];
this._symbolication = false;
/**
* Current report attributes
*/
this.attributes = {};
/**
* Backtrace complex objet
*/
this.annotations = {};
this.tabWidth = 8;
this.contextLineCount = 200;
if (!clientAttributes) {
clientAttributes = {};
}
this.splitAttributesFromAnnotations(clientAttributes);
if (!attachments) {
attachments = [];
}
this.setError(data);
}
Object.defineProperty(BacktraceReport.prototype, "symbolication", {
set: function (symbolication) {
this._symbolication = symbolication;
},
enumerable: true,
configurable: true
});
Object.defineProperty(BacktraceReport.prototype, "symbolicationMap", {
set: function (symbolMap) {
if (!symbolMap) {
throw new Error('Symbolication map is undefined');
}
if (!Array.isArray(symbolMap)) {
throw new TypeError('Invalid type of symbolication map');
}
var invalidValues = symbolMap.some(function (n) { return !n.file || !n.uuid; });
if (invalidValues) {
throw new TypeError('Symbolication map contains invalid values - missing file or uuid value');
}
this._symbolicationMap = symbolMap;
},
enumerable: true,
configurable: true
});
/**
* Check if report contains exception information
*/
BacktraceReport.prototype.isExceptionTypeReport = function () {
return this.detectReportType(this.data);
};
BacktraceReport.prototype.getPayload = function () {
return this.data;
};
/**
* Set error or message in BacktraceReport object
* @param err Current error
*/
BacktraceReport.prototype.setError = function (err) {
this.data = err;
if (this.detectReportType(err)) {
this.err = err;
this.classifiers = [err.name];
}
else {
this.err = new Error(err);
this.classifiers = [];
}
};
/**
* @deprecated
* Please don't use log method in new BacktraceReport object.
*/
BacktraceReport.prototype.log = function () {
console.warn('log method is deprecated.');
};
/**
* @deprecated
* Please don't use trace method in new BacktraceReport object
*/
BacktraceReport.prototype.trace = function () {
console.warn('trace method is deprecated.');
};
/**
* Add new attributes to existing report attributes
* @param attributes new report attributes object
*/
BacktraceReport.prototype.addObjectAttributes = function (attributes) {
this.clientAttributes = tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, this.clientAttributes), this.attributes), attributes);
};
BacktraceReport.prototype.addAttribute = function (key, value) {
this.clientAttributes[key] = value;
};
BacktraceReport.prototype.addAnnotation = function (key, value) {
this.annotations[key] = value;
};
BacktraceReport.prototype.getAttachments = function () {
return this.attachments;
};
BacktraceReport.prototype.toJson = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var result;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
// why library should wait to retrieve source code data?
// architecture decision require to pass additional parameters
// not in constructor, but in additional method.
return [4 /*yield*/, this.collectReportInformation()];
case 1:
// why library should wait to retrieve source code data?
// architecture decision require to pass additional parameters
// not in constructor, but in additional method.
_a.sent();
result = {
uuid: this.uuid,
timestamp: this.timestamp,
lang: this.lang,
langVersion: this.langVersion,
mainThread: this.mainThread,
classifiers: this.classifiers,
threads: { main: this.stackTrace.toJson() },
agent: this.agent,
agentVersion: this.agentVersion,
annotations: this.annotations,
attributes: this.attributes,
sourceCode: this.stackTrace.getSourceCode(),
symbolication_maps: this._symbolicationMap || this.stackTrace.symbolicationMaps,
};
// when symbolication information exists, set symbolication to sourcemap.
// we should check symbolicationMap and _symbolication boolean value and symbolication id from attributes
// if any value exists, we should extend report object with 'sourcemap' property.
if (this._symbolication || this.attributes['symbolication_id'] || this._symbolicationMap) {
result.symbolication = 'sourcemap';
}
return [2 /*return*/, result];
}
});
});
};
BacktraceReport.prototype.setSourceCodeOptions = function (tabWidth, contextLineCount) {
this.tabWidth = tabWidth;
this.contextLineCount = contextLineCount;
};
/**
* Include symbolication information based on stack trace analysis
*/
BacktraceReport.prototype.includeSymbolication = function () {
return this._symbolication && !this.attributes['symbolication_id'] && !this._symbolicationMap;
};
BacktraceReport.prototype.collectReportInformation = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
// get stack trace to retrieve calling module information
this.stackTrace = new backtraceStackTrace_1.BacktraceStackTrace(this.err);
this.stackTrace.setSourceCodeOptions(this.tabWidth, this.contextLineCount);
return [4 /*yield*/, this.stackTrace.parseStackFrames(this.includeSymbolication())];
case 1:
_b.sent();
// retrieve calling module object
if (!this.attributes.hasOwnProperty('application')) {
_a = moduleResolver_1.readModule(this.stackTrace.getCallingModulePath()), this._callingModule = _a[0], this._callingModulePath = _a[1];
}
// combine attributes
this.attributes = tslib_1.__assign(tslib_1.__assign({}, this.readBuiltInAttributes()), this.clientAttributes);
// combine annotations
this.annotations = this.readAnnotation();
return [2 /*return*/];
}
});
});
};
BacktraceReport.prototype.readBuiltInAttributes = function () {
return tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, processHelper_1.readMemoryInformation()), processHelper_1.readProcessStatus()), this.readAttributes()), this.readErrorAttributes());
};
BacktraceReport.prototype.detectReportType = function (err) {
return err instanceof Error;
};
BacktraceReport.prototype.generateUuid = function () {
var bytes = crypto_1.pseudoRandomBytes(16);
return (bytes.slice(0, 4).toString('hex') +
'-' +
bytes.slice(4, 6).toString('hex') +
'-' +
bytes.slice(6, 8).toString('hex') +
'-' +
bytes.slice(8, 10).toString('hex') +
'-' +
bytes.slice(10, 16).toString('hex'));
};
BacktraceReport.prototype.readErrorAttributes = function () {
if (!this.detectReportType(this.err)) {
return {
'error.message': this.err,
};
}
this.classifiers = [this.err.name];
return {
'error.message': this.err.message,
};
};
BacktraceReport.prototype.readAttributes = function () {
var result = moduleResolver_1.readSystemAttributes();
if (this._callingModule) {
var _a = (this._callingModule || {}), name_1 = _a.name, version = _a.version, main = _a.main, description = _a.description, author = _a.author;
result['name'] = name_1;
result['version'] = version;
result['main'] = main;
result['description'] = description;
result['author'] = typeof author === 'object' && author.name ? author.name : author;
}
return result;
};
BacktraceReport.prototype.readAnnotation = function () {
var result = {
'Environment Variables': process.env,
'Exec Arguments': process.execArgv,
};
if (this.detectReportType(this.err)) {
result['Exception'] = this.err;
}
return tslib_1.__assign(tslib_1.__assign({}, result), this.annotations);
};
BacktraceReport.prototype.splitAttributesFromAnnotations = function (clientAttributes) {
for (var key in clientAttributes) {
if (clientAttributes.hasOwnProperty(key)) {
var element = this.clientAttributes[key];
if (!element) {
continue;
}
if (typeof element === 'object') {
this.annotations[key] = element;
}
else {
this.attributes[key] = element;
}
}
}
};
BacktraceReport.machineId = machineId_1.machineIdSync(true);
return BacktraceReport;
}());
exports.BacktraceReport = BacktraceReport;
//# sourceMappingURL=backtraceReport.js.map