rollbar 2.17.0 → 2.19.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.
Files changed (55) hide show
  1. package/README.md +1 -1
  2. package/defaults.js +0 -1
  3. package/dist/rollbar.js +3810 -3556
  4. package/dist/rollbar.js.map +1 -1
  5. package/dist/rollbar.min.js +1 -1
  6. package/dist/rollbar.min.js.map +1 -1
  7. package/dist/rollbar.named-amd.js +3807 -3553
  8. package/dist/rollbar.named-amd.js.map +1 -1
  9. package/dist/rollbar.named-amd.min.js +1 -1
  10. package/dist/rollbar.named-amd.min.js.map +1 -1
  11. package/dist/rollbar.noconflict.umd.js +3807 -3553
  12. package/dist/rollbar.noconflict.umd.js.map +1 -1
  13. package/dist/rollbar.noconflict.umd.min.js +1 -1
  14. package/dist/rollbar.noconflict.umd.min.js.map +1 -1
  15. package/dist/rollbar.snippet.js +1 -1
  16. package/dist/rollbar.umd.js +3807 -3553
  17. package/dist/rollbar.umd.js.map +1 -1
  18. package/dist/rollbar.umd.min.js +1 -1
  19. package/dist/rollbar.umd.min.js.map +1 -1
  20. package/index.d.ts +2 -0
  21. package/package.json +1 -62
  22. package/src/api.js +13 -7
  23. package/src/browser/core.js +561 -0
  24. package/src/browser/defaults/scrubFields.js +59 -0
  25. package/src/browser/globalSetup.js +1 -41
  26. package/src/browser/rollbar.js +16 -544
  27. package/src/browser/shim.js +2 -1
  28. package/src/browser/telemetry.js +33 -17
  29. package/src/browser/transforms.js +28 -5
  30. package/src/browser/transport.js +13 -10
  31. package/src/browser/wrapGlobals.js +41 -0
  32. package/src/defaults.js +9 -0
  33. package/src/predicates.js +1 -0
  34. package/src/react-native/rollbar.js +9 -3
  35. package/src/react-native/transforms.js +7 -1
  36. package/src/react-native/transport.js +16 -10
  37. package/src/rollbar.js +9 -10
  38. package/src/scrub.js +93 -0
  39. package/src/server/rollbar.js +6 -2
  40. package/src/server/sourceMap/stackTrace.js +1 -2
  41. package/src/server/transforms.js +18 -4
  42. package/src/transforms.js +0 -1
  43. package/src/truncation.js +3 -2
  44. package/src/utility/traverse.js +38 -0
  45. package/src/utility.js +25 -107
  46. package/test/api.test.js +2 -0
  47. package/test/apiUtility.test.js +2 -1
  48. package/test/browser.core.test.js +555 -0
  49. package/test/browser.rollbar.test.js +116 -13
  50. package/test/browser.transforms.test.js +22 -2
  51. package/test/browser.transport.test.js +5 -2
  52. package/test/react-native.transport.test.js +5 -1
  53. package/test/server.transforms.test.js +70 -0
  54. package/test/truncation.test.js +2 -0
  55. package/test/utility.test.js +44 -13
@@ -1,4 +1,5 @@
1
1
  var _ = require('../utility');
2
+ var scrub = require('../scrub');
2
3
  var urlparser = require('./url');
3
4
  var domUtil = require('./domUtility');
4
5
 
