raygun
Version:
Raygun package for Node.js, written in TypeScript
296 lines (295 loc) • 10.5 kB
JavaScript
/*
* raygun
* https://github.com/MindscapeHQ/raygun4node
*
* Copyright (c) 2015 MindscapeHQ
* Licensed under the MIT license.
*/
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RaygunMessageBuilder = void 0;
var os_1 = __importDefault(require("os"));
var stack_trace_1 = __importDefault(require("stack-trace"));
var raygun_human_1 = require("./raygun.human");
var debug = require("debug")("raygun");
var packageDetails = require("../package.json");
/**
* Filter properties in obj according to provided filters.
* Also removes any recursive self-referencing object.
* @param obj - object to apply filter
* @param filters - list of keys to filter
* @param explored - Set that contains already explored nodes, used internally
* @returns object after applying the filters
*/
function filterKeys(obj, filters, explored) {
if (explored === void 0) { explored = null; }
if (!obj || !filters || typeof obj !== "object") {
return obj;
}
// create or update the explored set with the incoming object
var _explored = (explored === null || explored === void 0 ? void 0 : explored.add(obj)) || new Set([obj]);
// Make temporary copy of the object to avoid mutating the original
// Cast to Record<string, object> to enforce type check and avoid using any
var _obj = __assign({}, obj);
Object.keys(obj).forEach(function (key) {
// Remove child if:
// - the key is in the filter array
// - the value is already in the explored Set
if (filters.indexOf(key) > -1 || _explored.has(_obj[key])) {
delete _obj[key];
}
else {
_obj[key] = filterKeys(_obj[key], filters, _explored);
}
});
return _obj;
}
/**
* Extract stacktrace from provided Error
* @param error - error to process
* @param options - builder options
* @returns created stack trace
*/
function getStackTrace(error, options) {
var stack = [];
var trace = stack_trace_1.default.parse(error);
trace.forEach(function (callSite) {
var frame = {
lineNumber: callSite.getLineNumber(),
className: callSite.getTypeName() || "unknown",
fileName: callSite.getFileName(),
methodName: callSite.getFunctionName() || "[anonymous]",
};
if (!!options.reportColumnNumbers &&
typeof callSite.getColumnNumber === "function") {
frame.columnNumber = callSite.getColumnNumber();
}
stack.push(frame);
});
return stack;
}
/**
* Created an error payload to send
* @param error - error to process
* @param options - builder options
* @returns created error
*/
function buildError(error, options) {
var builtError = {
stackTrace: getStackTrace(error, options),
message: error.message || "NoMessage",
className: error.name,
};
var innerError = undefined;
if (options.innerErrorFieldName) {
innerError =
typeof error[options.innerErrorFieldName] === "function"
? error[options.innerErrorFieldName]()
: error[options.innerErrorFieldName];
}
if (innerError instanceof Error) {
builtError.innerError = buildError(innerError, options);
}
return builtError;
}
var RaygunMessageBuilder = /** @class */ (function () {
function RaygunMessageBuilder(options) {
if (options === void 0) { options = {}; }
options = options || {};
this.options = options;
this._filters = options.filters || [];
this.message = {
occurredOn: options.timestamp || new Date(),
details: {
client: {
name: "raygun-node",
version: packageDetails.version,
},
},
};
}
RaygunMessageBuilder.prototype.build = function () {
// TODO - this provides no type safety that you actually passed what is needed
// probably need to abandon the fluent builder pattern for better types
return this.message;
};
/**
* Add error details to builder
* @param error - error to add
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
RaygunMessageBuilder.prototype.setErrorDetails = function (error) {
if (!(error instanceof Error) &&
typeof error !== "string" &&
this.options.useHumanStringForObject) {
error = (0, raygun_human_1.humanString)(error);
this.message.details.groupingKey = error
.replace(/\W+/g, "")
.substring(0, 64);
}
if (typeof error === "string") {
this.message.details.error = {
message: error,
stackTrace: [],
className: "Error",
};
return this;
}
this.message.details.error = buildError(error, this.options);
return this;
};
/**
* Set environment details from OS to builder
*/
RaygunMessageBuilder.prototype.setEnvironmentDetails = function () {
var environment = {
osVersion: "".concat(os_1.default.type(), " ").concat(os_1.default.platform(), " ").concat(os_1.default.release()),
architecture: os_1.default.arch(),
totalPhysicalMemory: os_1.default.totalmem(),
availablePhysicalMemory: os_1.default.freemem(),
utcOffset: new Date().getTimezoneOffset() / -60.0,
};
// cpus seems to return undefined on some systems
var cpus = os_1.default.cpus();
if (cpus && cpus.length && cpus.length > 0) {
environment.processorCount = cpus.length;
environment.cpu = cpus[0].model;
}
this.message.details.environment = environment;
return this;
};
/**
* Set machine name to builder
* @param machineName - the machine name, if not provided reads from OS
*/
RaygunMessageBuilder.prototype.setMachineName = function (machineName) {
this.message.details.machineName = machineName || os_1.default.hostname();
return this;
};
/**
* Set custom data to builder
* @param customData - optional CustomData object
*/
RaygunMessageBuilder.prototype.setUserCustomData = function (customData) {
this.message.details.userCustomData = customData;
return this;
};
/**
* Set tags to builder
* @param tags - List of Tags
*/
RaygunMessageBuilder.prototype.setTags = function (tags) {
if (Array.isArray(tags)) {
this.message.details.tags = tags;
}
return this;
};
/**
* Set Request to builder
* @param request - optional request object
*/
RaygunMessageBuilder.prototype.setRequestDetails = function (request) {
if (request) {
var host = "hostname" in request ? request.hostname : request.host;
this.message.details.request = {
hostName: host,
url: request.path,
httpMethod: request.method,
ipAddress: request.ip,
queryString: filterKeys(request.query, this._filters),
headers: filterKeys(request.headers, this._filters),
form: filterKeys(request.body, this._filters),
};
}
return this;
};
/**
* Set user info to builder
* @param user - either a function or a UserMessageData object
*/
RaygunMessageBuilder.prototype.setUser = function (user) {
if (!user) {
return this;
}
var userData;
if (user instanceof Function) {
userData = user();
}
else {
userData = user;
}
if (userData instanceof Object) {
this.message.details.user = this.extractUserProperties(userData);
}
else if (typeof userData === "string") {
this.message.details.user = { identifier: userData };
}
return this;
};
/**
* Set application version to builder
* @param version - version as String
*/
RaygunMessageBuilder.prototype.setVersion = function (version) {
this.message.details.version = version;
return this;
};
RaygunMessageBuilder.prototype.extractUserProperties = function (userData) {
var data = {};
if (userData.identifier) {
data.identifier = userData.identifier;
}
if (userData.isAnonymous) {
data.isAnonymous = userData.isAnonymous;
}
if (userData.email) {
data.email = userData.email;
}
if (userData.fullName) {
data.fullName = userData.fullName;
}
if (userData.firstName) {
data.firstName = userData.firstName;
}
if (userData.uuid) {
data.uuid = userData.uuid;
}
return data;
};
/**
* Set list of breadcrumbs to builder
* @param breadcrumbs - optional list of breadcrumbs
*/
RaygunMessageBuilder.prototype.setBreadcrumbs = function (breadcrumbs) {
debug("[raygun.messageBuilder.ts] Added breadcrumbs: ".concat((breadcrumbs === null || breadcrumbs === void 0 ? void 0 : breadcrumbs.length) || 0));
if (breadcrumbs) {
this.message.details.breadcrumbs = __spreadArray([], breadcrumbs, true);
}
return this;
};
return RaygunMessageBuilder;
}());
exports.RaygunMessageBuilder = RaygunMessageBuilder;