@honeybadger-io/js 3.2.8 → 4.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/honeybadger.js +267 -119
- package/dist/browser/honeybadger.js.map +1 -1
- package/dist/browser/honeybadger.min.js +1 -1
- package/dist/browser/honeybadger.min.js.map +1 -1
- package/dist/browser/types/browser/util.d.ts +1 -1
- package/dist/browser/types/core/client.d.ts +23 -3
- package/dist/browser/types/core/store.d.ts +7 -0
- package/dist/browser/types/core/types.d.ts +8 -4
- package/dist/browser/types/core/util.d.ts +5 -3
- package/dist/browser/types/server/async_store.d.ts +5 -0
- package/dist/browser/types/server.d.ts +1 -0
- package/dist/server/honeybadger.d.ts +3 -1
- package/dist/server/honeybadger.js +375 -142
- package/dist/server/types/core/client.d.ts +23 -3
- package/dist/server/types/core/store.d.ts +7 -0
- package/dist/server/types/core/types.d.ts +8 -4
- package/dist/server/types/core/util.d.ts +5 -3
- package/dist/server/types/server/async_store.d.ts +5 -0
- package/dist/server/types/server/middleware.d.ts +3 -5
- package/dist/server/types/server/util.d.ts +7 -0
- package/dist/server/types/server.d.ts +3 -1
- package/honeybadger.d.ts +2 -1
- package/package.json +25 -22
- package/dist/browser/types/core/error.d.ts +0 -3
- package/dist/server/types/core/error.d.ts +0 -3
|
@@ -4,8 +4,8 @@ var https = require('https');
|
|
|
4
4
|
var http = require('http');
|
|
5
5
|
var url = require('url');
|
|
6
6
|
var os = require('os');
|
|
7
|
-
var fs = require('fs');
|
|
8
7
|
var domain = require('domain');
|
|
8
|
+
var fs = require('fs');
|
|
9
9
|
|
|
10
10
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
11
11
|
|
|
@@ -13,8 +13,8 @@ var https__default = /*#__PURE__*/_interopDefaultLegacy(https);
|
|
|
13
13
|
var http__default = /*#__PURE__*/_interopDefaultLegacy(http);
|
|
14
14
|
var url__default = /*#__PURE__*/_interopDefaultLegacy(url);
|
|
15
15
|
var os__default = /*#__PURE__*/_interopDefaultLegacy(os);
|
|
16
|
-
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
17
16
|
var domain__default = /*#__PURE__*/_interopDefaultLegacy(domain);
|
|
17
|
+
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
18
18
|
|
|
19
19
|
/*! *****************************************************************************
|
|
20
20
|
Copyright (c) Microsoft Corporation.
|
|
@@ -221,7 +221,8 @@ function objectIsEmpty(obj) {
|
|
|
221
221
|
function makeBacktrace(stack, shift) {
|
|
222
222
|
if (shift === void 0) { shift = 0; }
|
|
223
223
|
try {
|
|
224
|
-
var backtrace = parse(stack)
|
|
224
|
+
var backtrace = parse(stack)
|
|
225
|
+
.map(function (line) {
|
|
225
226
|
return {
|
|
226
227
|
file: line.file,
|
|
227
228
|
method: line.methodName,
|
|
@@ -237,24 +238,46 @@ function makeBacktrace(stack, shift) {
|
|
|
237
238
|
return [];
|
|
238
239
|
}
|
|
239
240
|
}
|
|
241
|
+
function getSourceForBacktrace(backtrace, getSourceFileHandler, cb) {
|
|
242
|
+
if (!getSourceFileHandler || !backtrace || !backtrace.length) {
|
|
243
|
+
cb([]);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
var result = [];
|
|
247
|
+
var getSourceFromFile = function (index) {
|
|
248
|
+
if (index === void 0) { index = 0; }
|
|
249
|
+
if (!backtrace.length) {
|
|
250
|
+
return cb(result);
|
|
251
|
+
}
|
|
252
|
+
var trace = backtrace.splice(0)[index];
|
|
253
|
+
getSourceFileHandler(trace.file, (function (fileContent) {
|
|
254
|
+
result[index] = getSourceCodeSnippet(fileContent, trace.number);
|
|
255
|
+
getSourceFromFile(index + 1);
|
|
256
|
+
}));
|
|
257
|
+
};
|
|
258
|
+
getSourceFromFile();
|
|
259
|
+
}
|
|
240
260
|
function runBeforeNotifyHandlers(notice, handlers) {
|
|
261
|
+
var result = true;
|
|
241
262
|
for (var i = 0, len = handlers.length; i < len; i++) {
|
|
242
263
|
var handler = handlers[i];
|
|
243
264
|
if (handler(notice) === false) {
|
|
244
|
-
|
|
265
|
+
result = false;
|
|
245
266
|
}
|
|
246
267
|
}
|
|
247
|
-
return
|
|
268
|
+
return result;
|
|
248
269
|
}
|
|
249
270
|
function runAfterNotifyHandlers(notice, handlers, error) {
|
|
250
|
-
if (
|
|
271
|
+
if (notice && notice.afterNotify) {
|
|
272
|
+
notice.afterNotify(error, notice);
|
|
273
|
+
}
|
|
251
274
|
for (var i = 0, len = handlers.length; i < len; i++) {
|
|
252
275
|
handlers[i](error, notice);
|
|
253
276
|
}
|
|
254
277
|
return true;
|
|
255
278
|
}
|
|
256
279
|
// Returns a new object with properties from other object.
|
|
257
|
-
function
|
|
280
|
+
function shallowClone(obj) {
|
|
258
281
|
if (typeof (obj) !== 'object' || obj === null) {
|
|
259
282
|
return {};
|
|
260
283
|
}
|
|
@@ -281,8 +304,14 @@ function sanitize(obj, maxDepth) {
|
|
|
281
304
|
return false;
|
|
282
305
|
}
|
|
283
306
|
function canSerialize(obj) {
|
|
284
|
-
|
|
285
|
-
|
|
307
|
+
var typeOfObj = typeof obj;
|
|
308
|
+
// Functions are TMI
|
|
309
|
+
if (/function/.test(typeOfObj)) {
|
|
310
|
+
// Let special toJSON method pass as it's used by JSON.stringify (#722)
|
|
311
|
+
return obj.name === 'toJSON';
|
|
312
|
+
}
|
|
313
|
+
// Symbols can't convert to strings.
|
|
314
|
+
if (/symbol/.test(typeOfObj)) {
|
|
286
315
|
return false;
|
|
287
316
|
}
|
|
288
317
|
if (obj === null) {
|
|
@@ -331,7 +360,7 @@ function sanitize(obj, maxDepth) {
|
|
|
331
360
|
return serialize(obj, depth);
|
|
332
361
|
}
|
|
333
362
|
catch (e) {
|
|
334
|
-
return "[ERROR] "
|
|
363
|
+
return "[ERROR] ".concat(e);
|
|
335
364
|
}
|
|
336
365
|
}
|
|
337
366
|
return safeSerialize(obj);
|
|
@@ -344,8 +373,13 @@ function logger(client) {
|
|
|
344
373
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
345
374
|
args[_i] = arguments[_i];
|
|
346
375
|
}
|
|
347
|
-
if (method === 'debug'
|
|
348
|
-
|
|
376
|
+
if (method === 'debug') {
|
|
377
|
+
if (!client.config.debug) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
// Log at default level so that you don't need to also enable verbose
|
|
381
|
+
// logging in Chrome.
|
|
382
|
+
method = 'log';
|
|
349
383
|
}
|
|
350
384
|
args.unshift('[Honeybadger]');
|
|
351
385
|
(_a = client.config.logger)[method].apply(_a, args);
|
|
@@ -368,12 +402,12 @@ function makeNotice(thing) {
|
|
|
368
402
|
if (!thing) {
|
|
369
403
|
notice = {};
|
|
370
404
|
}
|
|
371
|
-
else if (Object.prototype.toString.call(thing) === '[object Error]') {
|
|
405
|
+
else if (thing instanceof Error || Object.prototype.toString.call(thing) === '[object Error]') {
|
|
372
406
|
var e = thing;
|
|
373
407
|
notice = merge(thing, { name: e.name, message: e.message, stack: e.stack });
|
|
374
408
|
}
|
|
375
409
|
else if (typeof thing === 'object') {
|
|
376
|
-
notice =
|
|
410
|
+
notice = shallowClone(thing);
|
|
377
411
|
}
|
|
378
412
|
else {
|
|
379
413
|
var m = String(thing);
|
|
@@ -384,7 +418,7 @@ function makeNotice(thing) {
|
|
|
384
418
|
function endpoint(config, path) {
|
|
385
419
|
var endpoint = config.endpoint.trim().replace(/\/$/, '');
|
|
386
420
|
path = path.trim().replace(/(^\/|\/$)/g, '');
|
|
387
|
-
return endpoint
|
|
421
|
+
return "".concat(endpoint, "/").concat(path);
|
|
388
422
|
}
|
|
389
423
|
function generateStackTrace() {
|
|
390
424
|
try {
|
|
@@ -443,7 +477,9 @@ function filter(obj, filters) {
|
|
|
443
477
|
return newObj;
|
|
444
478
|
}
|
|
445
479
|
if (is('Array', obj)) {
|
|
446
|
-
return obj.map(function (v) {
|
|
480
|
+
return obj.map(function (v) {
|
|
481
|
+
return filter(v);
|
|
482
|
+
});
|
|
447
483
|
}
|
|
448
484
|
if (is('Function', obj)) {
|
|
449
485
|
return '[FUNC]';
|
|
@@ -479,7 +515,7 @@ function filterUrl(url, filters) {
|
|
|
479
515
|
query.split(/[&]\s?/).forEach(function (pair) {
|
|
480
516
|
var _a = pair.split('=', 2), key = _a[0], value = _a[1];
|
|
481
517
|
if (filterMatch(key, filters)) {
|
|
482
|
-
result = result.replace(key
|
|
518
|
+
result = result.replace("".concat(key, "=").concat(value), "".concat(key, "=[FILTERED]"));
|
|
483
519
|
}
|
|
484
520
|
});
|
|
485
521
|
return result;
|
|
@@ -493,34 +529,64 @@ function formatCGIData(vars, prefix) {
|
|
|
493
529
|
});
|
|
494
530
|
return formattedVars;
|
|
495
531
|
}
|
|
532
|
+
function getSourceCodeSnippet(fileData, lineNumber, sourceRadius) {
|
|
533
|
+
if (sourceRadius === void 0) { sourceRadius = 2; }
|
|
534
|
+
if (!fileData) {
|
|
535
|
+
return null;
|
|
536
|
+
}
|
|
537
|
+
var lines = fileData.split('\n');
|
|
538
|
+
// add one empty line because array index starts from 0, but error line number is counted from 1
|
|
539
|
+
lines.unshift('');
|
|
540
|
+
var start = lineNumber - sourceRadius;
|
|
541
|
+
var end = lineNumber + sourceRadius;
|
|
542
|
+
var result = {};
|
|
543
|
+
for (var i = start; i <= end; i++) {
|
|
544
|
+
var line = lines[i];
|
|
545
|
+
if (typeof line === 'string') {
|
|
546
|
+
result[i] = line;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return result;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
var GlobalStore$1 = /** @class */ (function () {
|
|
553
|
+
function GlobalStore(store) {
|
|
554
|
+
this.store = store;
|
|
555
|
+
}
|
|
556
|
+
GlobalStore.prototype.getStore = function () {
|
|
557
|
+
return this.store;
|
|
558
|
+
};
|
|
559
|
+
GlobalStore.prototype.run = function (store, callback) {
|
|
560
|
+
var args = [];
|
|
561
|
+
for (var _i = 2; _i < arguments.length; _i++) {
|
|
562
|
+
args[_i - 2] = arguments[_i];
|
|
563
|
+
}
|
|
564
|
+
this.store = store;
|
|
565
|
+
return callback.apply(void 0, args);
|
|
566
|
+
};
|
|
567
|
+
return GlobalStore;
|
|
568
|
+
}());
|
|
496
569
|
|
|
497
570
|
var notifier = {
|
|
498
571
|
name: 'honeybadger-js',
|
|
499
572
|
url: 'https://github.com/honeybadger-io/honeybadger-js',
|
|
500
|
-
version: '
|
|
573
|
+
version: '4.0.0-beta.2'
|
|
501
574
|
};
|
|
502
|
-
// Split at commas
|
|
503
|
-
var TAG_SEPARATOR =
|
|
504
|
-
// Removes any non-word characters
|
|
505
|
-
var TAG_SANITIZER = /[^\w]/g;
|
|
506
|
-
// Checks for blank strings
|
|
507
|
-
var STRING_EMPTY = '';
|
|
575
|
+
// Split at commas and spaces
|
|
576
|
+
var TAG_SEPARATOR = /,|\s+/;
|
|
508
577
|
// Checks for non-blank characters
|
|
509
578
|
var NOT_BLANK = /\S/;
|
|
510
579
|
var Client = /** @class */ (function () {
|
|
511
580
|
function Client(opts) {
|
|
512
581
|
if (opts === void 0) { opts = {}; }
|
|
513
|
-
/** @internal */
|
|
514
582
|
this.__pluginsExecuted = false;
|
|
515
|
-
|
|
516
|
-
this.__context = {};
|
|
517
|
-
/** @internal */
|
|
518
|
-
this.__breadcrumbs = [];
|
|
519
|
-
/** @internal */
|
|
583
|
+
this.__store = null;
|
|
520
584
|
this.__beforeNotifyHandlers = [];
|
|
521
|
-
/** @internal */
|
|
522
585
|
this.__afterNotifyHandlers = [];
|
|
523
|
-
this.config = __assign({ apiKey: null, endpoint: 'https://api.honeybadger.io', environment: null, hostname: null, projectRoot: null, component: null, action: null, revision: null, reportData: null, breadcrumbsEnabled: true, maxBreadcrumbs: 40, maxObjectDepth: 8, logger: console, developmentEnvironments: ['dev', 'development', 'test'],
|
|
586
|
+
this.config = __assign({ apiKey: null, endpoint: 'https://api.honeybadger.io', environment: null, hostname: null, projectRoot: null, component: null, action: null, revision: null, reportData: null, breadcrumbsEnabled: true, maxBreadcrumbs: 40, maxObjectDepth: 8, logger: console, developmentEnvironments: ['dev', 'development', 'test'], debug: false, tags: null, enableUncaught: true, enableUnhandledRejection: true, afterUncaught: function () { return true; }, filters: ['creditcard', 'password'], __plugins: [] }, opts);
|
|
587
|
+
// First, we go with the global (shared) store.
|
|
588
|
+
// Webserver middleware can then switch to the AsyncStore for async context tracking.
|
|
589
|
+
this.__store = new GlobalStore$1({ context: {}, breadcrumbs: [] });
|
|
524
590
|
this.logger = logger(this);
|
|
525
591
|
}
|
|
526
592
|
Client.prototype.factory = function (_opts) {
|
|
@@ -541,6 +607,10 @@ var Client = /** @class */ (function () {
|
|
|
541
607
|
}
|
|
542
608
|
return this;
|
|
543
609
|
};
|
|
610
|
+
/** @internal */
|
|
611
|
+
Client.prototype.__setStore = function (store) {
|
|
612
|
+
this.__store = store;
|
|
613
|
+
};
|
|
544
614
|
Client.prototype.beforeNotify = function (handler) {
|
|
545
615
|
this.__beforeNotifyHandlers.push(handler);
|
|
546
616
|
return this;
|
|
@@ -551,41 +621,129 @@ var Client = /** @class */ (function () {
|
|
|
551
621
|
};
|
|
552
622
|
Client.prototype.setContext = function (context) {
|
|
553
623
|
if (typeof context === 'object') {
|
|
554
|
-
|
|
624
|
+
var store = this.__store.getStore();
|
|
625
|
+
store.context = merge(store.context, context);
|
|
555
626
|
}
|
|
556
627
|
return this;
|
|
557
628
|
};
|
|
558
629
|
Client.prototype.resetContext = function (context) {
|
|
559
630
|
this.logger.warn('Deprecation warning: `Honeybadger.resetContext()` has been deprecated; please use `Honeybadger.clear()` instead.');
|
|
631
|
+
var store = this.__store.getStore();
|
|
560
632
|
if (typeof context === 'object' && context !== null) {
|
|
561
|
-
|
|
633
|
+
store.context = context;
|
|
562
634
|
}
|
|
563
635
|
else {
|
|
564
|
-
|
|
636
|
+
store.context = {};
|
|
565
637
|
}
|
|
566
638
|
return this;
|
|
567
639
|
};
|
|
568
640
|
Client.prototype.clear = function () {
|
|
569
|
-
|
|
570
|
-
|
|
641
|
+
var store = this.__store.getStore();
|
|
642
|
+
store.context = {};
|
|
643
|
+
store.breadcrumbs = [];
|
|
571
644
|
return this;
|
|
572
645
|
};
|
|
573
|
-
Client.prototype.notify = function (
|
|
646
|
+
Client.prototype.notify = function (noticeable, name, extra) {
|
|
647
|
+
var _this = this;
|
|
574
648
|
if (name === void 0) { name = undefined; }
|
|
575
649
|
if (extra === void 0) { extra = undefined; }
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
650
|
+
var preConditionError = null;
|
|
651
|
+
var notice = this.makeNotice(noticeable, name, extra);
|
|
652
|
+
if (!notice) {
|
|
653
|
+
this.logger.debug('failed to build error report');
|
|
654
|
+
preConditionError = new Error('failed to build error report');
|
|
579
655
|
}
|
|
580
|
-
if (!this.
|
|
581
|
-
this.logger.debug('
|
|
582
|
-
|
|
656
|
+
if (!preConditionError && this.config.reportData === false) {
|
|
657
|
+
this.logger.debug('skipping error report: honeybadger.js is disabled', notice);
|
|
658
|
+
preConditionError = new Error('honeybadger.js is disabled');
|
|
583
659
|
}
|
|
584
|
-
if (!this.
|
|
585
|
-
this.logger.
|
|
660
|
+
if (!preConditionError && this.__developmentMode()) {
|
|
661
|
+
this.logger.log('honeybadger.js is in development mode; the following error report will be sent in production.', notice);
|
|
662
|
+
preConditionError = new Error('honeybadger.js is in development mode');
|
|
663
|
+
}
|
|
664
|
+
if (!preConditionError && !this.config.apiKey) {
|
|
665
|
+
this.logger.warn('could not send error report: no API key has been configured', notice);
|
|
666
|
+
preConditionError = new Error('missing API key');
|
|
667
|
+
}
|
|
668
|
+
var beforeNotifyResult = runBeforeNotifyHandlers(notice, this.__beforeNotifyHandlers);
|
|
669
|
+
if (!preConditionError && !beforeNotifyResult) {
|
|
670
|
+
this.logger.debug('skipping error report: beforeNotify handlers returned false', notice);
|
|
671
|
+
preConditionError = new Error('beforeNotify handlers returned false');
|
|
672
|
+
}
|
|
673
|
+
if (preConditionError) {
|
|
674
|
+
runAfterNotifyHandlers(notice, this.__afterNotifyHandlers, preConditionError);
|
|
586
675
|
return false;
|
|
587
676
|
}
|
|
588
|
-
|
|
677
|
+
this.addBreadcrumb('Honeybadger Notice', {
|
|
678
|
+
category: 'notice',
|
|
679
|
+
metadata: {
|
|
680
|
+
message: notice.message,
|
|
681
|
+
name: notice.name,
|
|
682
|
+
stack: notice.stack
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
var breadcrumbs = this.__getStoreOrDefaultObject().breadcrumbs;
|
|
686
|
+
notice.__breadcrumbs = this.config.breadcrumbsEnabled ? breadcrumbs.slice() : [];
|
|
687
|
+
// we need to have the source file data before the beforeNotifyHandlers,
|
|
688
|
+
// in case they modify them
|
|
689
|
+
var sourceCodeData = notice && notice.backtrace ? notice.backtrace.map(function (trace) { return shallowClone(trace); }) : null;
|
|
690
|
+
getSourceForBacktrace(sourceCodeData, this.__getSourceFileHandler, function (sourcePerTrace) {
|
|
691
|
+
sourcePerTrace.forEach(function (source, index) {
|
|
692
|
+
notice.backtrace[index].source = source;
|
|
693
|
+
});
|
|
694
|
+
_this.__send(notice);
|
|
695
|
+
});
|
|
696
|
+
return true;
|
|
697
|
+
};
|
|
698
|
+
/**
|
|
699
|
+
* An async version of {@link notify} that resolves only after the notice has been reported to Honeybadger.
|
|
700
|
+
* Implemented using the {@link afterNotify} hook.
|
|
701
|
+
* Rejects if for any reason the report failed to be reported.
|
|
702
|
+
* Useful in serverless environments (AWS Lambda).
|
|
703
|
+
*/
|
|
704
|
+
Client.prototype.notifyAsync = function (noticeable, name, extra) {
|
|
705
|
+
var _this = this;
|
|
706
|
+
if (name === void 0) { name = undefined; }
|
|
707
|
+
if (extra === void 0) { extra = undefined; }
|
|
708
|
+
return new Promise(function (resolve, reject) {
|
|
709
|
+
var applyAfterNotify = function (partialNotice) {
|
|
710
|
+
var originalAfterNotify = partialNotice.afterNotify;
|
|
711
|
+
partialNotice.afterNotify = function (err) {
|
|
712
|
+
originalAfterNotify === null || originalAfterNotify === void 0 ? void 0 : originalAfterNotify.call(_this, err);
|
|
713
|
+
if (err) {
|
|
714
|
+
return reject(err);
|
|
715
|
+
}
|
|
716
|
+
resolve();
|
|
717
|
+
};
|
|
718
|
+
};
|
|
719
|
+
// We have to respect any afterNotify hooks that come from the arguments
|
|
720
|
+
var objectToOverride;
|
|
721
|
+
if (noticeable.afterNotify) {
|
|
722
|
+
objectToOverride = noticeable;
|
|
723
|
+
}
|
|
724
|
+
else if (name && name.afterNotify) {
|
|
725
|
+
objectToOverride = name;
|
|
726
|
+
}
|
|
727
|
+
else if (extra && extra.afterNotify) {
|
|
728
|
+
objectToOverride = extra;
|
|
729
|
+
}
|
|
730
|
+
else if (name && typeof name === 'object') {
|
|
731
|
+
objectToOverride = name;
|
|
732
|
+
}
|
|
733
|
+
else if (extra) {
|
|
734
|
+
objectToOverride = extra;
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
objectToOverride = name = {};
|
|
738
|
+
}
|
|
739
|
+
applyAfterNotify(objectToOverride);
|
|
740
|
+
_this.notify(noticeable, name, extra);
|
|
741
|
+
});
|
|
742
|
+
};
|
|
743
|
+
Client.prototype.makeNotice = function (noticeable, name, extra) {
|
|
744
|
+
if (name === void 0) { name = undefined; }
|
|
745
|
+
if (extra === void 0) { extra = undefined; }
|
|
746
|
+
var notice = makeNotice(noticeable);
|
|
589
747
|
if (name && !(typeof name === 'object')) {
|
|
590
748
|
var n = String(name);
|
|
591
749
|
name = { name: n };
|
|
@@ -597,17 +755,18 @@ var Client = /** @class */ (function () {
|
|
|
597
755
|
notice = mergeNotice(notice, extra);
|
|
598
756
|
}
|
|
599
757
|
if (objectIsEmpty(notice)) {
|
|
600
|
-
return
|
|
758
|
+
return null;
|
|
601
759
|
}
|
|
760
|
+
var context = this.__getStoreOrDefaultObject().context;
|
|
602
761
|
var noticeTags = this.__constructTags(notice.tags);
|
|
603
|
-
var contextTags = this.__constructTags(
|
|
762
|
+
var contextTags = this.__constructTags(context["tags"]);
|
|
604
763
|
var configTags = this.__constructTags(this.config.tags);
|
|
605
764
|
// Turning into a Set will remove duplicates
|
|
606
765
|
var tags = noticeTags.concat(contextTags).concat(configTags);
|
|
607
766
|
var uniqueTags = tags.filter(function (item, index) { return tags.indexOf(item) === index; });
|
|
608
767
|
notice = merge(notice, {
|
|
609
768
|
name: notice.name || 'Error',
|
|
610
|
-
context: merge(
|
|
769
|
+
context: merge(context, notice.context),
|
|
611
770
|
projectRoot: notice.projectRoot || this.config.projectRoot,
|
|
612
771
|
environment: notice.environment || this.config.environment,
|
|
613
772
|
component: notice.component || this.config.component,
|
|
@@ -621,52 +780,40 @@ var Client = /** @class */ (function () {
|
|
|
621
780
|
backtraceShift = 2;
|
|
622
781
|
}
|
|
623
782
|
notice.backtrace = makeBacktrace(notice.stack, backtraceShift);
|
|
624
|
-
|
|
625
|
-
return false;
|
|
626
|
-
}
|
|
627
|
-
this.addBreadcrumb('Honeybadger Notice', {
|
|
628
|
-
category: 'notice',
|
|
629
|
-
metadata: {
|
|
630
|
-
message: notice.message,
|
|
631
|
-
name: notice.name,
|
|
632
|
-
stack: notice.stack
|
|
633
|
-
}
|
|
634
|
-
});
|
|
635
|
-
notice.__breadcrumbs = this.config.breadcrumbsEnabled ? this.__breadcrumbs.slice() : [];
|
|
636
|
-
return this.__send(notice);
|
|
783
|
+
return notice;
|
|
637
784
|
};
|
|
638
785
|
Client.prototype.addBreadcrumb = function (message, opts) {
|
|
639
786
|
if (!this.config.breadcrumbsEnabled) {
|
|
640
787
|
return;
|
|
641
788
|
}
|
|
642
789
|
opts = opts || {};
|
|
643
|
-
var metadata =
|
|
790
|
+
var metadata = shallowClone(opts.metadata);
|
|
644
791
|
var category = opts.category || 'custom';
|
|
645
792
|
var timestamp = new Date().toISOString();
|
|
646
|
-
this.
|
|
793
|
+
var store = this.__store.getStore();
|
|
794
|
+
var breadcrumbs = store.breadcrumbs;
|
|
795
|
+
breadcrumbs.push({
|
|
647
796
|
category: category,
|
|
648
797
|
message: message,
|
|
649
798
|
metadata: metadata,
|
|
650
799
|
timestamp: timestamp
|
|
651
800
|
});
|
|
652
801
|
var limit = this.config.maxBreadcrumbs;
|
|
653
|
-
if (
|
|
654
|
-
|
|
802
|
+
if (breadcrumbs.length > limit) {
|
|
803
|
+
breadcrumbs = breadcrumbs.slice(breadcrumbs.length - limit);
|
|
655
804
|
}
|
|
805
|
+
store.breadcrumbs = breadcrumbs;
|
|
656
806
|
return this;
|
|
657
807
|
};
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
return this.config.reportData;
|
|
808
|
+
Client.prototype.__developmentMode = function () {
|
|
809
|
+
if (this.config.reportData === true) {
|
|
810
|
+
return false;
|
|
662
811
|
}
|
|
663
|
-
return
|
|
812
|
+
return (this.config.environment && this.config.developmentEnvironments.includes(this.config.environment));
|
|
664
813
|
};
|
|
665
|
-
/** @internal */
|
|
666
814
|
Client.prototype.__send = function (_notice) {
|
|
667
815
|
throw (new Error('Must implement send in subclass'));
|
|
668
816
|
};
|
|
669
|
-
/** @internal */
|
|
670
817
|
Client.prototype.__buildPayload = function (notice) {
|
|
671
818
|
var headers = filter(notice.headers, this.config.filters) || {};
|
|
672
819
|
var cgiData = filter(__assign(__assign({}, notice.cgiData), formatCGIData(headers, 'HTTP_')), this.config.filters);
|
|
@@ -702,14 +849,22 @@ var Client = /** @class */ (function () {
|
|
|
702
849
|
details: notice.details || {}
|
|
703
850
|
};
|
|
704
851
|
};
|
|
705
|
-
/** @internal */
|
|
706
852
|
Client.prototype.__constructTags = function (tags) {
|
|
707
853
|
if (!tags) {
|
|
708
854
|
return [];
|
|
709
855
|
}
|
|
710
|
-
return tags.toString().split(TAG_SEPARATOR).
|
|
711
|
-
|
|
712
|
-
|
|
856
|
+
return tags.toString().split(TAG_SEPARATOR).filter(function (tag) { return NOT_BLANK.test(tag); });
|
|
857
|
+
};
|
|
858
|
+
/**
|
|
859
|
+
* For ALS, the store may be uninitialized (if .run()` has not been called).
|
|
860
|
+
* This provides an easy way to read the existing store object or fall back to a default.
|
|
861
|
+
* Returns *a copy* of the store.
|
|
862
|
+
* @internal
|
|
863
|
+
*/
|
|
864
|
+
Client.prototype.__getStoreOrDefaultObject = function () {
|
|
865
|
+
var existingStore = this.__store.getStore();
|
|
866
|
+
var store = existingStore || {};
|
|
867
|
+
return __assign({ context: {}, breadcrumbs: [] }, store);
|
|
713
868
|
};
|
|
714
869
|
return Client;
|
|
715
870
|
}());
|
|
@@ -720,7 +875,7 @@ function fatallyLogAndExit(err) {
|
|
|
720
875
|
process.exit(1);
|
|
721
876
|
}
|
|
722
877
|
function getStats(cb) {
|
|
723
|
-
var load = os__default[
|
|
878
|
+
var load = os__default["default"].loadavg(), stats = {
|
|
724
879
|
load: {
|
|
725
880
|
one: load[0],
|
|
726
881
|
five: load[1],
|
|
@@ -728,8 +883,8 @@ function getStats(cb) {
|
|
|
728
883
|
},
|
|
729
884
|
mem: {}
|
|
730
885
|
};
|
|
731
|
-
if (fs__default[
|
|
732
|
-
return fs__default[
|
|
886
|
+
if (fs__default["default"].existsSync('/proc/meminfo')) {
|
|
887
|
+
return fs__default["default"].readFile('/proc/meminfo', 'utf8', parseStats);
|
|
733
888
|
}
|
|
734
889
|
fallback();
|
|
735
890
|
function parseStats(err, memData) {
|
|
@@ -752,21 +907,125 @@ function getStats(cb) {
|
|
|
752
907
|
}
|
|
753
908
|
function fallback() {
|
|
754
909
|
stats.mem = {
|
|
755
|
-
free: os__default[
|
|
756
|
-
total: os__default[
|
|
910
|
+
free: os__default["default"].freemem(),
|
|
911
|
+
total: os__default["default"].totalmem()
|
|
757
912
|
};
|
|
758
913
|
return cb(stats);
|
|
759
914
|
}
|
|
760
915
|
}
|
|
916
|
+
/**
|
|
917
|
+
* Get source file if possible, used to build `notice.backtrace.source`
|
|
918
|
+
*
|
|
919
|
+
* @param path to source code
|
|
920
|
+
* @param cb callback with fileContent
|
|
921
|
+
*/
|
|
922
|
+
function getSourceFile(path, cb) {
|
|
923
|
+
fs__default["default"].readFile(path, 'utf-8', function (err, data) {
|
|
924
|
+
cb(err ? null : data);
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
var Store;
|
|
929
|
+
try {
|
|
930
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
931
|
+
var AsyncLocalStorage = require('async_hooks').AsyncLocalStorage;
|
|
932
|
+
Store = new AsyncLocalStorage();
|
|
933
|
+
}
|
|
934
|
+
catch (e) {
|
|
935
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
936
|
+
var GlobalStore = require('../core/store').GlobalStore;
|
|
937
|
+
Store = new GlobalStore();
|
|
938
|
+
}
|
|
939
|
+
var AsyncStore = Store;
|
|
940
|
+
|
|
941
|
+
function isHandlerSync(handler) {
|
|
942
|
+
return handler.length > 2;
|
|
943
|
+
}
|
|
944
|
+
function reportToHoneybadger(hb, err, callback) {
|
|
945
|
+
hb.notify(err, {
|
|
946
|
+
afterNotify: function () {
|
|
947
|
+
hb.clear();
|
|
948
|
+
callback(err);
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
function asyncHandler(handler, hb) {
|
|
953
|
+
return function wrappedLambdaHandler(event, context) {
|
|
954
|
+
hb.__setStore(AsyncStore);
|
|
955
|
+
return new Promise(function (resolve, reject) {
|
|
956
|
+
AsyncStore.run({ context: {}, breadcrumbs: [] }, function () {
|
|
957
|
+
try {
|
|
958
|
+
handler(event, context)
|
|
959
|
+
.then(resolve)
|
|
960
|
+
.catch(function (err) { return reportToHoneybadger(hb, err, reject); });
|
|
961
|
+
}
|
|
962
|
+
catch (err) {
|
|
963
|
+
reportToHoneybadger(hb, err, reject);
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
});
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
function syncHandler(handler, hb) {
|
|
970
|
+
return function wrappedLambdaHandler(event, context, cb) {
|
|
971
|
+
hb.__setStore(AsyncStore);
|
|
972
|
+
AsyncStore.run({ context: {}, breadcrumbs: [] }, function () {
|
|
973
|
+
try {
|
|
974
|
+
handler(event, context, function (error, result) {
|
|
975
|
+
if (error) {
|
|
976
|
+
return reportToHoneybadger(hb, error, cb);
|
|
977
|
+
}
|
|
978
|
+
cb(null, result);
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
catch (err) {
|
|
982
|
+
reportToHoneybadger(hb, err, cb);
|
|
983
|
+
}
|
|
984
|
+
});
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
function lambdaHandler(handler) {
|
|
988
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
989
|
+
var hb = this;
|
|
990
|
+
if (isHandlerSync(handler)) {
|
|
991
|
+
return syncHandler(handler, hb);
|
|
992
|
+
}
|
|
993
|
+
return asyncHandler(handler, hb);
|
|
994
|
+
}
|
|
995
|
+
var listenerRemoved = false;
|
|
996
|
+
/**
|
|
997
|
+
* Removes AWS Lambda default listener that
|
|
998
|
+
* exits the process before letting us report to honeybadger.
|
|
999
|
+
*/
|
|
1000
|
+
function removeAwsDefaultUncaughtExceptionListener() {
|
|
1001
|
+
if (listenerRemoved) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
listenerRemoved = true;
|
|
1005
|
+
var listeners = process.listeners('uncaughtException');
|
|
1006
|
+
if (listeners.length === 0) {
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
// We assume it's the first listener
|
|
1010
|
+
process.removeListener('uncaughtException', listeners[0]);
|
|
1011
|
+
}
|
|
761
1012
|
|
|
762
1013
|
var count = 0;
|
|
1014
|
+
function removeAwsLambdaListener() {
|
|
1015
|
+
var isLambda = !!process.env.LAMBDA_TASK_ROOT;
|
|
1016
|
+
if (!isLambda) {
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
removeAwsDefaultUncaughtExceptionListener();
|
|
1020
|
+
}
|
|
763
1021
|
function uncaughtException () {
|
|
764
1022
|
return {
|
|
765
1023
|
load: function (client) {
|
|
766
1024
|
if (!client.config.enableUncaught) {
|
|
767
1025
|
return;
|
|
768
1026
|
}
|
|
769
|
-
|
|
1027
|
+
removeAwsLambdaListener();
|
|
1028
|
+
process.on('uncaughtException', function honeybadgerUncaughtExceptionListener(uncaughtError) {
|
|
770
1029
|
// Prevent recursive errors
|
|
771
1030
|
if (count > 1) {
|
|
772
1031
|
fatallyLogAndExit(uncaughtError);
|
|
@@ -810,7 +1069,7 @@ function fullUrl(req) {
|
|
|
810
1069
|
// @ts-ignore The old @types/node incorrectly defines `address` as string|Address
|
|
811
1070
|
var port = address ? address.port : undefined;
|
|
812
1071
|
// @ts-ignore
|
|
813
|
-
return url__default[
|
|
1072
|
+
return url__default["default"].format({
|
|
814
1073
|
protocol: req.protocol,
|
|
815
1074
|
hostname: req.hostname,
|
|
816
1075
|
port: port,
|
|
@@ -819,10 +1078,7 @@ function fullUrl(req) {
|
|
|
819
1078
|
});
|
|
820
1079
|
}
|
|
821
1080
|
function requestHandler(req, res, next) {
|
|
822
|
-
this.
|
|
823
|
-
var dom = domain__default['default'].create();
|
|
824
|
-
dom.on('error', next);
|
|
825
|
-
dom.run(next);
|
|
1081
|
+
this.run(next, next);
|
|
826
1082
|
}
|
|
827
1083
|
function errorHandler(err, req, _res, next) {
|
|
828
1084
|
this.notify(err, {
|
|
@@ -837,50 +1093,12 @@ function errorHandler(err, req, _res, next) {
|
|
|
837
1093
|
});
|
|
838
1094
|
return next(err);
|
|
839
1095
|
}
|
|
840
|
-
function lambdaHandler(handler) {
|
|
841
|
-
return function lambdaHandler(event, context, callback) {
|
|
842
|
-
// in the case of an async handler, the length of the handler will be less than 3 (no callback function).
|
|
843
|
-
// if this is the case, we have to explicitly call the callback function from the function we are returning.
|
|
844
|
-
// we don't have to do that if the handler has third callback function parameter,
|
|
845
|
-
// because it will be called directly from inside the handler.
|
|
846
|
-
var shouldInvokeCallbackExplicitly = handler.length < 3;
|
|
847
|
-
// eslint-disable-next-line prefer-rest-params
|
|
848
|
-
var args = arguments;
|
|
849
|
-
var dom = domain__default['default'].create();
|
|
850
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
851
|
-
var hb = this;
|
|
852
|
-
var hbHandler = function (err) {
|
|
853
|
-
var willNotify = hb.notify(err, {
|
|
854
|
-
afterNotify: function () {
|
|
855
|
-
hb.clear();
|
|
856
|
-
callback(err);
|
|
857
|
-
}
|
|
858
|
-
});
|
|
859
|
-
if (!willNotify) {
|
|
860
|
-
callback(err);
|
|
861
|
-
}
|
|
862
|
-
};
|
|
863
|
-
dom.on('error', hbHandler);
|
|
864
|
-
dom.run(function () {
|
|
865
|
-
process.nextTick(function () {
|
|
866
|
-
Promise.resolve(handler.apply(this, args))
|
|
867
|
-
.then(function (res) {
|
|
868
|
-
hb.clear();
|
|
869
|
-
if (shouldInvokeCallbackExplicitly) {
|
|
870
|
-
callback(null, res);
|
|
871
|
-
}
|
|
872
|
-
})
|
|
873
|
-
.catch(hbHandler);
|
|
874
|
-
});
|
|
875
|
-
});
|
|
876
|
-
}.bind(this);
|
|
877
|
-
}
|
|
878
1096
|
|
|
879
1097
|
var Honeybadger = /** @class */ (function (_super) {
|
|
880
1098
|
__extends(Honeybadger, _super);
|
|
881
1099
|
function Honeybadger(opts) {
|
|
882
1100
|
if (opts === void 0) { opts = {}; }
|
|
883
|
-
var _this = _super.call(this, __assign({ afterUncaught: fatallyLogAndExit, projectRoot: process.cwd(), hostname: os__default[
|
|
1101
|
+
var _this = _super.call(this, __assign({ afterUncaught: fatallyLogAndExit, projectRoot: process.cwd(), hostname: os__default["default"].hostname() }, opts)) || this;
|
|
884
1102
|
/** @internal */
|
|
885
1103
|
_this.__beforeNotifyHandlers = [
|
|
886
1104
|
function (notice) {
|
|
@@ -893,6 +1111,7 @@ var Honeybadger = /** @class */ (function (_super) {
|
|
|
893
1111
|
});
|
|
894
1112
|
}
|
|
895
1113
|
];
|
|
1114
|
+
_this.__getSourceFileHandler = getSourceFile.bind(_this);
|
|
896
1115
|
_this.errorHandler = errorHandler.bind(_this);
|
|
897
1116
|
_this.requestHandler = requestHandler.bind(_this);
|
|
898
1117
|
_this.lambdaHandler = lambdaHandler.bind(_this);
|
|
@@ -905,13 +1124,9 @@ var Honeybadger = /** @class */ (function (_super) {
|
|
|
905
1124
|
Honeybadger.prototype.__send = function (notice) {
|
|
906
1125
|
var _this = this;
|
|
907
1126
|
var protocol = new url.URL(this.config.endpoint).protocol;
|
|
908
|
-
var transport = (protocol === "http:" ? http__default[
|
|
1127
|
+
var transport = (protocol === "http:" ? http__default["default"] : https__default["default"]);
|
|
909
1128
|
var payload = this.__buildPayload(notice);
|
|
910
1129
|
payload.server.pid = process.pid;
|
|
911
|
-
var handlers = Array.prototype.slice.call(this.__afterNotifyHandlers);
|
|
912
|
-
if (notice.afterNotify) {
|
|
913
|
-
handlers.unshift(notice.afterNotify);
|
|
914
|
-
}
|
|
915
1130
|
getStats(function (stats) {
|
|
916
1131
|
payload.server.stats = stats;
|
|
917
1132
|
var data = Buffer.from(JSON.stringify(sanitize(payload, _this.config.maxObjectDepth)), 'utf8');
|
|
@@ -924,32 +1139,50 @@ var Honeybadger = /** @class */ (function (_super) {
|
|
|
924
1139
|
}
|
|
925
1140
|
};
|
|
926
1141
|
var req = transport.request(endpoint(_this.config, '/v1/notices/js'), options, function (res) {
|
|
927
|
-
_this.logger.debug("statusCode: "
|
|
1142
|
+
_this.logger.debug("statusCode: ".concat(res.statusCode));
|
|
928
1143
|
var body = '';
|
|
929
1144
|
res.on('data', function (chunk) {
|
|
930
1145
|
body += chunk;
|
|
931
1146
|
});
|
|
932
1147
|
res.on('end', function () {
|
|
933
1148
|
if (res.statusCode !== 201) {
|
|
934
|
-
runAfterNotifyHandlers(notice,
|
|
935
|
-
_this.logger.warn("Error report failed: unknown response from server. code="
|
|
1149
|
+
runAfterNotifyHandlers(notice, _this.__afterNotifyHandlers, new Error("Bad HTTP response: ".concat(res.statusCode)));
|
|
1150
|
+
_this.logger.warn("Error report failed: unknown response from server. code=".concat(res.statusCode));
|
|
936
1151
|
return;
|
|
937
1152
|
}
|
|
938
1153
|
var uuid = JSON.parse(body).id;
|
|
939
1154
|
runAfterNotifyHandlers(merge(notice, {
|
|
940
1155
|
id: uuid
|
|
941
|
-
}),
|
|
942
|
-
_this.logger.info(
|
|
1156
|
+
}), _this.__afterNotifyHandlers);
|
|
1157
|
+
_this.logger.info("Error report sent \u26A1 https://app.honeybadger.io/notice/".concat(uuid));
|
|
943
1158
|
});
|
|
944
1159
|
});
|
|
945
1160
|
req.on('error', function (err) {
|
|
946
|
-
_this.logger.error('Error report failed: an unknown error occurred.', "message="
|
|
947
|
-
runAfterNotifyHandlers(notice,
|
|
1161
|
+
_this.logger.error('Error report failed: an unknown error occurred.', "message=".concat(err.message));
|
|
1162
|
+
runAfterNotifyHandlers(notice, _this.__afterNotifyHandlers, err);
|
|
948
1163
|
});
|
|
949
1164
|
req.write(data);
|
|
950
1165
|
req.end();
|
|
951
1166
|
});
|
|
952
|
-
|
|
1167
|
+
};
|
|
1168
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1169
|
+
Honeybadger.prototype.run = function (handler, onError) {
|
|
1170
|
+
var _this = this;
|
|
1171
|
+
var storeObject = this.__getStoreOrDefaultObject();
|
|
1172
|
+
this.__setStore(AsyncStore);
|
|
1173
|
+
if (onError) {
|
|
1174
|
+
// ALS is fine for context-tracking, but `domain` allows us to catch errors
|
|
1175
|
+
// thrown asynchronously (timers, event emitters)
|
|
1176
|
+
// We can't use unhandledRejection/uncaughtException listeners; they're global and shared across all requests
|
|
1177
|
+
// But the `onError` handler might be request-specific.
|
|
1178
|
+
// Note that this doesn't still handle all cases. `domain` has its own problems:
|
|
1179
|
+
// See https://github.com/honeybadger-io/honeybadger-js/pull/711
|
|
1180
|
+
var dom = domain__default["default"].create();
|
|
1181
|
+
var onErrorWithContext = function (err) { return _this.__store.run(storeObject, function () { return onError(err); }); };
|
|
1182
|
+
dom.on('error', onErrorWithContext);
|
|
1183
|
+
handler = dom.bind(handler);
|
|
1184
|
+
}
|
|
1185
|
+
return this.__store.run(storeObject, handler);
|
|
953
1186
|
};
|
|
954
1187
|
return Honeybadger;
|
|
955
1188
|
}(Client));
|
|
@@ -957,7 +1190,7 @@ var server = new Honeybadger({
|
|
|
957
1190
|
__plugins: [
|
|
958
1191
|
uncaughtException(),
|
|
959
1192
|
unhandledRejection()
|
|
960
|
-
]
|
|
1193
|
+
],
|
|
961
1194
|
});
|
|
962
1195
|
|
|
963
1196
|
module.exports = server;
|