├── .gitignore ├── .jshintrc ├── .travis.yml ├── Gruntfile.js ├── LICENSE ├── README.md ├── angular-raven.js ├── angular-raven.min.js ├── bower.json ├── examples └── index.html ├── package.json └── test └── angular-raven_test.js /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components/ 2 | node_modules/ 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": true, 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "unused": false, 11 | "boss": true, 12 | "eqnull": true, 13 | "node": true, 14 | "globals": { 15 | "window": false, 16 | "Raven": false, 17 | "document": false, 18 | "angular": false, 19 | "$": false, 20 | "_": false, 21 | "alert": false, 22 | "app": false 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '0.8' 5 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt) { 4 | 5 | require('load-grunt-tasks')(grunt); 6 | require('time-grunt')(grunt); 7 | 8 | // Project configuration. 9 | grunt.initConfig({ 10 | nodeunit: { 11 | files: ['test/**/*_test.js'], 12 | }, 13 | jshint: { 14 | options: { 15 | jshintrc: '.jshintrc', 16 | }, 17 | gruntfile: { 18 | src: 'Gruntfile.js', 19 | }, 20 | lib: { 21 | src: ['angular-raven.js'], 22 | }, 23 | test: { 24 | src: ['test/**/*.js'], 25 | }, 26 | }, 27 | watch: { 28 | gruntfile: { 29 | files: '<%= jshint.gruntfile.src %>', 30 | tasks: ['jshint:gruntfile'], 31 | }, 32 | lib: { 33 | files: '<%= jshint.lib.src %>', 34 | tasks: ['jshint:lib', 'nodeunit'], 35 | }, 36 | test: { 37 | files: '<%= jshint.test.src %>', 38 | tasks: ['jshint:test', 'nodeunit'], 39 | }, 40 | }, 41 | uglify: { 42 | options: { 43 | compress: true, 44 | mangle: true, 45 | }, 46 | dist: { 47 | files: { 48 | 'angular-raven.min.js': ['angular-raven.js'], 49 | }, 50 | }, 51 | }, 52 | bump: { 53 | options: { 54 | files: ['package.json', 'bower.json'], 55 | updateConfigs: [], 56 | commit: true, 57 | commitMessage: 'Release v%VERSION%', 58 | commitFiles: ['package.json', 'bower.json'], 59 | createTag: true, 60 | tagName: 'v%VERSION%', 61 | tagMessage: 'Version %VERSION%', 62 | push: false, 63 | pushTo: 'origin', 64 | gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d', 65 | globalReplace: false, 66 | prereleaseName: false, 67 | regExp: false, 68 | }, 69 | }, 70 | }); 71 | 72 | // Default task. 73 | grunt.registerTask('default', [ 74 | 'jshint', 75 | 'nodeunit', 76 | 'uglify', 77 | ]); 78 | 79 | }; 80 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 Patrick Stapleton, gdi2290, PatrickJS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-raven [![Build Status](https://travis-ci.org/gdi2290/angular-raven.png?branch=master)](https://travis-ci.org/gdi2290/angular-raven) 2 | A Raven.js / Sentry wrapper for Angular.js 3 | 4 | #How do I add this to my project? 5 | 6 | You can download angular-raven by: 7 | 8 | * (prefered) Using bower and running `bower install angular-raven --save` 9 | * Using npm and running `npm install angular-raven --save` 10 | * Downloading it manually by clicking [here to download development unminified version](https://raw.github.com/gdi2290/angular-raven/master/angular-raven.js) 11 | 12 | 13 | ````html 14 | 15 | Log Error 16 | 17 | 18 | 19 | 29 | 30 | 31 | 48 | 49 | ```` 50 | 51 | Initializing Raven.js outside of Angular allows Raven to track errors when Angular wasn't able to bootstrap correctly. 52 | 53 | 54 | The community has compiled a list of common ignore rules for common things, like Facebook, Chrome extensions, etc. 55 | ```javascript 56 | Raven.config('YOUR_PUBLIC_DSN', { 57 | logger: 'javascript', 58 | ignoreErrors: [ 59 | // Random plugins/extensions 60 | 'top.GLOBALS', 61 | // See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error. html 62 | 'originalCreateNotification', 63 | 'canvas.contentDocument', 64 | 'MyApp_RemoveAllHighlights', 65 | 'http://tt.epicplay.com', 66 | 'Can\'t find variable: ZiteReader', 67 | 'jigsaw is not defined', 68 | 'ComboSearch is not defined', 69 | 'http://loading.retry.widdit.com/', 70 | 'atomicFindClose', 71 | // Facebook borked 72 | 'fb_xd_fragment', 73 | // ISP "optimizing" proxy - `Cache-Control: no-transform` seems to reduce this. (thanks @acdha) 74 | // See http://stackoverflow.com/questions/4113268/how-to-stop-javascript-injection-from-vodafone-proxy 75 | 'bmi_SafeAddOnload', 76 | 'EBCallBackMessageReceived', 77 | // See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx 78 | 'conduitPage' 79 | ], 80 | ignoreUrls: [ 81 | // Facebook flakiness 82 | /graph\.facebook\.com/i, 83 | // Facebook blocked 84 | /connect\.facebook\.net\/en_US\/all\.js/i, 85 | // Woopra flakiness 86 | /eatdifferent\.com\.woopra-ns\.com/i, 87 | /static\.woopra\.com\/js\/woopra\.js/i, 88 | // Chrome extensions 89 | /extensions\//i, 90 | /^chrome:\/\//i, 91 | // Other plugins 92 | /127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb 93 | /webappstoolbarba\.texthelp\.com\//i, 94 | /metrics\.itunes\.apple\.com\.edgesuite\.net\//i 95 | ] 96 | }).install(); 97 | -------------------------------------------------------------------------------- /angular-raven.js: -------------------------------------------------------------------------------- 1 | (function(global, angular, undefined) { 2 | 'use strict'; 3 | 4 | var _development = null; 5 | 6 | function $RavenProvider() { 7 | 8 | this.development = function(config) { 9 | _development = config || _development; 10 | return this; 11 | }; 12 | 13 | this.$get = ['$window', '$log', function($window, $log) { 14 | var service = { 15 | VERSION: ($window.Raven) ? $window.Raven.VERSION : 'development', 16 | TraceKit: ($window.Raven) ? $window.Raven.TraceKit : 'development', 17 | captureException: function captureException(exception, cause) { 18 | if (!_development) { 19 | $window.Raven.captureException(exception, cause); 20 | } else { 21 | $log.error('Raven: Exception ', exception, cause); 22 | } 23 | }, 24 | captureMessage: function captureMessage(message, data) { 25 | if (!_development) { 26 | $window.Raven.captureMessage(message, data); 27 | } else { 28 | $log.error('Raven: Message ', message, data); 29 | } 30 | }, 31 | setUser: function setUser(user) { 32 | if (_development) { 33 | $log.info('Raven: User ', user); 34 | } else { 35 | if ($window.Raven.setUser) { 36 | $window.Raven.setUser(user); 37 | } else if ($window.Raven.setUserContext) { 38 | $window.Raven.setUserContext(user); 39 | } 40 | } 41 | }, 42 | setUserContext: function setUserContext(user) { 43 | if (_development) { 44 | $log.info('Raven: User ', user); 45 | } else { 46 | if ($window.Raven.setUserContext) { 47 | $window.Raven.setUserContext(user); 48 | } else if ($window.Raven.setUser) { 49 | $window.Raven.setUser(user); 50 | } 51 | } 52 | }, 53 | lastException: function lastException() { 54 | if (_development) { 55 | $log.error('Raven: Last Exception'); 56 | } else { 57 | $window.Raven.lastException(); 58 | } 59 | }, 60 | setExtraContext: function setExtraContext(data) { 61 | if (_development) { 62 | $log.info('Raven: Extra Context ', data); 63 | } else { 64 | $window.Raven.setExtraContext(data); 65 | } 66 | }, 67 | setRelease: function setRelease(data) { 68 | if (_development) { 69 | $log.info('Raven: Release Context ', data); 70 | } else { 71 | $window.Raven.setRelease(data); 72 | } 73 | }, 74 | isSetup: function isSetup() { 75 | return $window.Raven.isSetup(); 76 | }, 77 | setDataCallback: function setDataCallback(callback) { 78 | return $window.Raven.setDataCallback(callback); 79 | }, 80 | setShouldSendCallback: function setShouldSendCallback(callback) { 81 | return $window.Raven.setShouldSendCallback(callback); 82 | }, 83 | setTagsContext: function setTagsContext(data) { 84 | if (_development) { 85 | $log.info('Raven: Tags Context ', data); 86 | } else { 87 | $window.Raven.setTagsContext(data); 88 | } 89 | }, 90 | context: function context(options, func, args) { 91 | var RavenService = this; 92 | 93 | if (angular.isFunction(options)) { 94 | args = func || []; 95 | func = options; 96 | options = undefined; 97 | } 98 | 99 | return RavenService.wrap(options, func).apply(RavenService, args); 100 | }, 101 | wrap: function wrap(options, func) { 102 | var RavenService = this; 103 | 104 | if (angular.isUndefined(func) && !angular.isFunction(options)) { 105 | return options; 106 | } 107 | 108 | if (angular.isFunction(options)) { 109 | func = options; 110 | options = undefined; 111 | } 112 | 113 | if (!angular.isFunction(func)) { 114 | return func; 115 | } 116 | 117 | if (func.__raven__) { 118 | return func; 119 | } 120 | 121 | function Wrapped() { 122 | var args = [], i = arguments.length; 123 | while (i--) { 124 | args[i] = RavenService.wrap(options, arguments[i]); 125 | } 126 | try { 127 | return func.apply(this, args); 128 | } catch (e) { 129 | RavenService.captureException(e, options); 130 | } 131 | } 132 | 133 | for (var property in func) { 134 | if (func.hasOwnProperty(property)) { 135 | Wrapped[property] = func[property]; 136 | } 137 | } 138 | Wrapped.__raven__ = true; 139 | return Wrapped; 140 | } 141 | 142 | }; 143 | 144 | return service; 145 | }]; // end $get 146 | } // end provider 147 | 148 | function $ExceptionHandlerProvider($provide) { 149 | $provide.decorator('$exceptionHandler', [ 150 | '$delegate', '$raven', '$injector', 151 | $ExceptionHandlerDecorator 152 | ]); 153 | } 154 | 155 | function $ExceptionHandlerDecorator($delegate, $raven, $injector) { 156 | // If we try to include a $location object, we will get: 157 | // "Circular dependency found: $location <- $exceptionHandler <- $rootScope" 158 | // Therefore, we inject it. 159 | var $location; 160 | 161 | function $ExceptionHandler(exception, cause) { 162 | $location = $location || $injector.get('$location'); 163 | 164 | var exceptionData = { 165 | culprit: $location.absUrl(), 166 | extra: { 167 | exception: exception, 168 | cause: cause 169 | } 170 | }; 171 | 172 | if (exception instanceof Error) { 173 | $raven.captureException(exception, exceptionData); 174 | } else { 175 | var message = ''; 176 | if (angular.isString(exception.message)) { 177 | message = exception.message; 178 | } else { 179 | message = angular.isString(exception) ? exception : exception.statusText || ''; 180 | } 181 | $raven.captureMessage(message, exceptionData); 182 | } 183 | 184 | $delegate(exception, cause); 185 | } 186 | 187 | return $ExceptionHandler; 188 | } 189 | 190 | angular.module('ngRaven', []) 191 | .provider('$raven', $RavenProvider) 192 | .provider('Raven', $RavenProvider) 193 | .config(['$provide', $ExceptionHandlerProvider]); 194 | 195 | angular.module('angular-raven', ['ngRaven']); 196 | 197 | }(this, angular)); 198 | -------------------------------------------------------------------------------- /angular-raven.min.js: -------------------------------------------------------------------------------- 1 | !function(a,b,c){"use strict";function d(){this.development=function(a){return g=a||g,this},this.$get=["$window","$log",function(a,d){var e={VERSION:a.Raven?a.Raven.VERSION:"development",TraceKit:a.Raven?a.Raven.TraceKit:"development",captureException:function(b,c){g?d.error("Raven: Exception ",b,c):a.Raven.captureException(b,c)},captureMessage:function(b,c){g?d.error("Raven: Message ",b,c):a.Raven.captureMessage(b,c)},setUser:function(b){g?d.info("Raven: User ",b):a.Raven.setUser?a.Raven.setUser(b):a.Raven.setUserContext&&a.Raven.setUserContext(b)},setUserContext:function(b){g?d.info("Raven: User ",b):a.Raven.setUserContext?a.Raven.setUserContext(b):a.Raven.setUser&&a.Raven.setUser(b)},lastException:function(){g?d.error("Raven: Last Exception"):a.Raven.lastException()},setExtraContext:function(b){g?d.info("Raven: Extra Context ",b):a.Raven.setExtraContext(b)},setRelease:function(b){g?d.info("Raven: Release Context ",b):a.Raven.setRelease(b)},isSetup:function(){return a.Raven.isSetup()},setDataCallback:function(b){return a.Raven.setDataCallback(b)},setShouldSendCallback:function(b){return a.Raven.setShouldSendCallback(b)},setTagsContext:function(b){g?d.info("Raven: Tags Context ",b):a.Raven.setTagsContext(b)},context:function(a,d,e){var f=this;return b.isFunction(a)&&(e=d||[],d=a,a=c),f.wrap(a,d).apply(f,e)},wrap:function(a,d){function e(){for(var b=[],c=arguments.length;c--;)b[c]=f.wrap(a,arguments[c]);try{return d.apply(this,b)}catch(e){f.captureException(e,a)}}var f=this;if(b.isUndefined(d)&&!b.isFunction(a))return a;if(b.isFunction(a)&&(d=a,a=c),!b.isFunction(d))return d;if(d.__raven__)return d;for(var g in d)d.hasOwnProperty(g)&&(e[g]=d[g]);return e.__raven__=!0,e}};return e}]}function e(a){a.decorator("$exceptionHandler",["$delegate","$raven","$injector",f])}function f(a,c,d){function e(e,g){f=f||d.get("$location");var h={culprit:f.absUrl(),extra:{exception:e,cause:g}};if(e instanceof Error)c.captureException(e,h);else{var i="";i=b.isString(e.message)?e.message:b.isString(e)?e:e.statusText||"",c.captureMessage(i,h)}a(e,g)}var f;return e}var g=null;b.module("ngRaven",[]).provider("$raven",d).provider("Raven",d).config(["$provide",e]),b.module("angular-raven",["ngRaven"])}(this,angular); -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-raven", 3 | "version": "0.6.3", 4 | "main": "angular-raven.js", 5 | "keywords": [ 6 | "Patrick", 7 | "PatrickJS", 8 | "gdi2290", 9 | "angular", 10 | "angularjs", 11 | "angular.js", 12 | "$exceptionHandler", 13 | "raven", 14 | "ravenjs", 15 | "raven.js", 16 | "sentry.js", 17 | "sentry", 18 | "sentryjs", 19 | "error", 20 | "errorhandler" 21 | ], 22 | "authors": [ 23 | { 24 | "name": "Patrick Stapleton", 25 | "email": "github@gdi2290.com", 26 | "url": "www.gdi2290.com" 27 | } 28 | ], 29 | "ignore": [ 30 | "**/.*", 31 | "*.yml", 32 | "*.xml", 33 | "node_modules", 34 | "bower_components", 35 | "test", 36 | "tests" 37 | ], 38 | "dependencies": { 39 | "angular": "*", 40 | "raven-js": "*" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Raven.js for Angular.js 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | 17 | 18 |
19 | 24 |
25 | 26 | 27 | 28 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-raven", 3 | "version": "0.6.3", 4 | "main": "angular-raven.js", 5 | "description": "A Raven.js / Sentry wrapper for Angular.js", 6 | "homepage": "https://github.com/gdi2290/angular-raven", 7 | "bugs": "https://github.com/gdi2290/angular-raven/issues", 8 | "author": { 9 | "name": "Patrick Stapleton", 10 | "email": "github@gdi2290.com", 11 | "url": "www.gdi2290.com" 12 | }, 13 | "keywords": [ 14 | "Patrick", 15 | "PatrickJS", 16 | "gdi2290", 17 | "angular", 18 | "angularjs", 19 | "angular.js", 20 | "$exceptionHandler", 21 | "raven", 22 | "ravenjs", 23 | "raven.js", 24 | "sentry.js", 25 | "sentry", 26 | "sentryjs", 27 | "error", 28 | "errorhandler" 29 | ], 30 | "repository": { 31 | "type": "git", 32 | "url": "git@github.com:gdi2290/angular-raven.git" 33 | }, 34 | "licenses": [ 35 | { 36 | "type": "MIT" 37 | } 38 | ], 39 | "dependencies": { 40 | "angular": "*", 41 | "raven": "*" 42 | }, 43 | "devDependencies": { 44 | "grunt": "~0.4.1", 45 | "grunt-bump": "^0.7.0", 46 | "grunt-contrib-jshint": "~0.6.0", 47 | "grunt-contrib-nodeunit": "~0.2.0", 48 | "grunt-contrib-uglify": "~0.9.0", 49 | "grunt-contrib-watch": "~0.5.0", 50 | "load-grunt-tasks": "~0.1.0", 51 | "time-grunt": "~0.1.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/angular-raven_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // var angularRaven = require('../angular-raven.js'); 4 | 5 | /* 6 | ======== A Handy Little Nodeunit Reference ======== 7 | https://github.com/caolan/nodeunit 8 | 9 | Test methods: 10 | test.expect(numAssertions) 11 | test.done() 12 | Test assertions: 13 | test.ok(value, [message]) 14 | test.equal(actual, expected, [message]) 15 | test.notEqual(actual, expected, [message]) 16 | test.deepEqual(actual, expected, [message]) 17 | test.notDeepEqual(actual, expected, [message]) 18 | test.strictEqual(actual, expected, [message]) 19 | test.notStrictEqual(actual, expected, [message]) 20 | test.throws(block, [error], [message]) 21 | test.doesNotThrow(block, [error], [message]) 22 | test.ifError(value) 23 | */ 24 | 25 | exports['angularRaven'] = { 26 | setUp: function(done) { 27 | // setup here 28 | done(); 29 | }, 30 | 'no args': function(test) { 31 | test.expect(1); 32 | // tests here 33 | test.equal(1, 1, 'pass the test.'); 34 | test.done(); 35 | } 36 | }; 37 | --------------------------------------------------------------------------------