224 lines
17 KiB
JavaScript
224 lines
17 KiB
JavaScript
|
'use strict';
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
const tslib_1 = require("tslib");
|
||
|
const configuration_1 = require("../configuration");
|
||
|
const serviceManager_1 = require("../serviceManager");
|
||
|
const debug_1 = require("debug");
|
||
|
const semver = require("semver");
|
||
|
const stackParser_1 = require("../utils/stackParser");
|
||
|
const fs = require("fs");
|
||
|
const path = require("path");
|
||
|
class NotifyOptions {
|
||
|
}
|
||
|
exports.NotifyOptions = NotifyOptions;
|
||
|
class ErrorContext {
|
||
|
}
|
||
|
exports.ErrorContext = ErrorContext;
|
||
|
const optionsDefault = {
|
||
|
catchExceptions: true
|
||
|
};
|
||
|
class NotifyFeature {
|
||
|
constructor() {
|
||
|
this.logger = debug_1.default('axm:features:notify');
|
||
|
}
|
||
|
init(options) {
|
||
|
if (options === undefined) {
|
||
|
options = optionsDefault;
|
||
|
}
|
||
|
this.logger('init');
|
||
|
this.transport = serviceManager_1.ServiceManager.get('transport');
|
||
|
if (this.transport === undefined) {
|
||
|
return this.logger(`Failed to load transporter service`);
|
||
|
}
|
||
|
configuration_1.default.configureModule({
|
||
|
error: true
|
||
|
});
|
||
|
if (options.catchExceptions === false)
|
||
|
return;
|
||
|
this.logger('Registering hook to catch unhandled exception/rejection');
|
||
|
this.cache = new stackParser_1.Cache({
|
||
|
miss: (key) => {
|
||
|
try {
|
||
|
const content = fs.readFileSync(path.resolve(key));
|
||
|
return content.toString().split(/\r?\n/);
|
||
|
}
|
||
|
catch (err) {
|
||
|
this.logger('Error while trying to get file from FS : %s', err.message || err);
|
||
|
return null;
|
||
|
}
|
||
|
},
|
||
|
ttl: 30 * 60
|
||
|
});
|
||
|
this.stackParser = new stackParser_1.StackTraceParser({
|
||
|
cache: this.cache,
|
||
|
contextSize: 5
|
||
|
});
|
||
|
this.catchAll();
|
||
|
}
|
||
|
destroy() {
|
||
|
process.removeListener('uncaughtException', this.onUncaughtException);
|
||
|
process.removeListener('unhandledRejection', this.onUnhandledRejection);
|
||
|
this.logger('destroy');
|
||
|
}
|
||
|
getSafeError(err) {
|
||
|
if (err instanceof Error)
|
||
|
return err;
|
||
|
let message;
|
||
|
try {
|
||
|
message = `Non-error value: ${JSON.stringify(err)}`;
|
||
|
}
|
||
|
catch (e) {
|
||
|
try {
|
||
|
message = `Unserializable non-error value: ${String(e)}`;
|
||
|
}
|
||
|
catch (e2) {
|
||
|
message = `Unserializable non-error value that cannot be converted to a string`;
|
||
|
}
|
||
|
}
|
||
|
if (message.length > 1000)
|
||
|
message = message.substr(0, 1000) + '...';
|
||
|
return new Error(message);
|
||
|
}
|
||
|
notifyError(err, context) {
|
||
|
if (typeof context !== 'object') {
|
||
|
context = {};
|
||
|
}
|
||
|
if (this.transport === undefined) {
|
||
|
return this.logger(`Tried to send error without having transporter available`);
|
||
|
}
|
||
|
const safeError = this.getSafeError(err);
|
||
|
let stackContext = null;
|
||
|
if (err instanceof Error) {
|
||
|
stackContext = this.stackParser.retrieveContext(err);
|
||
|
}
|
||
|
const payload = Object.assign({
|
||
|
message: safeError.message,
|
||
|
stack: safeError.stack,
|
||
|
name: safeError.name,
|
||
|
metadata: context
|
||
|
}, stackContext === null ? {} : stackContext);
|
||
|
return this.transport.send('process:exception', payload);
|
||
|
}
|
||
|
onUncaughtException(error) {
|
||
|
if (semver.satisfies(process.version, '< 6')) {
|
||
|
console.error(error.stack);
|
||
|
}
|
||
|
else {
|
||
|
console.error(error);
|
||
|
}
|
||
|
const safeError = this.getSafeError(error);
|
||
|
let stackContext = null;
|
||
|
if (error instanceof Error) {
|
||
|
stackContext = this.stackParser.retrieveContext(error);
|
||
|
}
|
||
|
const payload = Object.assign({
|
||
|
message: safeError.message,
|
||
|
stack: safeError.stack,
|
||
|
name: safeError.name
|
||
|
}, stackContext === null ? {} : stackContext);
|
||
|
if (serviceManager_1.ServiceManager.get('transport')) {
|
||
|
serviceManager_1.ServiceManager.get('transport').send('process:exception', payload);
|
||
|
}
|
||
|
if (process.listeners('uncaughtException').length === 1) {
|
||
|
process.exit(1);
|
||
|
}
|
||
|
}
|
||
|
onUnhandledRejection(error) {
|
||
|
if (error === undefined)
|
||
|
return;
|
||
|
console.error(error);
|
||
|
const safeError = this.getSafeError(error);
|
||
|
let stackContext = null;
|
||
|
if (error instanceof Error) {
|
||
|
stackContext = this.stackParser.retrieveContext(error);
|
||
|
}
|
||
|
const payload = Object.assign({
|
||
|
message: safeError.message,
|
||
|
stack: safeError.stack,
|
||
|
name: safeError.name
|
||
|
}, stackContext === null ? {} : stackContext);
|
||
|
if (serviceManager_1.ServiceManager.get('transport')) {
|
||
|
serviceManager_1.ServiceManager.get('transport').send('process:exception', payload);
|
||
|
}
|
||
|
}
|
||
|
catchAll() {
|
||
|
if (process.env.exec_mode === 'cluster_mode') {
|
||
|
return false;
|
||
|
}
|
||
|
process.on('uncaughtException', this.onUncaughtException.bind(this));
|
||
|
process.on('unhandledRejection', this.onUnhandledRejection.bind(this));
|
||
|
}
|
||
|
expressErrorHandler() {
|
||
|
const self = this;
|
||
|
configuration_1.default.configureModule({
|
||
|
error: true
|
||
|
});
|
||
|
return function errorHandler(err, req, res, next) {
|
||
|
const safeError = self.getSafeError(err);
|
||
|
const payload = {
|
||
|
message: safeError.message,
|
||
|
stack: safeError.stack,
|
||
|
name: safeError.name,
|
||
|
metadata: {
|
||
|
http: {
|
||
|
url: req.url,
|
||
|
params: req.params,
|
||
|
method: req.method,
|
||
|
query: req.query,
|
||
|
body: req.body,
|
||
|
path: req.path,
|
||
|
route: req.route && req.route.path ? req.route.path : undefined
|
||
|
},
|
||
|
custom: {
|
||
|
user: typeof req.user === 'object' ? req.user.id : undefined
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
if (serviceManager_1.ServiceManager.get('transport')) {
|
||
|
serviceManager_1.ServiceManager.get('transport').send('process:exception', payload);
|
||
|
}
|
||
|
return next(err);
|
||
|
};
|
||
|
}
|
||
|
koaErrorHandler() {
|
||
|
const self = this;
|
||
|
configuration_1.default.configureModule({
|
||
|
error: true
|
||
|
});
|
||
|
return function (ctx, next) {
|
||
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
||
|
try {
|
||
|
yield next();
|
||
|
}
|
||
|
catch (err) {
|
||
|
const safeError = self.getSafeError(err);
|
||
|
const payload = {
|
||
|
message: safeError.message,
|
||
|
stack: safeError.stack,
|
||
|
name: safeError.name,
|
||
|
metadata: {
|
||
|
http: {
|
||
|
url: ctx.request.url,
|
||
|
params: ctx.params,
|
||
|
method: ctx.request.method,
|
||
|
query: ctx.request.query,
|
||
|
body: ctx.request.body,
|
||
|
path: ctx.request.path,
|
||
|
route: ctx._matchedRoute
|
||
|
},
|
||
|
custom: {
|
||
|
user: typeof ctx.user === 'object' ? ctx.user.id : undefined
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
if (serviceManager_1.ServiceManager.get('transport')) {
|
||
|
serviceManager_1.ServiceManager.get('transport').send('process:exception', payload);
|
||
|
}
|
||
|
throw err;
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
exports.NotifyFeature = NotifyFeature;
|
||
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWZ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2ZlYXR1cmVzL25vdGlmeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZLENBQUE7OztBQUdaLG9EQUE0QztBQUM1QyxzREFBa0Q7QUFDbEQsaUNBQXlCO0FBRXpCLGlDQUFnQztBQUNoQyxzREFBNEU7QUFDNUUseUJBQXdCO0FBQ3hCLDZCQUE0QjtBQUU1QixNQUFhLGFBQWE7Q0FFekI7QUFGRCxzQ0FFQztBQUVELE1BQWEsWUFBWTtDQVV4QjtBQVZELG9DQVVDO0FBRUQsTUFBTSxjQUFjLEdBQWtCO0lBQ3BDLGVBQWUsRUFBRSxJQUFJO0NBQ3RCLENBQUE7QUFFRCxNQUFhLGFBQWE7SUFBMUI7UUFFVSxXQUFNLEdBQWEsZUFBSyxDQUFDLHFCQUFxQixDQUFDLENBQUE7SUFxT3pELENBQUM7SUFoT0MsSUFBSSxDQUFFLE9BQXVCO1FBQzNCLElBQUksT0FBTyxLQUFLLFNBQVMsRUFBRTtZQUN6QixPQUFPLEdBQUcsY0FBYyxDQUFBO1NBQ3pCO1FBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQTtRQUNuQixJQUFJLENBQUMsU0FBUyxHQUFHLCtCQUFjLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFBO1FBQ2hELElBQUksSUFBSSxDQUFDLFNBQVMsS0FBSyxTQUFTLEVBQUU7WUFDaEMsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLG9DQUFvQyxDQUFDLENBQUE7U0FDekQ7UUFFRCx1QkFBYSxDQUFDLGVBQWUsQ0FBQztZQUM1QixLQUFLLEVBQUcsSUFBSTtTQUNiLENBQUMsQ0FBQTtRQUNGLElBQUksT0FBTyxDQUFDLGVBQWUsS0FBSyxLQUFLO1lBQUUsT0FBTTtRQUM3QyxJQUFJLENBQUMsTUFBTSxDQUFDLHlEQUF5RCxDQUFDLENBQUE7UUFDdEUsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLG1CQUFLLENBQUM7WUFDckIsSUFB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
|