@@ -168,15 +169,20 @@ Instrumenter.prototype.instrumentNetwork = function() {
168
169
  replace(xhrp, 'open', function(orig) {
169
170
  return function(method, url) {
170
171
  if (_.isType(url, 'string')) {
171
- this.__rollbar_xhr = {
172
- method: method,
173
- url: url,
174
- status_code: null,
175
- start_time_ms: _.now(),
176
- end_time_ms: null
177
- };
178
- if (self.autoInstrument.networkRequestHeaders) {
179
- this.__rollbar_xhr.request_headers = {};
172
+ if (this.__rollbar_xhr) {
173
+ this.__rollbar_xhr.method = method;
174
+ this.__rollbar_xhr.url = url;
175
+ this.__rollbar_xhr.status_code = null;
176
+ this.__rollbar_xhr.start_time_ms = _.now();
177
+ this.__rollbar_xhr.end_time_ms = null;
178
+ } else {
179
+ this.__rollbar_xhr = {
180
+ method: method,
181
+ url: url,
182
+ status_code: null,
183
+ start_time_ms: _.now(),
184
+ end_time_ms: null
185
+ };
180
186
  }
181
187
  }
182
188
  return orig.apply(this, arguments);
@@ -185,12 +191,21 @@ Instrumenter.prototype.instrumentNetwork = function() {
185
191
 
186
192
  replace(xhrp, 'setRequestHeader', function(orig) {
187
193
  return function(header, value) {
188
- if (self.autoInstrument.networkRequestHeaders && this.__rollbar_xhr &&
189
- _.isType(header, 'string') && _.isType(value, 'string')) {
190
- this.__rollbar_xhr.request_headers[header] = value;
194
+ // If xhr.open is async, __rollbar_xhr may not be initialized yet.
195
+ if (!this.__rollbar_xhr) {
196
+ this.__rollbar_xhr = {};
191
197
  }
192
- if (header.toLowerCase() === 'content-type') {
193
- this.__rollbar_xhr.request_content_type = value;
198
+ if (_.isType(header, 'string') && _.isType(value, 'string')) {
199
+ if (self.autoInstrument.networkRequestHeaders) {
200
+ if (!this.__rollbar_xhr.request_headers) {
201
+ this.__rollbar_xhr.request_headers = {};
202
+ }
203
+ this.__rollbar_xhr.request_headers[header] = value;
204
+ }
205
+ // We want the content type even if request header telemetry is off.
206
+ if (header.toLowerCase() === 'content-type') {
207
+ this.__rollbar_xhr.request_content_type = value;
208
+ }
194
209
  }
195
210
  return orig.apply(this, arguments);
196
211
  };
@@ -367,8 +382,9 @@ Instrumenter.prototype.instrumentNetwork = function() {
367
382
  }
368
383
  var body = null;
369
384
  if (self.autoInstrument.networkResponseBody) {
370
- if (typeof resp.text === 'function') { // Response.text() is not implemented on multiple platforms
371
- body = resp.text(); //returns a Promise
385
+ if (typeof resp.text === 'function') { // Response.text() is not implemented on some platforms
386
+ // The response must be cloned to prevent reading (and locking) the original stream.
387
+ body = resp.clone().text(); //returns a Promise
372
388
  }
373
389
  }
374
390
  if (headers || body) {
@@ -409,7 +425,7 @@ Instrumenter.prototype.isJsonContentType = function(contentType) {
409
425
  }
410
426
 
411
427
  Instrumenter.prototype.scrubJson = function(json) {
412
- return JSON.stringify(_.scrub(JSON.parse(json), this.options.scrubFields));
428
+ return JSON.stringify(scrub(JSON.parse(json), this.options.scrubFields));
413
429
  }
414
430
 
415
431
  Instrumenter.prototype.fetchHeaders = function(inHeaders, headersConfig) {
@@ -19,6 +19,10 @@ function handleItemWithError(item, options, callback) {
19
19
  if (item.err) {
20
20
  try {
21
21
  item.stackInfo = item.err._savedStackTrace || errorParser.parse(item.err, item.skipFrames);
22
+
23
+ if (options.addErrorContext) {
24
+ addErrorContext(item);
25
+ }
22
26
  } catch (e) {
23
27
  logger.error('Error while parsing the error object.', e);
24
28
  try {
@@ -32,6 +36,20 @@ function handleItemWithError(item, options, callback) {
32
36
  callback(null, item);
33
37
  }
34
38
 
39
+ function addErrorContext(item) {
40
+ var chain = [];
41
+ var err = item.err;
42
+
43
+ chain.push(err);
44
+
45
+ while (err.nested) {
46
+ err = err.nested;
47
+ chain.push(err);
48
+ }
49
+
50
+ _.addErrorContext(item, chain);
51
+ }
52
+
35
53
  function ensureItemHasSomethingToSay(item, options, callback) {
36
54
  if (!item.message && !item.stackInfo && !item.custom) {
37
55
  callback(new Error('No message, stack info, or custom data'), null);
@@ -291,10 +309,15 @@ function errorClass(stackInfo, guess, options) {
291
309
  }
292
310
  }
293
311
 
294
- function scrubPayload(item, options, callback) {
295
- var scrubFields = options.scrubFields;
296
- item.data = _.scrub(item.data, scrubFields);
297
- callback(null, item);
312
+ function addScrubber(scrubFn) {
313
+ return function (item, options, callback) {
314
+ if (scrubFn) {
315
+ var scrubFields = options.scrubFields || [];
316
+ var scrubPaths = options.scrubPaths || [];
317
+ item.data = scrubFn(item.data, scrubFields, scrubPaths);
318
+ }
319
+ callback(null, item);
320
+ }
298
321
  }
299
322
 
300
323
  module.exports = {
@@ -306,5 +329,5 @@ module.exports = {
306
329
  addClientInfo: addClientInfo,
307
330
  addPluginInfo: addPluginInfo,
308
331
  addBody: addBody,
309
- scrubPayload: scrubPayload
332
+ addScrubber: addScrubber
310
333
  };
@@ -1,7 +1,6 @@
1
1
  /*global XDomainRequest*/
2
2
 
3
3
  var _ = require('../utility');
4
- var truncation = require('../truncation');
5
4
  var logger = require('./logger');
6
5
 
7
6
  /*
@@ -21,8 +20,11 @@ var logger = require('./logger');
21
20
  *
22
21
  * payload is an unserialized object
23
22
  */
23
+ function Transport(truncation) {
24
+ this.truncation = truncation;
25
+ }
24
26
 
25
- function get(accessToken, options, params, callback, requestFactory) {
27
+ Transport.prototype.get = function(accessToken, options, params, callback, requestFactory) {
26
28
  if (!callback || !_.isFunction(callback)) {
27
29
  callback = function() {};
28
30
  }
@@ -33,7 +35,7 @@ function get(accessToken, options, params, callback, requestFactory) {
33
35
  _makeZoneRequest(accessToken, url, method, null, callback, requestFactory);
34
36
  }
35
37
 
36
- function post(accessToken, options, payload, callback, requestFactory) {
38
+ Transport.prototype.post = function(accessToken, options, payload, callback, requestFactory) {
37
39
  if (!callback || !_.isFunction(callback)) {
38
40
  callback = function() {};
39
41
  }
@@ -42,7 +44,12 @@ function post(accessToken, options, payload, callback, requestFactory) {
42
44
  return callback(new Error('Cannot send empty request'));
43
45
  }
44
46
 
45
- var stringifyResult = truncation.truncate(payload);
47
+ var stringifyResult;
48
+ if (this.truncation) {
49
+ stringifyResult = this.truncation.truncate(payload);
50
+ } else {
51
+ stringifyResult = _.stringify(payload)
52
+ }
46
53
  if (stringifyResult.error) {
47
54
  return callback(stringifyResult.error);
48
55
  }
@@ -53,7 +60,7 @@ function post(accessToken, options, payload, callback, requestFactory) {
53
60
  _makeZoneRequest(accessToken, url, method, writeData, callback, requestFactory);
54
61
  }
55
62
 
56
- function postJsonPayload(accessToken, options, jsonPayload, callback, requestFactory) {
63
+ Transport.prototype.postJsonPayload = function (accessToken, options, jsonPayload, callback, requestFactory) {
57
64
  if (!callback || !_.isFunction(callback)) {
58
65
  callback = function() {};
59
66
  }
@@ -245,8 +252,4 @@ function _newRetriableError(message, code) {
245
252
  return err;
246
253
  }
247
254
 
248
- module.exports = {
249
- get: get,
250
- post: post,
251
- postJsonPayload: postJsonPayload
252
- };
255
+ module.exports = Transport;
@@ -0,0 +1,41 @@
1
+ function wrapGlobals(window, handler, shim) {
2
+ if (!window) { return; }
3
+ // Adapted from https://github.com/bugsnag/bugsnag-js
4
+ var globals = 'EventTarget,Window,Node,ApplicationCache,AudioTrackList,ChannelMergerNode,CryptoOperation,EventSource,FileReader,HTMLUnknownElement,IDBDatabase,IDBRequest,IDBTransaction,KeyOperation,MediaController,MessagePort,ModalWindow,Notification,SVGElementInstance,Screen,TextTrack,TextTrackCue,TextTrackList,WebSocket,WebSocketWorker,Worker,XMLHttpRequest,XMLHttpRequestEventTarget,XMLHttpRequestUpload'.split(',');
5
+ var i, global;
6
+ for (i = 0; i < globals.length; ++i) {
7
+ global = globals[i];
8
+
9
+ if (window[global] && window[global].prototype) {
10
+ _extendListenerPrototype(handler, window[global].prototype, shim);
11
+ }
12
+ }
13
+ }
14
+
15
+ function _extendListenerPrototype(handler, prototype, shim) {
16
+ if (prototype.hasOwnProperty && prototype.hasOwnProperty('addEventListener')) {
17
+ var oldAddEventListener = prototype.addEventListener;
18
+ while (oldAddEventListener._rollbarOldAdd && oldAddEventListener.belongsToShim) {
19
+ oldAddEventListener = oldAddEventListener._rollbarOldAdd;
20
+ }
21
+ var addFn = function(event, callback, bubble) {
22
+ oldAddEventListener.call(this, event, handler.wrap(callback), bubble);
23
+ };
24
+ addFn._rollbarOldAdd = oldAddEventListener;
25
+ addFn.belongsToShim = shim;
26
+ prototype.addEventListener = addFn;
27
+
28
+ var oldRemoveEventListener = prototype.removeEventListener;
29
+ while (oldRemoveEventListener._rollbarOldRemove && oldRemoveEventListener.belongsToShim) {
30
+ oldRemoveEventListener = oldRemoveEventListener._rollbarOldRemove;
31
+ }
32
+ var removeFn = function(event, callback, bubble) {
33
+ oldRemoveEventListener.call(this, event, callback && callback._rollbar_wrapped || callback, bubble);
34
+ };
35
+ removeFn._rollbarOldRemove = oldRemoveEventListener;
36
+ removeFn.belongsToShim = shim;
37
+ prototype.removeEventListener = removeFn;
38
+ }
39
+ }
40
+
41
+ module.exports = wrapGlobals;
@@ -0,0 +1,9 @@
1
+ module.exports = {
2
+ version: '2.19.2',
3
+ endpoint: 'api.rollbar.com/api/1/item/',
4
+ logLevel: 'debug',
5
+ reportLevel: 'debug',
6
+ uncaughtErrorLevel: 'error',
7
+ maxItems: 0,
8
+ itemsPerMin: 60
9
+ }
package/src/predicates.js CHANGED
@@ -15,6 +15,7 @@ function checkLevel(item, settings) {
15
15
  function userCheckIgnore(logger) {
16
16
  return function(item, settings) {
17
17
  var isUncaught = !!item._isUncaught;
18
+ delete item._isUncaught;
18
19
  var args = item._originalArgs;
19
20
  delete item._originalArgs;
20
21
  try {
@@ -4,12 +4,14 @@ var _ = require('../utility');
4
4
  var API = require('../api');
5
5
  var logger = require('./logger');
6
6
 
7
- var transport = require('./transport');
7
+ var Transport = require('./transport');
8
8
  var urllib = require('../browser/url');
9
9
 
10
+ var Telemeter = require('../telemetry');
10
11
  var transforms = require('./transforms');
11
12
  var sharedTransforms = require('../transforms');
12
13
  var sharedPredicates = require('../predicates');
14
+ var truncation = require('../truncation');
13
15
 
14
16
  function Rollbar(options, client) {
15
17
  if (_.isType(options, 'string')) {
@@ -22,10 +24,14 @@ function Rollbar(options, client) {
22
24
  // This makes no sense in a long running app
23
25
  delete this.options.maxItems;
24
26
  this.options.environment = this.options.environment || 'unspecified';
25
- var api = new API(this.options, transport, urllib);
26
- this.client = client || new Client(this.options, api, logger, 'react-native');
27
+
28
+ var transport = new Transport(truncation);
29
+ var api = new API(this.options, transport, urllib, truncation);
30
+ var telemeter = new Telemeter(this.options)
31
+ this.client = client || new Client(this.options, api, logger, telemeter, 'react-native');
27
32
  addTransformsToNotifier(this.client.notifier);
28
33
  addPredicatesToQueue(this.client.queue);
34
+ _.setupJSON();
29
35
  }
30
36
 
31
37
  var _instance = null;
@@ -1,4 +1,5 @@
1
1
  var _ = require('../utility');
2
+ var scrub = require('../scrub');
2
3
  var errorParser = require('../errorParser');
3
4
 
4
5
  function baseData(item, options, callback) {
@@ -64,6 +65,10 @@ function handleItemWithError(item, options, callback) {
64
65
  return callback(null, item);
65
66
  }
66
67
 
68
+ if (options.addErrorContext) {
69
+ _.addErrorContext(item, [item.err]);
70
+ }
71
+
67
72
  var err = item.err;
68
73
  var parsedError = errorParser.parse(err);
69
74
  var guess = errorParser.guessErrorClass(parsedError.message);
@@ -85,8 +90,9 @@ function handleItemWithError(item, options, callback) {
85
90
  function scrubPayload(item, options, callback) {
86
91
  var scrubHeaders = options.scrubHeaders || [];
87
92
  var scrubFields = options.scrubFields || [];
93
+ var scrubPaths = options.scrubPaths || [];
88
94
  scrubFields = scrubHeaders.concat(scrubFields);
89
- item.data = _.scrub(item.data, scrubFields);
95
+ item.data = scrub(item.data, scrubFields, scrubPaths);
90
96
  callback(null, item);
91
97
  }
92
98
 
@@ -1,10 +1,14 @@
1
1
  var _ = require('../utility');
2
- var truncation = require('../truncation');
3
2
  var logger = require('./logger');
4
3
 
5
4
  var Buffer = require('buffer/').Buffer;
6
5
 
7
- function get(accessToken, options, params, callback) {
6
+ function Transport(truncation) {
7
+ this.rateLimitExpires = 0;
8
+ this.truncation = truncation;
9
+ }
10
+
11
+ Transport.prototype.get = function(accessToken, options, params, callback) {
8
12
  if (!callback || !_.isFunction(callback)) {
9
13
  callback = function() {};
10
14
  }
@@ -23,7 +27,7 @@ function get(accessToken, options, params, callback) {
23
27
  });
24
28
  }
25
29
 
26
- function post(accessToken, options, payload, callback) {
30
+ Transport.prototype.post = function(accessToken, options, payload, callback) {
27
31
  if (!callback || !_.isFunction(callback)) {
28
32
  callback = function() {};
29
33
  }
@@ -31,7 +35,13 @@ function post(accessToken, options, payload, callback) {
31
35
  if (!payload) {
32
36
  return callback(new Error('Cannot send empty request'));
33
37
  }
34
- var stringifyResult = truncation.truncate(payload);
38
+
39
+ var stringifyResult;
40
+ if (this.truncation) {
41
+ stringifyResult = this.truncation.truncate(payload);
42
+ } else {
43
+ stringifyResult = _.stringify(payload)
44
+ }
35
45
  if (stringifyResult.error) {
36
46
  logger.error('Problem stringifying payload. Giving up');
37
47
  return callback(stringifyResult.error);
@@ -42,7 +52,7 @@ function post(accessToken, options, payload, callback) {
42
52
  _makeRequest(headers, options, writeData, callback);
43
53
  }
44
54
 
45
- function postJsonPayload(accessToken, options, jsonPayload, callback) {
55
+ Transport.prototype.postJsonPayload = function(accessToken, options, jsonPayload, callback) {
46
56
  if (!callback || !_.isFunction(callback)) {
47
57
  callback = function() {};
48
58
  }
@@ -114,8 +124,4 @@ function _wrapPostCallback(callback) {
114
124
  }
115
125
  }
116
126
 
117
- module.exports = {
118
- get: get,
119
- post: post,
120
- postJsonPayload: postJsonPayload
121
- };
127
+ module.exports = Transport;
package/src/rollbar.js CHANGED
@@ -1,7 +1,6 @@
1
1
  var RateLimiter = require('./rateLimiter');
2
2
  var Queue = require('./queue');
3
3
  var Notifier = require('./notifier');
4
- var Telemeter = require('./telemetry');
5
4
  var _ = require('./utility');
6
5
 
7
6
  /*
@@ -11,7 +10,7 @@ var _ = require('./utility');
11
10
  * @param api
12
11
  * @param logger
13
12
  */
14
- function Rollbar(options, api, logger, platform) {
13
+ function Rollbar(options, api, logger, telemeter, platform) {
15
14
  this.options = _.merge(options);
16
15
  this.logger = logger;
17
16
  Rollbar.rateLimiter.configureGlobal(this.options);
@@ -31,7 +30,7 @@ function Rollbar(options, api, logger, platform) {
31
30
  }
32
31
 
33
32
  this.notifier = new Notifier(this.queue, this.options);
34
- this.telemeter = new Telemeter(this.options);
33
+ this.telemeter = telemeter;
35
34
  setStackTraceLimit(options);
36
35
  this.lastError = null;
37
36
  this.lastErrorHash = 'none';
@@ -115,15 +114,15 @@ Rollbar.prototype.wait = function (callback) {
115
114
  };
116
115
 
117
116
  Rollbar.prototype.captureEvent = function (type, metadata, level) {
118
- return this.telemeter.captureEvent(type, metadata, level);
117
+ return this.telemeter && this.telemeter.captureEvent(type, metadata, level);
119
118
  };
120
119
 
121
120
  Rollbar.prototype.captureDomContentLoaded = function (ts) {
122
- return this.telemeter.captureDomContentLoaded(ts);
121
+ return this.telemeter && this.telemeter.captureDomContentLoaded(ts);
123
122
  };
124
123
 
125
124
  Rollbar.prototype.captureLoad = function (ts) {
126
- return this.telemeter.captureLoad(ts);
125
+ return this.telemeter && this.telemeter.captureLoad(ts);
127
126
  };
128
127
 
129
128
  Rollbar.prototype.buildJsonPayload = function (item) {
@@ -153,8 +152,8 @@ Rollbar.prototype._log = function (defaultLevel, item) {
153
152
  try {
154
153
  this._addTracingInfo(item);
155
154
  item.level = item.level || defaultLevel;
156
- this.telemeter._captureRollbarItem(item);
157
- item.telemetryEvents = this.telemeter.copyEvents();
155
+ this.telemeter && this.telemeter._captureRollbarItem(item);
156
+ item.telemetryEvents = (this.telemeter && this.telemeter.copyEvents()) || [];
158
157
  this.notifier.log(item, callback);
159
158
  } catch (e) {
160
159
  this.logger.error(e);
@@ -235,7 +234,7 @@ function validateTracer(tracer) {
235
234
  return false;
236
235
  }
237
236
 
238
- const scope = tracer.scope();
237
+ var scope = tracer.scope();
239
238
 
240
239
  if (!scope || !scope.active || typeof scope.active !== 'function') {
241
240
  return false;
@@ -253,7 +252,7 @@ function validateSpan(span) {
253
252
  return false;
254
253
  }
255
254
 
256
- const spanContext = span.context();
255
+ var spanContext = span.context();
257
256
 
258
257
  if (!spanContext
259
258
  || !spanContext.toSpanId
package/src/scrub.js ADDED
@@ -0,0 +1,93 @@
1
+ var _ = require('./utility');
2
+ var traverse = require('./utility/traverse');
3
+
4
+ function scrub(data, scrubFields, scrubPaths) {
5
+ scrubFields = scrubFields || [];
6
+
7
+ if (scrubPaths) {
8
+ for (var i = 0; i < scrubPaths.length; ++i) {
9
+ scrubPath(data, scrubPaths[i]);
10
+ }
11
+ }
12
+
13
+ var paramRes = _getScrubFieldRegexs(scrubFields);
14
+ var queryRes = _getScrubQueryParamRegexs(scrubFields);
15
+
16
+ function redactQueryParam(dummy0, paramPart) {
17
+ return paramPart + _.redact();
18
+ }
19
+
20
+ function paramScrubber(v) {
21
+ var i;
22
+ if (_.isType(v, 'string')) {
23
+ for (i = 0; i < queryRes.length; ++i) {
24
+ v = v.replace(queryRes[i], redactQueryParam);
25
+ }
26
+ }
27
+ return v;
28
+ }
29
+
30
+ function valScrubber(k, v) {
31
+ var i;
32
+ for (i = 0; i < paramRes.length; ++i) {
33
+ if (paramRes[i].test(k)) {
34
+ v = _.redact();
35
+ break;
36
+ }
37
+ }
38
+ return v;
39
+ }
40
+
41
+ function scrubber(k, v, seen) {
42
+ var tmpV = valScrubber(k, v);
43
+ if (tmpV === v) {
44
+ if (_.isType(v, 'object') || _.isType(v, 'array')) {
45
+ return traverse(v, scrubber, seen);
46
+ }
47
+ return paramScrubber(tmpV);
48
+ } else {
49
+ return tmpV;
50
+ }
51
+ }
52
+
53
+ return traverse(data, scrubber, []);
54
+ }
55
+
56
+ function scrubPath(obj, path) {
57
+ var keys = path.split('.');
58
+ var last = keys.length - 1;
59
+ try {
60
+ for (var i = 0; i <= last; ++i) {
61
+ if (i < last) {
62
+ obj = obj[keys[i]];
63
+ } else {
64
+ obj[keys[i]] = _.redact();
65
+ }
66
+ }
67
+ } catch (e) {
68
+ // Missing key is OK;
69
+ }
70
+ }
71
+
72
+ function _getScrubFieldRegexs(scrubFields) {
73
+ var ret = [];
74
+ var pat;
75
+ for (var i = 0; i < scrubFields.length; ++i) {
76
+ pat = '^\\[?(%5[bB])?' + scrubFields[i] + '\\[?(%5[bB])?\\]?(%5[dD])?$';
77
+ ret.push(new RegExp(pat, 'i'));
78
+ }
79
+ return ret;
80
+ }
81
+
82
+
83
+ function _getScrubQueryParamRegexs(scrubFields) {
84
+ var ret = [];
85
+ var pat;
86
+ for (var i = 0; i < scrubFields.length; ++i) {
87
+ pat = '\\[?(%5[bB])?' + scrubFields[i] + '\\[?(%5[bB])?\\]?(%5[dD])?';
88
+ ret.push(new RegExp('(' + pat + '=)([^&\\n]+)', 'igm'));
89
+ }
90
+ return ret;
91
+ }
92
+
93
+ module.exports = scrub;
@@ -11,9 +11,11 @@ var Transport = require('./transport');
11
11
  var urllib = require('url');
12
12
  var jsonBackup = require('json-stringify-safe');
13
13
 
14
+ var Telemeter = require('../telemetry');
14
15
  var transforms = require('./transforms');
15
16
  var sharedTransforms = require('../transforms');
16
17
  var sharedPredicates = require('../predicates');
18
+ var truncation = require('../truncation');
17
19
 
18
20
  function Rollbar(options, client) {
19
21
  if (_.isType(options, 'string')) {
@@ -34,11 +36,13 @@ function Rollbar(options, client) {
34
36
  this.lambdaContext = null;
35
37
  this.lambdaTimeoutHandle = null;
36
38
  var transport = new Transport();
37
- var api = new API(this.options, transport, urllib, jsonBackup);
38
- this.client = client || new Client(this.options, api, logger, 'server');
39
+ var api = new API(this.options, transport, urllib, truncation, jsonBackup);
40
+ var telemeter = new Telemeter(this.options)
41
+ this.client = client || new Client(this.options, api, logger, telemeter, 'server');
39
42
  addTransformsToNotifier(this.client.notifier);
40
43
  addPredicatesToQueue(this.client.queue);
41
44
  this.setupUnhandledCapture();
45
+ _.setupJSON();
42
46
  }
43
47
 
44
48
  var _instance = null;
@@ -1,7 +1,6 @@
1
1
  var SourceMapConsumer = require('source-map').SourceMapConsumer;
2
2
  var path = require('path');
3
3
  var fs = require('fs');
4
- var bufferFrom = require('buffer-from');
5
4
 
6
5
  /**
7
6
  * Uses Node source-map to map transpiled JS stack locations to original
@@ -94,7 +93,7 @@ function retrieveSourceMap(source) {
94
93
  if (reSourceMap.test(sourceMappingURL)) {
95
94
  // Support source map URL as a data url
96
95
  var rawData = sourceMappingURL.slice(sourceMappingURL.indexOf(',') + 1);
97
- sourceMapData = bufferFrom(rawData, 'base64').toString();
96
+ sourceMapData = Buffer.from(rawData, 'base64').toString();
98
97
  sourceMappingURL = source;
99
98
  } else {
100
99
  // Support source map URLs relative to the source URL
@@ -3,6 +3,7 @@ var parser = require('./parser');
3
3
  var requestIp = require('request-ip');
4
4
  var url = require('url');
5
5
  var _ = require('../utility');
6
+ var scrub = require('../scrub');
6
7
 
7
8
  function baseData(item, options, callback) {
8
9
  var environment = (options.payload && options.payload.environment) || options.environment;
@@ -88,6 +89,10 @@ function handleItemWithError(item, options, callback) {
88
89
  } while (err !== undefined);
89
90
  item.stackInfo = chain;
90
91
 
92
+ if (options.addErrorContext) {
93
+ _.addErrorContext(item, errors);
94
+ }
95
+
91
96
  var cb = function(e) {
92
97
  if (e) {
93
98
  item.message = item.err.message || item.err.description || item.message || String(item.err);
@@ -108,6 +113,8 @@ function addRequestData(item, options, callback) {
108
113
  return;
109
114
  }
110
115
 
116
+ var baseUrl = req.baseUrl || '';
117
+
111
118
  if (options.addRequestData && _.isFunction(options.addRequestData)) {
112
119
  options.addRequestData(item.data, req);
113
120
  callback(null, item);
@@ -118,11 +125,15 @@ function addRequestData(item, options, callback) {
118
125
  _.filterIp(requestData, options.captureIp);
119
126
  item.data.request = requestData;
120
127
 
128
+ var routePath;
129
+
121
130
  if (req.route) {
122
- item.data.context = req.route.path;
131
+ routePath = req.route.path;
132
+ item.data.context = baseUrl && baseUrl.length ? baseUrl + routePath : routePath;
123
133
  } else {
124
134
  try {
125
- item.data.context = req.app._router.matchRequest(req).path;
135
+ routePath = req.app._router.matchRequest(req).path;
136
+ item.data.context = baseUrl && baseUrl.length ? baseUrl + routePath : routePath;
126
137
  } catch (ignore) {
127
138
  // Ignored
128
139
  }
@@ -184,10 +195,11 @@ function addLambdaData(item, options, callback) {
184
195
  function scrubPayload(item, options, callback) {
185
196
  var scrubHeaders = options.scrubHeaders || [];
186
197
  var scrubFields = options.scrubFields || [];
198
+ var scrubPaths = options.scrubPaths || [];
187
199
  scrubFields = scrubHeaders.concat(scrubFields);
188
200
 
189
201
  parseRequestBody(item.data.request, options);
190
- item.data = _.scrub(item.data, scrubFields);
202
+ item.data = scrub(item.data, scrubFields, scrubPaths);
191
203
  serializeRequestBody(item.data.request, options);
192
204
 
193
205
  callback(null, item);
@@ -258,8 +270,10 @@ function _buildRequestData(req) {
258
270
  var host = headers.host || '<no host>';
259
271
  var proto = req.protocol || ((req.socket && req.socket.encrypted) ? 'https' : 'http' );
260
272
  var parsedUrl;
273
+ var baseUrl = req.baseUrl || '';
261
274
  if (_.isType(req.url, 'string')) {
262
- parsedUrl = url.parse(req.url, true);
275
+ var fullUrl = baseUrl && baseUrl.length ? baseUrl + req.url : req.url
276
+ parsedUrl = url.parse(fullUrl, true);
263
277
  } else {
264
278
  parsedUrl = req.url || {};
265
279
  }
package/src/transforms.js CHANGED
@@ -103,7 +103,6 @@ function addDiagnosticKeys(item, options, callback) {
103
103
 
104
104
  if (item._isUncaught) {
105
105
  diagnostic.is_uncaught = item._isUncaught;
106
- delete item._isUncaught;
107
106
  }
108
107
 
109
108
  if (item.err) {