From 5bac4197b77f79fda7dce70270e1b5e01792856c Mon Sep 17 00:00:00 2001 From: Matt Robenolt Date: Tue, 3 Nov 2015 11:44:59 -0800 Subject: [PATCH 1/3] Handle a native angular minErr by deconstructing it Fixes GH-243 See: https://github.com/angular/angular.js/blob/v1.4.7/src/minErr.js --- src/raven.js | 17 +++++++++++++++-- test/raven.test.js | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/raven.js b/src/raven.js index 77964b91b732..ff55d33eb95e 100644 --- a/src/raven.js +++ b/src/raven.js @@ -481,7 +481,8 @@ function triggerEvent(eventType, options) { } var dsnKeys = 'source protocol user pass host port path'.split(' '), - dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/; + dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/, + angularPattern = /^\[((?:[$a-zA-Z0-9]+:)?(?:[$a-zA-Z0-9]+))\] (.+?)\n(\S+)$/; function RavenConfigError(message) { this.name = 'RavenConfigError'; @@ -568,7 +569,19 @@ function each(obj, callback) { } function handleStackInfo(stackInfo, options) { - var frames = []; + var frames = [], + matches = angularPattern.exec(stackInfo.message); + + if (matches) { + stackInfo.name = matches[1]; + stackInfo.message = matches[2]; + // auto set a new tag specifically for the angular error url + options = options || {}; + options.extra = objectMerge({ + // Truncate this message pretty short since it can be insane. + ref: truncate(matches[3], 250) + }, options.extra); + } if (stackInfo.stack && stackInfo.stack.length) { each(stackInfo.stack, function(i, stack) { diff --git a/test/raven.test.js b/test/raven.test.js index 5cc46898f7cf..4fbef35c9555 100644 --- a/test/raven.test.js +++ b/test/raven.test.js @@ -1553,6 +1553,28 @@ describe('globals', function() { 'new ', 'hey', 'http://example.com', 10, [], undefined ]); }); + + it('should extract angularjs specific error messages', function() { + this.sinon.stub(window, 'normalizeFrame').returns(undefined); + this.sinon.stub(window, 'processException'); + + var stackInfo = { + name: 'Error', + message: '[$foo:bar] thing happened\nhttp://errors.angularjs.org/cool/story', + url: 'http://example.com', + lineno: 10 + }; + + handleStackInfo(stackInfo); + assert.deepEqual(window.processException.lastCall.args, [ + '$foo:bar', + 'thing happened', + 'http://example.com', + 10, + [], + {extra: {ref: 'http://errors.angularjs.org/cool/story'}} + ]); + }); }); describe('joinRegExp', function() { From 1006ff3a938a55e4156de6d7d0290962c400f350 Mon Sep 17 00:00:00 2001 From: Matt Robenolt Date: Wed, 4 Nov 2015 11:15:48 -0800 Subject: [PATCH 2/3] Move into angular plugin --- plugins/angular.js | 23 ++++++++++++++++++++++- src/raven.js | 17 ++--------------- test/raven.test.js | 22 ---------------------- 3 files changed, 24 insertions(+), 38 deletions(-) diff --git a/plugins/angular.js b/plugins/angular.js index 9ecf2e291906..df24fbdfe800 100644 --- a/plugins/angular.js +++ b/plugins/angular.js @@ -24,7 +24,7 @@ function ExceptionHandlerProvider($provide) { } function exceptionHandler(Raven, $delegate) { - return function (ex, cause) { + return function (ex, cause) { Raven.captureException(ex, { extra: { cause: cause } }); @@ -32,10 +32,31 @@ function exceptionHandler(Raven, $delegate) { }; } +// See https://github.com/angular/angular.js/blob/v1.4.7/src/minErr.js +var angularPattern = /^\[((?:[$a-zA-Z0-9]+:)?(?:[$a-zA-Z0-9]+))\] (.+?)\n(\S+)$/; + Raven.addPlugin(function () { angular.module('ngRaven', []) .provider('Raven', RavenProvider) .config(['$provide', ExceptionHandlerProvider]); }); +Raven.setDataCallback(function(data) { + // We only care about mutating an exception + var exception = data.exception; + if (exception) { + exception = exception.values[0]; + var matches = angularPattern.exec(exception.value); + + if (matches) { + // This type now becomes something like: $rootScope:inprog + exception.type = matches[1]; + exception.value = matches[2]; + data.message = exception.type + ': ' + exception.value; + // auto set a new tag specifically for the angular error url + data.extra.angularDocs = matches[3]; + } + } +}); + }(typeof window !== 'undefined' ? window : this)); diff --git a/src/raven.js b/src/raven.js index ff55d33eb95e..77964b91b732 100644 --- a/src/raven.js +++ b/src/raven.js @@ -481,8 +481,7 @@ function triggerEvent(eventType, options) { } var dsnKeys = 'source protocol user pass host port path'.split(' '), - dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/, - angularPattern = /^\[((?:[$a-zA-Z0-9]+:)?(?:[$a-zA-Z0-9]+))\] (.+?)\n(\S+)$/; + dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/; function RavenConfigError(message) { this.name = 'RavenConfigError'; @@ -569,19 +568,7 @@ function each(obj, callback) { } function handleStackInfo(stackInfo, options) { - var frames = [], - matches = angularPattern.exec(stackInfo.message); - - if (matches) { - stackInfo.name = matches[1]; - stackInfo.message = matches[2]; - // auto set a new tag specifically for the angular error url - options = options || {}; - options.extra = objectMerge({ - // Truncate this message pretty short since it can be insane. - ref: truncate(matches[3], 250) - }, options.extra); - } + var frames = []; if (stackInfo.stack && stackInfo.stack.length) { each(stackInfo.stack, function(i, stack) { diff --git a/test/raven.test.js b/test/raven.test.js index 4fbef35c9555..5cc46898f7cf 100644 --- a/test/raven.test.js +++ b/test/raven.test.js @@ -1553,28 +1553,6 @@ describe('globals', function() { 'new ', 'hey', 'http://example.com', 10, [], undefined ]); }); - - it('should extract angularjs specific error messages', function() { - this.sinon.stub(window, 'normalizeFrame').returns(undefined); - this.sinon.stub(window, 'processException'); - - var stackInfo = { - name: 'Error', - message: '[$foo:bar] thing happened\nhttp://errors.angularjs.org/cool/story', - url: 'http://example.com', - lineno: 10 - }; - - handleStackInfo(stackInfo); - assert.deepEqual(window.processException.lastCall.args, [ - '$foo:bar', - 'thing happened', - 'http://example.com', - 10, - [], - {extra: {ref: 'http://errors.angularjs.org/cool/story'}} - ]); - }); }); describe('joinRegExp', function() { From fda2aa09d3ea63430ffdec1f6ebb3e0b23d26841 Mon Sep 17 00:00:00 2001 From: Matt Robenolt Date: Fri, 6 Nov 2015 14:10:30 -0800 Subject: [PATCH 3/3] Make sure we truncate angularDocs url so it's not crazy --- plugins/angular.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/angular.js b/plugins/angular.js index df24fbdfe800..dd929f5cddeb 100644 --- a/plugins/angular.js +++ b/plugins/angular.js @@ -54,7 +54,7 @@ Raven.setDataCallback(function(data) { exception.value = matches[2]; data.message = exception.type + ': ' + exception.value; // auto set a new tag specifically for the angular error url - data.extra.angularDocs = matches[3]; + data.extra.angularDocs = matches[3].substr(0, 250); } } });