1 | const http = require('http');
|
2 |
|
3 | // vendor
|
4 | const xtend = require('xtend');
|
5 | const raven = require('raven');
|
6 |
|
7 | // https://docs.sentry.io/clients/node/usage/
|
8 |
|
9 | // level is a numeric value for book from [0, 5]
|
10 | // panic, error, warning, info, debug, trace
|
11 | const sentry_levels = ['fatal', 'error', 'warning', 'info', 'debug', 'debug'];
|
12 |
|
13 | module.exports = function(dsn, opt) {
|
14 | opt = opt || {};
|
15 |
|
16 | const sentry = new raven.Client(dsn, opt);
|
17 |
|
18 | const on_error = opt.on_error;
|
19 |
|
20 | // we will ignore anything above this level
|
21 | const ignore_levels = opt.ignore_levels || 2;
|
22 |
|
23 | if (on_error && typeof on_error === 'function') {
|
24 | sentry.on('error', on_error);
|
25 | }
|
26 | else {
|
27 | sentry.on('error', function(err) {
|
28 | // throw the error out to the environment
|
29 | // process uncaught exception is able to handle this if the user wants to
|
30 | // sentry logging errors should not be ignored since you may not
|
31 | // otherwise know you are failing
|
32 | err._sentry_error = true;
|
33 | throw err;
|
34 | });
|
35 | }
|
36 |
|
37 | return function() {
|
38 | const self = this;
|
39 |
|
40 | // default is error
|
41 | let lvl = 'error';
|
42 |
|
43 | if (self.level < sentry_levels.length) {
|
44 | lvl = sentry_levels[self.level];
|
45 | }
|
46 |
|
47 | // ignore anything below warning
|
48 | if (self.level > ignore_levels) {
|
49 | return;
|
50 | }
|
51 |
|
52 | const extra = xtend({}, self);
|
53 | delete extra.level;
|
54 |
|
55 | // add our fields to the message
|
56 | const packet = {
|
57 | message: self.message,
|
58 | extra: extra,
|
59 | level: lvl,
|
60 | };
|
61 |
|
62 | for (let idx=0 ; idx < arguments.length ; ++idx) {
|
63 | const arg = arguments[idx];
|
64 |
|
65 | // http interface handling
|
66 | if (arg instanceof http.IncomingMessage) {
|
67 | packet.req = arg
|
68 | }
|
69 | // error will be handled below
|
70 | // only allowed as first argument
|
71 | else if (arg instanceof Error) {
|
72 | continue;
|
73 | }
|
74 | // if user passed an object, then capture extra fields
|
75 | else if (arg instanceof Object) {
|
76 | Object.keys(arg).forEach(function(key) {
|
77 | extra[key] = arg[key];
|
78 | });
|
79 | }
|
80 | }
|
81 |
|
82 | // if the first argument is an error, capture it as the error interface
|
83 | if (arguments[0] instanceof Error) {
|
84 | const err = arguments[0];
|
85 |
|
86 | // avoid trying to log a sentry error since this will just lead to
|
87 | // likely causing even more errors
|
88 | if (err._sentry_error) {
|
89 | return;
|
90 | }
|
91 |
|
92 | if (Object.keys(err).length > 0) {
|
93 | extra.error = err;
|
94 | }
|
95 |
|
96 | // captures the error and stacktrace
|
97 | return sentry.captureException(err, packet);
|
98 | }
|
99 |
|
100 | // no error objects, just send the packet
|
101 | sentry.send(packet);
|
102 | }
|
103 | }
|