@honeybadger-io/js 3.2.7 → 4.0.0-beta.1
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 -116
- 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/error.d.ts +3 -0
- 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 +4 -2
- package/dist/browser/types/server/async_store.d.ts +5 -0
- package/dist/browser/types/server/aws_lambda.d.ts +9 -0
- package/dist/browser/types/server/integrations/uncaught_exception.d.ts +2 -0
- package/dist/browser/types/server/integrations/unhandled_rejection.d.ts +2 -0
- package/dist/browser/types/server/middleware.d.ts +4 -0
- package/dist/browser/types/server/util.d.ts +9 -0
- package/dist/browser/types/server.d.ts +14 -0
- package/dist/server/honeybadger.d.ts +3 -1
- package/dist/server/honeybadger.js +375 -139
- package/dist/server/types/browser/integrations/breadcrumbs.d.ts +2 -0
- package/dist/server/types/browser/integrations/event_listeners.d.ts +2 -0
- package/dist/server/types/browser/integrations/onerror.d.ts +3 -0
- package/dist/server/types/browser/integrations/onunhandledrejection.d.ts +2 -0
- package/dist/server/types/browser/integrations/timers.d.ts +2 -0
- package/dist/server/types/browser/util.d.ts +18 -0
- package/dist/server/types/browser.d.ts +15 -0
- package/dist/server/types/core/client.d.ts +23 -3
- package/dist/server/types/core/error.d.ts +3 -0
- 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 +4 -2
- package/dist/server/types/server/async_store.d.ts +5 -0
- package/dist/server/types/server/aws_lambda.d.ts +9 -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
|
@@ -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,17 +238,39 @@ 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
|
}
|
|
@@ -309,7 +332,7 @@ function sanitize(obj, maxDepth) {
|
|
|
309
332
|
}
|
|
310
333
|
// Serialize inside arrays
|
|
311
334
|
if (Array.isArray(obj)) {
|
|
312
|
-
return obj.map(function (o) { return
|
|
335
|
+
return obj.map(function (o) { return safeSerialize(o, depth + 1); });
|
|
313
336
|
}
|
|
314
337
|
// Serialize inside objects
|
|
315
338
|
if (typeof (obj) === 'object') {
|
|
@@ -317,7 +340,7 @@ function sanitize(obj, maxDepth) {
|
|
|
317
340
|
for (var k in obj) {
|
|
318
341
|
var v = obj[k];
|
|
319
342
|
if (Object.prototype.hasOwnProperty.call(obj, k) && (k != null) && (v != null)) {
|
|
320
|
-
ret[k] =
|
|
343
|
+
ret[k] = safeSerialize(v, depth + 1);
|
|
321
344
|
}
|
|
322
345
|
}
|
|
323
346
|
return ret;
|
|
@@ -325,7 +348,16 @@ function sanitize(obj, maxDepth) {
|
|
|
325
348
|
// Return everything else untouched
|
|
326
349
|
return obj;
|
|
327
350
|
}
|
|
328
|
-
|
|
351
|
+
function safeSerialize(obj, depth) {
|
|
352
|
+
if (depth === void 0) { depth = 0; }
|
|
353
|
+
try {
|
|
354
|
+
return serialize(obj, depth);
|
|
355
|
+
}
|
|
356
|
+
catch (e) {
|
|
357
|
+
return "[ERROR] ".concat(e);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return safeSerialize(obj);
|
|
329
361
|
}
|
|
330
362
|
function logger(client) {
|
|
331
363
|
var log = function (method) {
|
|
@@ -335,8 +367,13 @@ function logger(client) {
|
|
|
335
367
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
336
368
|
args[_i] = arguments[_i];
|
|
337
369
|
}
|
|
338
|
-
if (method === 'debug'
|
|
339
|
-
|
|
370
|
+
if (method === 'debug') {
|
|
371
|
+
if (!client.config.debug) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
// Log at default level so that you don't need to also enable verbose
|
|
375
|
+
// logging in Chrome.
|
|
376
|
+
method = 'log';
|
|
340
377
|
}
|
|
341
378
|
args.unshift('[Honeybadger]');
|
|
342
379
|
(_a = client.config.logger)[method].apply(_a, args);
|
|
@@ -359,7 +396,7 @@ function makeNotice(thing) {
|
|
|
359
396
|
if (!thing) {
|
|
360
397
|
notice = {};
|
|
361
398
|
}
|
|
362
|
-
else if (Object.prototype.toString.call(thing) === '[object Error]') {
|
|
399
|
+
else if (thing instanceof Error || Object.prototype.toString.call(thing) === '[object Error]') {
|
|
363
400
|
var e = thing;
|
|
364
401
|
notice = merge(thing, { name: e.name, message: e.message, stack: e.stack });
|
|
365
402
|
}
|
|
@@ -375,7 +412,7 @@ function makeNotice(thing) {
|
|
|
375
412
|
function endpoint(config, path) {
|
|
376
413
|
var endpoint = config.endpoint.trim().replace(/\/$/, '');
|
|
377
414
|
path = path.trim().replace(/(^\/|\/$)/g, '');
|
|
378
|
-
return endpoint
|
|
415
|
+
return "".concat(endpoint, "/").concat(path);
|
|
379
416
|
}
|
|
380
417
|
function generateStackTrace() {
|
|
381
418
|
try {
|
|
@@ -434,7 +471,9 @@ function filter(obj, filters) {
|
|
|
434
471
|
return newObj;
|
|
435
472
|
}
|
|
436
473
|
if (is('Array', obj)) {
|
|
437
|
-
return obj.map(function (v) {
|
|
474
|
+
return obj.map(function (v) {
|
|
475
|
+
return filter(v);
|
|
476
|
+
});
|
|
438
477
|
}
|
|
439
478
|
if (is('Function', obj)) {
|
|
440
479
|
return '[FUNC]';
|
|
@@ -470,7 +509,7 @@ function filterUrl(url, filters) {
|
|
|
470
509
|
query.split(/[&]\s?/).forEach(function (pair) {
|
|
471
510
|
var _a = pair.split('=', 2), key = _a[0], value = _a[1];
|
|
472
511
|
if (filterMatch(key, filters)) {
|
|
473
|
-
result = result.replace(key
|
|
512
|
+
result = result.replace("".concat(key, "=").concat(value), "".concat(key, "=[FILTERED]"));
|
|
474
513
|
}
|
|
475
514
|
});
|
|
476
515
|
return result;
|
|
@@ -484,34 +523,64 @@ function formatCGIData(vars, prefix) {
|
|
|
484
523
|
});
|
|
485
524
|
return formattedVars;
|
|
486
525
|
}
|
|
526
|
+
function getSourceCodeSnippet(fileData, lineNumber, sourceRadius) {
|
|
527
|
+
if (sourceRadius === void 0) { sourceRadius = 2; }
|
|
528
|
+
if (!fileData) {
|
|
529
|
+
return null;
|
|
530
|
+
}
|
|
531
|
+
var lines = fileData.split('\n');
|
|
532
|
+
// add one empty line because array index starts from 0, but error line number is counted from 1
|
|
533
|
+
lines.unshift('');
|
|
534
|
+
var start = lineNumber - sourceRadius;
|
|
535
|
+
var end = lineNumber + sourceRadius;
|
|
536
|
+
var result = {};
|
|
537
|
+
for (var i = start; i <= end; i++) {
|
|
538
|
+
var line = lines[i];
|
|
539
|
+
if (typeof line === 'string') {
|
|
540
|
+
result[i] = line;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return result;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
var GlobalStore$1 = /** @class */ (function () {
|
|
547
|
+
function GlobalStore(store) {
|
|
548
|
+
this.store = store;
|
|
549
|
+
}
|
|
550
|
+
GlobalStore.prototype.getStore = function () {
|
|
551
|
+
return this.store;
|
|
552
|
+
};
|
|
553
|
+
GlobalStore.prototype.run = function (store, callback) {
|
|
554
|
+
var args = [];
|
|
555
|
+
for (var _i = 2; _i < arguments.length; _i++) {
|
|
556
|
+
args[_i - 2] = arguments[_i];
|
|
557
|
+
}
|
|
558
|
+
this.store = store;
|
|
559
|
+
return callback.apply(void 0, args);
|
|
560
|
+
};
|
|
561
|
+
return GlobalStore;
|
|
562
|
+
}());
|
|
487
563
|
|
|
488
564
|
var notifier = {
|
|
489
565
|
name: 'honeybadger-js',
|
|
490
566
|
url: 'https://github.com/honeybadger-io/honeybadger-js',
|
|
491
|
-
version: '
|
|
567
|
+
version: '4.0.0-beta.1'
|
|
492
568
|
};
|
|
493
|
-
// Split at commas
|
|
494
|
-
var TAG_SEPARATOR =
|
|
495
|
-
// Removes any non-word characters
|
|
496
|
-
var TAG_SANITIZER = /[^\w]/g;
|
|
497
|
-
// Checks for blank strings
|
|
498
|
-
var STRING_EMPTY = '';
|
|
569
|
+
// Split at commas and spaces
|
|
570
|
+
var TAG_SEPARATOR = /,|\s+/;
|
|
499
571
|
// Checks for non-blank characters
|
|
500
572
|
var NOT_BLANK = /\S/;
|
|
501
573
|
var Client = /** @class */ (function () {
|
|
502
574
|
function Client(opts) {
|
|
503
575
|
if (opts === void 0) { opts = {}; }
|
|
504
|
-
/** @internal */
|
|
505
576
|
this.__pluginsExecuted = false;
|
|
506
|
-
|
|
507
|
-
this.__context = {};
|
|
508
|
-
/** @internal */
|
|
509
|
-
this.__breadcrumbs = [];
|
|
510
|
-
/** @internal */
|
|
577
|
+
this.__store = null;
|
|
511
578
|
this.__beforeNotifyHandlers = [];
|
|
512
|
-
/** @internal */
|
|
513
579
|
this.__afterNotifyHandlers = [];
|
|
514
|
-
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'],
|
|
580
|
+
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);
|
|
581
|
+
// First, we go with the global (shared) store.
|
|
582
|
+
// Webserver middleware can then switch to the AsyncStore for async context tracking.
|
|
583
|
+
this.__store = new GlobalStore$1({ context: {}, breadcrumbs: [] });
|
|
515
584
|
this.logger = logger(this);
|
|
516
585
|
}
|
|
517
586
|
Client.prototype.factory = function (_opts) {
|
|
@@ -532,6 +601,10 @@ var Client = /** @class */ (function () {
|
|
|
532
601
|
}
|
|
533
602
|
return this;
|
|
534
603
|
};
|
|
604
|
+
/** @internal */
|
|
605
|
+
Client.prototype.__setStore = function (store) {
|
|
606
|
+
this.__store = store;
|
|
607
|
+
};
|
|
535
608
|
Client.prototype.beforeNotify = function (handler) {
|
|
536
609
|
this.__beforeNotifyHandlers.push(handler);
|
|
537
610
|
return this;
|
|
@@ -542,41 +615,129 @@ var Client = /** @class */ (function () {
|
|
|
542
615
|
};
|
|
543
616
|
Client.prototype.setContext = function (context) {
|
|
544
617
|
if (typeof context === 'object') {
|
|
545
|
-
|
|
618
|
+
var store = this.__store.getStore();
|
|
619
|
+
store.context = merge(store.context, context);
|
|
546
620
|
}
|
|
547
621
|
return this;
|
|
548
622
|
};
|
|
549
623
|
Client.prototype.resetContext = function (context) {
|
|
550
624
|
this.logger.warn('Deprecation warning: `Honeybadger.resetContext()` has been deprecated; please use `Honeybadger.clear()` instead.');
|
|
625
|
+
var store = this.__store.getStore();
|
|
551
626
|
if (typeof context === 'object' && context !== null) {
|
|
552
|
-
|
|
627
|
+
store.context = context;
|
|
553
628
|
}
|
|
554
629
|
else {
|
|
555
|
-
|
|
630
|
+
store.context = {};
|
|
556
631
|
}
|
|
557
632
|
return this;
|
|
558
633
|
};
|
|
559
634
|
Client.prototype.clear = function () {
|
|
560
|
-
|
|
561
|
-
|
|
635
|
+
var store = this.__store.getStore();
|
|
636
|
+
store.context = {};
|
|
637
|
+
store.breadcrumbs = [];
|
|
562
638
|
return this;
|
|
563
639
|
};
|
|
564
|
-
Client.prototype.notify = function (
|
|
640
|
+
Client.prototype.notify = function (noticeable, name, extra) {
|
|
641
|
+
var _this = this;
|
|
565
642
|
if (name === void 0) { name = undefined; }
|
|
566
643
|
if (extra === void 0) { extra = undefined; }
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
644
|
+
var preConditionError = null;
|
|
645
|
+
var notice = this.makeNotice(noticeable, name, extra);
|
|
646
|
+
if (!notice) {
|
|
647
|
+
this.logger.debug('failed to build error report');
|
|
648
|
+
preConditionError = new Error('failed to build error report');
|
|
570
649
|
}
|
|
571
|
-
if (!this.
|
|
572
|
-
this.logger.debug('
|
|
573
|
-
|
|
650
|
+
if (!preConditionError && this.config.reportData === false) {
|
|
651
|
+
this.logger.debug('skipping error report: honeybadger.js is disabled', notice);
|
|
652
|
+
preConditionError = new Error('honeybadger.js is disabled');
|
|
574
653
|
}
|
|
575
|
-
if (!this.
|
|
576
|
-
this.logger.
|
|
654
|
+
if (!preConditionError && this.__developmentMode()) {
|
|
655
|
+
this.logger.log('honeybadger.js is in development mode; the following error report will be sent in production.', notice);
|
|
656
|
+
preConditionError = new Error('honeybadger.js is in development mode');
|
|
657
|
+
}
|
|
658
|
+
if (!preConditionError && !this.config.apiKey) {
|
|
659
|
+
this.logger.warn('could not send error report: no API key has been configured', notice);
|
|
660
|
+
preConditionError = new Error('missing API key');
|
|
661
|
+
}
|
|
662
|
+
var beforeNotifyResult = runBeforeNotifyHandlers(notice, this.__beforeNotifyHandlers);
|
|
663
|
+
if (!preConditionError && !beforeNotifyResult) {
|
|
664
|
+
this.logger.debug('skipping error report: beforeNotify handlers returned false', notice);
|
|
665
|
+
preConditionError = new Error('beforeNotify handlers returned false');
|
|
666
|
+
}
|
|
667
|
+
if (preConditionError) {
|
|
668
|
+
runAfterNotifyHandlers(notice, this.__afterNotifyHandlers, preConditionError);
|
|
577
669
|
return false;
|
|
578
670
|
}
|
|
579
|
-
|
|
671
|
+
this.addBreadcrumb('Honeybadger Notice', {
|
|
672
|
+
category: 'notice',
|
|
673
|
+
metadata: {
|
|
674
|
+
message: notice.message,
|
|
675
|
+
name: notice.name,
|
|
676
|
+
stack: notice.stack
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
var breadcrumbs = this.__getStoreOrDefaultObject().breadcrumbs;
|
|
680
|
+
notice.__breadcrumbs = this.config.breadcrumbsEnabled ? breadcrumbs.slice() : [];
|
|
681
|
+
// we need to have the source file data before the beforeNotifyHandlers,
|
|
682
|
+
// in case they modify them
|
|
683
|
+
var sourceCodeData = notice && notice.backtrace ? notice.backtrace.map(function (trace) { return newObject(trace); }) : null;
|
|
684
|
+
getSourceForBacktrace(sourceCodeData, this.__getSourceFileHandler, function (sourcePerTrace) {
|
|
685
|
+
sourcePerTrace.forEach(function (source, index) {
|
|
686
|
+
notice.backtrace[index].source = source;
|
|
687
|
+
});
|
|
688
|
+
_this.__send(notice);
|
|
689
|
+
});
|
|
690
|
+
return true;
|
|
691
|
+
};
|
|
692
|
+
/**
|
|
693
|
+
* An async version of {@link notify} that resolves only after the notice has been reported to Honeybadger.
|
|
694
|
+
* Implemented using the {@link afterNotify} hook.
|
|
695
|
+
* Rejects if for any reason the report failed to be reported.
|
|
696
|
+
* Useful in serverless environments (AWS Lambda).
|
|
697
|
+
*/
|
|
698
|
+
Client.prototype.notifyAsync = function (noticeable, name, extra) {
|
|
699
|
+
var _this = this;
|
|
700
|
+
if (name === void 0) { name = undefined; }
|
|
701
|
+
if (extra === void 0) { extra = undefined; }
|
|
702
|
+
return new Promise(function (resolve, reject) {
|
|
703
|
+
var applyAfterNotify = function (partialNotice) {
|
|
704
|
+
var originalAfterNotify = partialNotice.afterNotify;
|
|
705
|
+
partialNotice.afterNotify = function (err) {
|
|
706
|
+
originalAfterNotify === null || originalAfterNotify === void 0 ? void 0 : originalAfterNotify.call(_this, err);
|
|
707
|
+
if (err) {
|
|
708
|
+
return reject(err);
|
|
709
|
+
}
|
|
710
|
+
resolve();
|
|
711
|
+
};
|
|
712
|
+
};
|
|
713
|
+
// We have to respect any afterNotify hooks that come from the arguments
|
|
714
|
+
var objectToOverride;
|
|
715
|
+
if (noticeable.afterNotify) {
|
|
716
|
+
objectToOverride = noticeable;
|
|
717
|
+
}
|
|
718
|
+
else if (name && name.afterNotify) {
|
|
719
|
+
objectToOverride = name;
|
|
720
|
+
}
|
|
721
|
+
else if (extra && extra.afterNotify) {
|
|
722
|
+
objectToOverride = extra;
|
|
723
|
+
}
|
|
724
|
+
else if (name && typeof name === 'object') {
|
|
725
|
+
objectToOverride = name;
|
|
726
|
+
}
|
|
727
|
+
else if (extra) {
|
|
728
|
+
objectToOverride = extra;
|
|
729
|
+
}
|
|
730
|
+
else {
|
|
731
|
+
objectToOverride = name = {};
|
|
732
|
+
}
|
|
733
|
+
applyAfterNotify(objectToOverride);
|
|
734
|
+
_this.notify(noticeable, name, extra);
|
|
735
|
+
});
|
|
736
|
+
};
|
|
737
|
+
Client.prototype.makeNotice = function (noticeable, name, extra) {
|
|
738
|
+
if (name === void 0) { name = undefined; }
|
|
739
|
+
if (extra === void 0) { extra = undefined; }
|
|
740
|
+
var notice = makeNotice(noticeable);
|
|
580
741
|
if (name && !(typeof name === 'object')) {
|
|
581
742
|
var n = String(name);
|
|
582
743
|
name = { name: n };
|
|
@@ -588,17 +749,18 @@ var Client = /** @class */ (function () {
|
|
|
588
749
|
notice = mergeNotice(notice, extra);
|
|
589
750
|
}
|
|
590
751
|
if (objectIsEmpty(notice)) {
|
|
591
|
-
return
|
|
752
|
+
return null;
|
|
592
753
|
}
|
|
754
|
+
var context = this.__getStoreOrDefaultObject().context;
|
|
593
755
|
var noticeTags = this.__constructTags(notice.tags);
|
|
594
|
-
var contextTags = this.__constructTags(
|
|
756
|
+
var contextTags = this.__constructTags(context["tags"]);
|
|
595
757
|
var configTags = this.__constructTags(this.config.tags);
|
|
596
758
|
// Turning into a Set will remove duplicates
|
|
597
759
|
var tags = noticeTags.concat(contextTags).concat(configTags);
|
|
598
760
|
var uniqueTags = tags.filter(function (item, index) { return tags.indexOf(item) === index; });
|
|
599
761
|
notice = merge(notice, {
|
|
600
762
|
name: notice.name || 'Error',
|
|
601
|
-
context: merge(
|
|
763
|
+
context: merge(context, notice.context),
|
|
602
764
|
projectRoot: notice.projectRoot || this.config.projectRoot,
|
|
603
765
|
environment: notice.environment || this.config.environment,
|
|
604
766
|
component: notice.component || this.config.component,
|
|
@@ -612,19 +774,7 @@ var Client = /** @class */ (function () {
|
|
|
612
774
|
backtraceShift = 2;
|
|
613
775
|
}
|
|
614
776
|
notice.backtrace = makeBacktrace(notice.stack, backtraceShift);
|
|
615
|
-
|
|
616
|
-
return false;
|
|
617
|
-
}
|
|
618
|
-
this.addBreadcrumb('Honeybadger Notice', {
|
|
619
|
-
category: 'notice',
|
|
620
|
-
metadata: {
|
|
621
|
-
message: notice.message,
|
|
622
|
-
name: notice.name,
|
|
623
|
-
stack: notice.stack
|
|
624
|
-
}
|
|
625
|
-
});
|
|
626
|
-
notice.__breadcrumbs = this.config.breadcrumbsEnabled ? this.__breadcrumbs.slice() : [];
|
|
627
|
-
return this.__send(notice);
|
|
777
|
+
return notice;
|
|
628
778
|
};
|
|
629
779
|
Client.prototype.addBreadcrumb = function (message, opts) {
|
|
630
780
|
if (!this.config.breadcrumbsEnabled) {
|
|
@@ -634,30 +784,30 @@ var Client = /** @class */ (function () {
|
|
|
634
784
|
var metadata = newObject(opts.metadata);
|
|
635
785
|
var category = opts.category || 'custom';
|
|
636
786
|
var timestamp = new Date().toISOString();
|
|
637
|
-
this.
|
|
787
|
+
var store = this.__store.getStore();
|
|
788
|
+
var breadcrumbs = store.breadcrumbs;
|
|
789
|
+
breadcrumbs.push({
|
|
638
790
|
category: category,
|
|
639
791
|
message: message,
|
|
640
792
|
metadata: metadata,
|
|
641
793
|
timestamp: timestamp
|
|
642
794
|
});
|
|
643
795
|
var limit = this.config.maxBreadcrumbs;
|
|
644
|
-
if (
|
|
645
|
-
|
|
796
|
+
if (breadcrumbs.length > limit) {
|
|
797
|
+
breadcrumbs = breadcrumbs.slice(breadcrumbs.length - limit);
|
|
646
798
|
}
|
|
799
|
+
store.breadcrumbs = breadcrumbs;
|
|
647
800
|
return this;
|
|
648
801
|
};
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
return this.config.reportData;
|
|
802
|
+
Client.prototype.__developmentMode = function () {
|
|
803
|
+
if (this.config.reportData === true) {
|
|
804
|
+
return false;
|
|
653
805
|
}
|
|
654
|
-
return
|
|
806
|
+
return (this.config.environment && this.config.developmentEnvironments.includes(this.config.environment));
|
|
655
807
|
};
|
|
656
|
-
/** @internal */
|
|
657
808
|
Client.prototype.__send = function (_notice) {
|
|
658
809
|
throw (new Error('Must implement send in subclass'));
|
|
659
810
|
};
|
|
660
|
-
/** @internal */
|
|
661
811
|
Client.prototype.__buildPayload = function (notice) {
|
|
662
812
|
var headers = filter(notice.headers, this.config.filters) || {};
|
|
663
813
|
var cgiData = filter(__assign(__assign({}, notice.cgiData), formatCGIData(headers, 'HTTP_')), this.config.filters);
|
|
@@ -693,14 +843,22 @@ var Client = /** @class */ (function () {
|
|
|
693
843
|
details: notice.details || {}
|
|
694
844
|
};
|
|
695
845
|
};
|
|
696
|
-
/** @internal */
|
|
697
846
|
Client.prototype.__constructTags = function (tags) {
|
|
698
847
|
if (!tags) {
|
|
699
848
|
return [];
|
|
700
849
|
}
|
|
701
|
-
return tags.toString().split(TAG_SEPARATOR).
|
|
702
|
-
|
|
703
|
-
|
|
850
|
+
return tags.toString().split(TAG_SEPARATOR).filter(function (tag) { return NOT_BLANK.test(tag); });
|
|
851
|
+
};
|
|
852
|
+
/**
|
|
853
|
+
* For ALS, the store may be uninitialized (if .run()` has not been called).
|
|
854
|
+
* This provides an easy way to read the existing store object or fall back to a default.
|
|
855
|
+
* Returns *a copy* of the store.
|
|
856
|
+
* @internal
|
|
857
|
+
*/
|
|
858
|
+
Client.prototype.__getStoreOrDefaultObject = function () {
|
|
859
|
+
var existingStore = this.__store.getStore();
|
|
860
|
+
var store = existingStore || {};
|
|
861
|
+
return __assign({ context: {}, breadcrumbs: [] }, store);
|
|
704
862
|
};
|
|
705
863
|
return Client;
|
|
706
864
|
}());
|
|
@@ -711,7 +869,7 @@ function fatallyLogAndExit(err) {
|
|
|
711
869
|
process.exit(1);
|
|
712
870
|
}
|
|
713
871
|
function getStats(cb) {
|
|
714
|
-
var load = os__default[
|
|
872
|
+
var load = os__default["default"].loadavg(), stats = {
|
|
715
873
|
load: {
|
|
716
874
|
one: load[0],
|
|
717
875
|
five: load[1],
|
|
@@ -719,8 +877,8 @@ function getStats(cb) {
|
|
|
719
877
|
},
|
|
720
878
|
mem: {}
|
|
721
879
|
};
|
|
722
|
-
if (fs__default[
|
|
723
|
-
return fs__default[
|
|
880
|
+
if (fs__default["default"].existsSync('/proc/meminfo')) {
|
|
881
|
+
return fs__default["default"].readFile('/proc/meminfo', 'utf8', parseStats);
|
|
724
882
|
}
|
|
725
883
|
fallback();
|
|
726
884
|
function parseStats(err, memData) {
|
|
@@ -743,21 +901,125 @@ function getStats(cb) {
|
|
|
743
901
|
}
|
|
744
902
|
function fallback() {
|
|
745
903
|
stats.mem = {
|
|
746
|
-
free: os__default[
|
|
747
|
-
total: os__default[
|
|
904
|
+
free: os__default["default"].freemem(),
|
|
905
|
+
total: os__default["default"].totalmem()
|
|
748
906
|
};
|
|
749
907
|
return cb(stats);
|
|
750
908
|
}
|
|
751
909
|
}
|
|
910
|
+
/**
|
|
911
|
+
* Get source file if possible, used to build `notice.backtrace.source`
|
|
912
|
+
*
|
|
913
|
+
* @param path to source code
|
|
914
|
+
* @param cb callback with fileContent
|
|
915
|
+
*/
|
|
916
|
+
function getSourceFile(path, cb) {
|
|
917
|
+
fs__default["default"].readFile(path, 'utf-8', function (err, data) {
|
|
918
|
+
cb(err ? null : data);
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
var Store;
|
|
923
|
+
try {
|
|
924
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
925
|
+
var AsyncLocalStorage = require('async_hooks').AsyncLocalStorage;
|
|
926
|
+
Store = new AsyncLocalStorage();
|
|
927
|
+
}
|
|
928
|
+
catch (e) {
|
|
929
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
930
|
+
var GlobalStore = require('../core/store').GlobalStore;
|
|
931
|
+
Store = new GlobalStore();
|
|
932
|
+
}
|
|
933
|
+
var AsyncStore = Store;
|
|
934
|
+
|
|
935
|
+
function isHandlerSync(handler) {
|
|
936
|
+
return handler.length > 2;
|
|
937
|
+
}
|
|
938
|
+
function reportToHoneybadger(hb, err, callback) {
|
|
939
|
+
hb.notify(err, {
|
|
940
|
+
afterNotify: function () {
|
|
941
|
+
hb.clear();
|
|
942
|
+
callback(err);
|
|
943
|
+
}
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
function asyncHandler(handler, hb) {
|
|
947
|
+
return function wrappedLambdaHandler(event, context) {
|
|
948
|
+
hb.__setStore(AsyncStore);
|
|
949
|
+
return new Promise(function (resolve, reject) {
|
|
950
|
+
AsyncStore.run({ context: {}, breadcrumbs: [] }, function () {
|
|
951
|
+
try {
|
|
952
|
+
handler(event, context)
|
|
953
|
+
.then(resolve)
|
|
954
|
+
.catch(function (err) { return reportToHoneybadger(hb, err, reject); });
|
|
955
|
+
}
|
|
956
|
+
catch (err) {
|
|
957
|
+
reportToHoneybadger(hb, err, reject);
|
|
958
|
+
}
|
|
959
|
+
});
|
|
960
|
+
});
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
function syncHandler(handler, hb) {
|
|
964
|
+
return function wrappedLambdaHandler(event, context, cb) {
|
|
965
|
+
hb.__setStore(AsyncStore);
|
|
966
|
+
AsyncStore.run({ context: {}, breadcrumbs: [] }, function () {
|
|
967
|
+
try {
|
|
968
|
+
handler(event, context, function (error, result) {
|
|
969
|
+
if (error) {
|
|
970
|
+
return reportToHoneybadger(hb, error, cb);
|
|
971
|
+
}
|
|
972
|
+
cb(null, result);
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
catch (err) {
|
|
976
|
+
reportToHoneybadger(hb, err, cb);
|
|
977
|
+
}
|
|
978
|
+
});
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
function lambdaHandler(handler) {
|
|
982
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
983
|
+
var hb = this;
|
|
984
|
+
if (isHandlerSync(handler)) {
|
|
985
|
+
return syncHandler(handler, hb);
|
|
986
|
+
}
|
|
987
|
+
return asyncHandler(handler, hb);
|
|
988
|
+
}
|
|
989
|
+
var listenerRemoved = false;
|
|
990
|
+
/**
|
|
991
|
+
* Removes AWS Lambda default listener that
|
|
992
|
+
* exits the process before letting us report to honeybadger.
|
|
993
|
+
*/
|
|
994
|
+
function removeAwsDefaultUncaughtExceptionListener() {
|
|
995
|
+
if (listenerRemoved) {
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
listenerRemoved = true;
|
|
999
|
+
var listeners = process.listeners('uncaughtException');
|
|
1000
|
+
if (listeners.length === 0) {
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
// We assume it's the first listener
|
|
1004
|
+
process.removeListener('uncaughtException', listeners[0]);
|
|
1005
|
+
}
|
|
752
1006
|
|
|
753
1007
|
var count = 0;
|
|
1008
|
+
function removeAwsLambdaListener() {
|
|
1009
|
+
var isLambda = !!process.env.LAMBDA_TASK_ROOT;
|
|
1010
|
+
if (!isLambda) {
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
removeAwsDefaultUncaughtExceptionListener();
|
|
1014
|
+
}
|
|
754
1015
|
function uncaughtException () {
|
|
755
1016
|
return {
|
|
756
1017
|
load: function (client) {
|
|
757
1018
|
if (!client.config.enableUncaught) {
|
|
758
1019
|
return;
|
|
759
1020
|
}
|
|
760
|
-
|
|
1021
|
+
removeAwsLambdaListener();
|
|
1022
|
+
process.on('uncaughtException', function honeybadgerUncaughtExceptionListener(uncaughtError) {
|
|
761
1023
|
// Prevent recursive errors
|
|
762
1024
|
if (count > 1) {
|
|
763
1025
|
fatallyLogAndExit(uncaughtError);
|
|
@@ -801,7 +1063,7 @@ function fullUrl(req) {
|
|
|
801
1063
|
// @ts-ignore The old @types/node incorrectly defines `address` as string|Address
|
|
802
1064
|
var port = address ? address.port : undefined;
|
|
803
1065
|
// @ts-ignore
|
|
804
|
-
return url__default[
|
|
1066
|
+
return url__default["default"].format({
|
|
805
1067
|
protocol: req.protocol,
|
|
806
1068
|
hostname: req.hostname,
|
|
807
1069
|
port: port,
|
|
@@ -810,10 +1072,7 @@ function fullUrl(req) {
|
|
|
810
1072
|
});
|
|
811
1073
|
}
|
|
812
1074
|
function requestHandler(req, res, next) {
|
|
813
|
-
this.
|
|
814
|
-
var dom = domain__default['default'].create();
|
|
815
|
-
dom.on('error', next);
|
|
816
|
-
dom.run(next);
|
|
1075
|
+
this.run(next, next);
|
|
817
1076
|
}
|
|
818
1077
|
function errorHandler(err, req, _res, next) {
|
|
819
1078
|
this.notify(err, {
|
|
@@ -828,50 +1087,12 @@ function errorHandler(err, req, _res, next) {
|
|
|
828
1087
|
});
|
|
829
1088
|
return next(err);
|
|
830
1089
|
}
|
|
831
|
-
function lambdaHandler(handler) {
|
|
832
|
-
return function lambdaHandler(event, context, callback) {
|
|
833
|
-
// in the case of an async handler, the length of the handler will be less than 3 (no callback function).
|
|
834
|
-
// if this is the case, we have to explicitly call the callback function from the function we are returning.
|
|
835
|
-
// we don't have to do that if the handler has third callback function parameter,
|
|
836
|
-
// because it will be called directly from inside the handler.
|
|
837
|
-
var shouldInvokeCallbackExplicitly = handler.length < 3;
|
|
838
|
-
// eslint-disable-next-line prefer-rest-params
|
|
839
|
-
var args = arguments;
|
|
840
|
-
var dom = domain__default['default'].create();
|
|
841
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
842
|
-
var hb = this;
|
|
843
|
-
var hbHandler = function (err) {
|
|
844
|
-
var willNotify = hb.notify(err, {
|
|
845
|
-
afterNotify: function () {
|
|
846
|
-
hb.clear();
|
|
847
|
-
callback(err);
|
|
848
|
-
}
|
|
849
|
-
});
|
|
850
|
-
if (!willNotify) {
|
|
851
|
-
callback(err);
|
|
852
|
-
}
|
|
853
|
-
};
|
|
854
|
-
dom.on('error', hbHandler);
|
|
855
|
-
dom.run(function () {
|
|
856
|
-
process.nextTick(function () {
|
|
857
|
-
Promise.resolve(handler.apply(this, args))
|
|
858
|
-
.then(function (res) {
|
|
859
|
-
hb.clear();
|
|
860
|
-
if (shouldInvokeCallbackExplicitly) {
|
|
861
|
-
callback(null, res);
|
|
862
|
-
}
|
|
863
|
-
})
|
|
864
|
-
.catch(hbHandler);
|
|
865
|
-
});
|
|
866
|
-
});
|
|
867
|
-
}.bind(this);
|
|
868
|
-
}
|
|
869
1090
|
|
|
870
1091
|
var Honeybadger = /** @class */ (function (_super) {
|
|
871
1092
|
__extends(Honeybadger, _super);
|
|
872
1093
|
function Honeybadger(opts) {
|
|
873
1094
|
if (opts === void 0) { opts = {}; }
|
|
874
|
-
var _this = _super.call(this, __assign({ afterUncaught: fatallyLogAndExit, projectRoot: process.cwd(), hostname: os__default[
|
|
1095
|
+
var _this = _super.call(this, __assign({ afterUncaught: fatallyLogAndExit, projectRoot: process.cwd(), hostname: os__default["default"].hostname() }, opts)) || this;
|
|
875
1096
|
/** @internal */
|
|
876
1097
|
_this.__beforeNotifyHandlers = [
|
|
877
1098
|
function (notice) {
|
|
@@ -884,6 +1105,7 @@ var Honeybadger = /** @class */ (function (_super) {
|
|
|
884
1105
|
});
|
|
885
1106
|
}
|
|
886
1107
|
];
|
|
1108
|
+
_this.__getSourceFileHandler = getSourceFile.bind(_this);
|
|
887
1109
|
_this.errorHandler = errorHandler.bind(_this);
|
|
888
1110
|
_this.requestHandler = requestHandler.bind(_this);
|
|
889
1111
|
_this.lambdaHandler = lambdaHandler.bind(_this);
|
|
@@ -896,13 +1118,9 @@ var Honeybadger = /** @class */ (function (_super) {
|
|
|
896
1118
|
Honeybadger.prototype.__send = function (notice) {
|
|
897
1119
|
var _this = this;
|
|
898
1120
|
var protocol = new url.URL(this.config.endpoint).protocol;
|
|
899
|
-
var transport = (protocol === "http:" ? http__default[
|
|
1121
|
+
var transport = (protocol === "http:" ? http__default["default"] : https__default["default"]);
|
|
900
1122
|
var payload = this.__buildPayload(notice);
|
|
901
1123
|
payload.server.pid = process.pid;
|
|
902
|
-
var handlers = Array.prototype.slice.call(this.__afterNotifyHandlers);
|
|
903
|
-
if (notice.afterNotify) {
|
|
904
|
-
handlers.unshift(notice.afterNotify);
|
|
905
|
-
}
|
|
906
1124
|
getStats(function (stats) {
|
|
907
1125
|
payload.server.stats = stats;
|
|
908
1126
|
var data = Buffer.from(JSON.stringify(sanitize(payload, _this.config.maxObjectDepth)), 'utf8');
|
|
@@ -915,32 +1133,50 @@ var Honeybadger = /** @class */ (function (_super) {
|
|
|
915
1133
|
}
|
|
916
1134
|
};
|
|
917
1135
|
var req = transport.request(endpoint(_this.config, '/v1/notices/js'), options, function (res) {
|
|
918
|
-
_this.logger.debug("statusCode: "
|
|
1136
|
+
_this.logger.debug("statusCode: ".concat(res.statusCode));
|
|
919
1137
|
var body = '';
|
|
920
1138
|
res.on('data', function (chunk) {
|
|
921
1139
|
body += chunk;
|
|
922
1140
|
});
|
|
923
1141
|
res.on('end', function () {
|
|
924
1142
|
if (res.statusCode !== 201) {
|
|
925
|
-
runAfterNotifyHandlers(notice,
|
|
926
|
-
_this.logger.warn("Error report failed: unknown response from server. code="
|
|
1143
|
+
runAfterNotifyHandlers(notice, _this.__afterNotifyHandlers, new Error("Bad HTTP response: ".concat(res.statusCode)));
|
|
1144
|
+
_this.logger.warn("Error report failed: unknown response from server. code=".concat(res.statusCode));
|
|
927
1145
|
return;
|
|
928
1146
|
}
|
|
929
1147
|
var uuid = JSON.parse(body).id;
|
|
930
1148
|
runAfterNotifyHandlers(merge(notice, {
|
|
931
1149
|
id: uuid
|
|
932
|
-
}),
|
|
933
|
-
_this.logger.info(
|
|
1150
|
+
}), _this.__afterNotifyHandlers);
|
|
1151
|
+
_this.logger.info("Error report sent \u26A1 https://app.honeybadger.io/notice/".concat(uuid));
|
|
934
1152
|
});
|
|
935
1153
|
});
|
|
936
1154
|
req.on('error', function (err) {
|
|
937
|
-
_this.logger.error('Error report failed: an unknown error occurred.', "message="
|
|
938
|
-
runAfterNotifyHandlers(notice,
|
|
1155
|
+
_this.logger.error('Error report failed: an unknown error occurred.', "message=".concat(err.message));
|
|
1156
|
+
runAfterNotifyHandlers(notice, _this.__afterNotifyHandlers, err);
|
|
939
1157
|
});
|
|
940
1158
|
req.write(data);
|
|
941
1159
|
req.end();
|
|
942
1160
|
});
|
|
943
|
-
|
|
1161
|
+
};
|
|
1162
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1163
|
+
Honeybadger.prototype.run = function (handler, onError) {
|
|
1164
|
+
var _this = this;
|
|
1165
|
+
var storeObject = this.__getStoreOrDefaultObject();
|
|
1166
|
+
this.__setStore(AsyncStore);
|
|
1167
|
+
if (onError) {
|
|
1168
|
+
// ALS is fine for context-tracking, but `domain` allows us to catch errors
|
|
1169
|
+
// thrown asynchronously (timers, event emitters)
|
|
1170
|
+
// We can't use unhandledRejection/uncaughtException listeners; they're global and shared across all requests
|
|
1171
|
+
// But the `onError` handler might be request-specific.
|
|
1172
|
+
// Note that this doesn't still handle all cases. `domain` has its own problems:
|
|
1173
|
+
// See https://github.com/honeybadger-io/honeybadger-js/pull/711
|
|
1174
|
+
var dom = domain__default["default"].create();
|
|
1175
|
+
var onErrorWithContext = function (err) { return _this.__store.run(storeObject, function () { return onError(err); }); };
|
|
1176
|
+
dom.on('error', onErrorWithContext);
|
|
1177
|
+
handler = dom.bind(handler);
|
|
1178
|
+
}
|
|
1179
|
+
return this.__store.run(storeObject, handler);
|
|
944
1180
|
};
|
|
945
1181
|
return Honeybadger;
|
|
946
1182
|
}(Client));
|
|
@@ -948,7 +1184,7 @@ var server = new Honeybadger({
|
|
|
948
1184
|
__plugins: [
|
|
949
1185
|
uncaughtException(),
|
|
950
1186
|
unhandledRejection()
|
|
951
|
-
]
|
|
1187
|
+
],
|
|
952
1188
|
});
|
|
953
1189
|
|
|
954
1190
|
module.exports = server;
|