New Added client-side Sentry logging

Using Raven.js allows logging client-side javascript errors to the
configured Sentry server.
This commit is contained in:
Raphaël Doursenaud 2015-08-31 17:21:03 +02:00
parent 7ef5cbfb96
commit a6ef289470
47 changed files with 7872 additions and 9 deletions

View File

@ -0,0 +1,18 @@
{
"name": "raven-js",
"version": "1.1.19",
"dependencies": {},
"main": "dist/raven.js",
"ignore": {},
"homepage": "https://github.com/getsentry/raven-js",
"_release": "1.1.19",
"_resolution": {
"type": "version",
"tag": "1.1.19",
"commit": "82b9c07b7545c6c10e297709a741eaa9b75f64e8"
},
"_source": "git://github.com/getsentry/raven-js.git",
"_target": "~1.1.19",
"_originalSource": "raven-js",
"_direct": true
}

22
htdocs/includes/raven-js/.gitignore vendored Normal file
View File

@ -0,0 +1,22 @@
.DS_Store
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
docs/html
docs/doctrees
build
node_modules
npm-debug.log
scratch/
*.pyc
.idea
aws.json

View File

@ -0,0 +1,9 @@
{
"es3": true,
"globalstrict": true,
"browser": true,
"predef": [
"TraceKit",
"console"
]
}

View File

@ -0,0 +1,8 @@
# language doesn't matter, we're only using phantom.js
language: node_js
node_js:
- "0.10"
script:
- ./node_modules/.bin/grunt test build
notifications:
irc: "irc.freenode.org#sentry"

View File

@ -0,0 +1 @@
https://github.com/getsentry/raven-js/graphs/contributors

View File

@ -0,0 +1,254 @@
module.exports = function(grunt) {
"use strict";
var _ = require('lodash');
var path = require('path');
var coreFiles = [
'template/_header.js',
'vendor/**/*.js',
'src/**/*.js',
'template/_footer.js'
];
var plugins = grunt.option('plugins');
// Create plugin paths and verify hey exist
plugins = _.map(plugins ? plugins.split(',') : [], function (plugin) {
var path = 'plugins/' + plugin + '.js';
if(!grunt.file.exists(path))
throw new Error("Plugin '" + plugin + "' not found in plugins directory.");
return path;
});
// Taken from http://dzone.com/snippets/calculate-all-combinations
var combine = function (a) {
var fn = function (n, src, got, all) {
if (n === 0) {
all.push(got);
return;
}
for (var j = 0; j < src.length; j++) {
fn(n - 1, src.slice(j + 1), got.concat([src[j]]), all);
}
};
var all = [a];
for (var i = 0; i < a.length; i++) {
fn(i, a, [], all);
}
return all;
};
var pluginCombinations = combine(grunt.file.expand('plugins/*.js'));
var pluginConcatFiles = _.reduce(pluginCombinations, function (dict, comb) {
var key = _.map(comb, function (plugin) {
return path.basename(plugin, '.js');
});
key.sort();
var dest = path.join('build/', key.join(','), '/raven.js');
dict[dest] = coreFiles.concat(comb);
return dict;
}, {});
var gruntConfig = {
pkg: grunt.file.readJSON('package.json'),
aws: grunt.file.exists('aws.json') ? grunt.file.readJSON('aws.json'): {},
clean: ['build'],
concat: {
options: {
separator: '\n',
banner: grunt.file.read('template/_copyright.js'),
process: true
},
core: {
src: coreFiles.concat(plugins),
dest: 'build/raven.js'
},
all: {
files: pluginConcatFiles
}
},
uglify: {
options: {
sourceMap: function (dest) {
return path.join(path.dirname(dest),
path.basename(dest, '.js')) +
'.map';
},
sourceMappingURL: function (dest) {
return path.basename(dest, '.js') + '.map';
},
preserveComments: 'some'
},
dist: {
src: ['build/**/*.js'],
ext: '.min.js',
expand: true
}
},
fixSourceMaps: {
all: ['build/**/*.map']
},
jshint: {
options: {
jshintrc: '.jshintrc'
},
all: ['Gruntfile.js', 'src/**/*.js', 'plugins/**/*.js']
},
mocha: {
all: {
options: {
mocha: {
ignoreLeaks: true,
grep: grunt.option('grep')
},
log: true,
reporter: 'Dot',
run: true
},
src: ['test/index.html'],
nonull: true
}
},
release: {
options: {
npm: false,
commitMessage: 'Release <%= version %>'
}
},
s3: {
options: {
key: '<%= aws.key %>',
secret: '<%= aws.secret %>',
bucket: '<%= aws.bucket %>',
access: 'public-read',
// Limit concurrency
maxOperations: 20,
headers: {
// Surrogate-Key header for Fastly to purge by release
'x-amz-meta-surrogate-key': '<%= pkg.release %>'
}
},
all: {
upload: [{
src: 'build/**/*',
dest: '<%= pkg.release %>/',
rel: 'build/'
}]
}
},
connect: {
test: {
options: {
port: 8000,
debug: true,
keepalive: true
}
},
docs: {
options: {
port: 8000,
debug: true,
base: 'docs/html',
keepalive: true
}
}
},
copy: {
dist: {
expand: true,
flatten: true,
cwd: 'build/',
src: '**',
dest: 'dist/'
}
}
};
grunt.initConfig(gruntConfig);
// Custom Grunt tasks
grunt.registerTask('version', function() {
var pkg = grunt.config.get('pkg');
if (grunt.option('dev')) {
pkg.release = 'dev';
pkg.version = grunt.config.get('gitinfo').local.branch.current.shortSHA;
} else {
pkg.release = pkg.version;
}
grunt.config.set('pkg', pkg);
});
grunt.registerMultiTask('fixSourceMaps', function () {
this.files.forEach(function (f) {
var result;
var sources = f.src.filter(function (filepath) {
if (!grunt.file.exists(filepath)) {
grunt.log.warn('Source file "' + filepath + '" not found.');
return false;
} else {
return true;
}
}).forEach(function (filepath) {
var base = path.dirname(filepath);
var sMap = grunt.file.readJSON(filepath);
sMap.file = path.relative(base, sMap.file);
sMap.sources = _.map(sMap.sources, path.relative.bind(path, base));
grunt.file.write(filepath, JSON.stringify(sMap));
// Print a success message.
grunt.log.writeln('File "' + filepath + '" fixed.');
});
});
});
// Grunt contrib tasks
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-copy');
// 3rd party Grunt tasks
grunt.loadNpmTasks('grunt-mocha');
grunt.loadNpmTasks('grunt-release');
grunt.loadNpmTasks('grunt-s3');
grunt.loadNpmTasks('grunt-gitinfo');
// Build tasks
grunt.registerTask('_prep', ['clean', 'gitinfo', 'version']);
grunt.registerTask('concat.core', ['_prep', 'concat:core']);
grunt.registerTask('concat.all', ['_prep', 'concat:all']);
grunt.registerTask('build.core', ['concat.core', 'uglify', 'fixSourceMaps']);
grunt.registerTask('build.all', ['concat.all', 'uglify', 'fixSourceMaps']);
grunt.registerTask('build', ['build.all']);
grunt.registerTask('dist', ['build.core', 'copy:dist']);
// Test task
grunt.registerTask('test', ['jshint', 'mocha']);
// Webserver tasks
grunt.registerTask('run:test', ['connect:test']);
grunt.registerTask('run:docs', ['connect:docs']);
grunt.registerTask('publish', ['test', 'build.all', 's3']);
grunt.registerTask('default', ['test']);
};

View File

@ -0,0 +1,9 @@
Copyright (c) 2014 Matt Robenolt and other contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,20 @@
develop: update-submodules
npm install .
update-submodules:
git submodule init
git submodule update
docs:
cd docs; $(MAKE) html
docs-live:
while true; do \
sleep 2; \
$(MAKE) docs; \
done
clean:
rm -rf docs/html
.PHONY: develop update-submodules docs docs-live clean

View File

@ -0,0 +1,13 @@
# Raven.js [![Build Status](https://travis-ci.org/getsentry/raven-js.svg?branch=master)](https://travis-ci.org/getsentry/raven-js)
Raven.js is a tiny standalone JavaScript client for [Sentry](https://www.getsentry.com/).
**Raven.js v1.1 requires Sentry v6.0 or later.**
## Resources
* [Download](http://ravenjs.com)
* [Documentation](https://raven-js.readthedocs.org)
* [Bug Tracker](https://github.com/getsentry/raven-js/issues)
* [IRC](irc://chat.freenode.net/sentry) (chat.freenode.net, #sentry)
* Follow [@mattrobenolt](https://twitter.com/mattrobenolt) on Twitter for updates

View File

@ -0,0 +1,7 @@
{
"name": "raven-js",
"version": "1.1.19",
"dependencies": {},
"main": "dist/raven.js",
"ignore": {}
}

1909
htdocs/includes/raven-js/dist/raven.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,153 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = .
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/raven-js.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/raven-js.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/raven-js"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/raven-js"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

View File

@ -0,0 +1,138 @@
Changelog
=========
1.1.19
~~~~~~
* Use more compliant way of creating an Image in the dom. See: https://github.com/getsentry/raven-js/pull/334
* `String` objects weren't getting identified as a string. See: https://github.com/getsentry/raven-js/pull/336
* Expose getter/setter for dataCallback and shouldSendCallback
* Better handle if/when the dataCallback returns garbage
* Fix support for nodeunit. See: https://github.com/getsentry/raven-js/pull/338
* Fix `console.warn` sending as a `warning` level to server. See: https://github.com/getsentry/raven-js/issues/342
* Improve the capture of unhandled errors from promises in Ember plugin. See: https://github.com/getsentry/raven-js/pull/330
1.1.18
~~~~~~
* Fixed a trailing comma which would make IE8 cry. This affects the uncompressed builds only. Compressed builds were unaffected. See: https://github.com/getsentry/raven-js/pull/333
1.1.17
~~~~~~
* Better support for Angular errors. See: https://github.com/getsentry/raven-js/pull/238
* Allow setting truncate length through ``globalOptions.maxMessageLength``. See: https://github.com/getsentry/raven-js/pull/246
* Fixed the pattern for parsing gecko stacktraces. See: https://github.com/getsentry/raven-js/pull/252
* Browserify support. See: https://github.com/getsentry/raven-js/pull/253, https://github.com/getsentry/raven-js/pull/260, https://github.com/getsentry/raven-js/pull/261
* Start tracking ``session:duration`` automatically as metadata.
* Fix globalOptions overwrite. See: https://github.com/getsentry/raven-js/pull/264
* Better cross origin support. See: https://github.com/getsentry/raven-js/pull/276
* Better anonymous function support in Chrome stack trace parsing. See: https://github.com/getsentry/raven-js/pull/290, https://github.com/getsentry/raven-js/pull/294
* Remove deprecated ``site`` param.
* New ``Raven.isSetup()``. See: https://github.com/getsentry/raven-js/pull/309
* Better backbone.js support. See: https://github.com/getsentry/raven-js/pull/307
* ``ignoreErrors`` now also is applied to ``captureMessage()``. See: https://github.com/getsentry/raven-js/pull/312
* Capture unhandled errors from promises in Ember. See: https://github.com/getsentry/raven-js/pull/319
* Add new support for ``releases``. See: https://github.com/getsentry/raven-js/issues/325
1.1.16
~~~~~~
* Fixed a bug that was preventing stack frames from ``raven.js`` from being hidden correctly. See: https://github.com/getsentry/raven-js/pull/216
* Fixed an IE bug with the ``console`` plugin. See: https://github.com/getsentry/raven-js/issues/217
* Added support for ``chrome-extension://`` protocol in Chrome in stack traces.
* Added ``setExtraContext`` and ``setTagsContext``. See: https://github.com/getsentry/raven-js/pull/219
* Renamed ``setUser`` to ``setUserContext`` to match. ``setUser`` still exists, but will be deprecated in a future release.
* New ``backbone.js`` plugin. See: https://github.com/getsentry/raven-js/pull/220
* Added support for ``chrome://`` protocol in Firefox in stack traces. See: https://github.com/getsentry/raven-js/pull/225
* Ignore more garbage from IE cross origin errors. See: https://github.com/getsentry/raven-js/pull/224
* Added ``Raven.debug`` to prevent logging to ``console`` when ``false``. Defaults to ``true`` for backwards compatability. See: https://github.com/getsentry/raven-js/pull/229
* Prevent calling ``Raven.config()`` or ``Raven.install()`` twice. See: https://github.com/getsentry/raven-js/pull/233
1.1.15
~~~~~~
* Fix issues if a non-string were passed to ``Raven.captureMessage`` and non-Error objects were passed to ``Raven.captureException``.
1.1.14
~~~~~~
* Only filter normal Error objects without a message, not all of them. Turns out, people throw errors like this. Ahem, Underscore.js. See: https://github.com/jashkenas/underscore/pull/1589/files
1.1.13
~~~~~~
* Fixed a unicode issue in the previous release.
1.1.12
~~~~~~
* Fix a bug using the ``console`` plugin with older IE. See: https://github.com/getsentry/raven-js/pull/192
* Added initial ``ember.js`` plugin for early testing and feedback.
* Added initial ``angular.js`` plugin for early testing and feedback.
* Fixed an issue with the ``require.js`` plugin basically not working at all. See: https://github.com/getsentry/raven-js/commit/c2a2e2672a2a61a5a07e88f24a9c885f6dba57ae
* Got rid of ``Raven.afterLoad`` and made it internal only.
* ``Raven.TraceKit`` is now internal only.
* Truncate message length to a max of 100 characters becasue angular.js sucks and generates stupidly large error messages.
1.1.11
~~~~~~
* Capture column number from FireFox
* Fix propagation of extra options through ``captureException``, see: https://github.com/getsentry/raven-js/pull/189
* Fix a minor bug that causes TraceKit to blow up of someone passes something dumb through ``window.onerror``
1.1.10
~~~~~~
* A falsey DSN value disables Raven without yelling about an invalid DSN.
1.1.9
~~~~~
* Added ``Raven.lastEventId()`` to get back the Sentry event id. See: http://raven-js.readthedocs.org/en/latest/usage/index.html#getting-back-an-event-id
* Fixed a bug in the ``console`` plugin. See: https://github.com/getsentry/raven-js/pull/181
* Provide a way out of deep wrapping arguments. See: https://github.com/getsentry/raven-js/pull/182
* ``Raven.uninstall()`` actually removes the patched ``window.onerror``.
* No more globally exposed ``TraceKit``!
1.1.8
~~~~~
* Fixed a bug in IE8. See: https://github.com/getsentry/raven-js/pull/179
1.1.4-1.1.7
~~~~~~~~~~~
These were a bunch of super small incremental updates trying to get better integration and better support inside Sentry itself.
* Culprit determined from the src url of the offending script, not the url of the page.
* Send Sentry the frames in the right order. They were being sent in reverse. Somehow nobody noticed this.
* Support for Chrome's new window.onerror api. See: https://github.com/getsentry/raven-js/issues/172
1.1.3
~~~~~
* When loading with an AMD loader present, do not automatically call ``Raven.noConflict()``. This was causing issues with using plugins. See: https://github.com/getsentry/raven-js/pull/165
* https://github.com/getsentry/raven-js/pull/168
1.1.2
~~~~~
* An invalid DSN will now raise a RavenConfigError instead of some cryptic error
* Will raise a RavenConfigError when supplying the private key part of the DSN since this isn't applicable for raven.js and is harmful to include
* https://github.com/getsentry/raven-js/issues/128
1.1.1
~~~~~
* Fixed a bug in parsing some DSNs. See: https://github.com/getsentry/raven-js/issues/160
1.1.0
~~~~~
Plugins
-------
If you're upgrading from 1.0.x, 2 "plugins" were included with the package. These 2 plugins are now stripped out of core and included as the ``jquery`` and ``native`` plugins. If you'd like to start using 1.1.0 and maintain existing functionality, you'll want to use: http://cdn.ravenjs.com/1.1.0/jquery,native/raven.min.js For a list of other plugins, checkout http://ravenjs.com
ravenjs.com
-----------
A new website dedicated to helping you compile a custom build of raven.js
whitelistUrls
-------------
``whitelistUrls`` are recommended over ``ignoreUrls``. ``whitelistUrls`` drastically helps cut out noisy error messages from other scripts running on your site.
Misc
----
* ``ignoreUrls``, ``ignoreErrors``, ``includePaths`` have all been unified to accept both a regular expression and strings to avoid confusion and backwards compatability
* ``Raven.wrap`` recursively wraps arguments
* Events are dispatched when an exception is received, recorded or failed sending to Sentry
* Support newer Sentry protocol which allows smaller packets
* Allow loading raven async with RavenConfig
* Entirely new build system with Grunt
* ``options.collectWindowErrors`` to tell Raven to ignore window.onerror

View File

@ -0,0 +1,244 @@
# -*- coding: utf-8 -*-
#
# raven-js documentation build configuration file, created by
# sphinx-quickstart on Mon Jan 21 21:04:27 2013.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os, datetime
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'raven-js'
copyright = u'%s, Matt Robenolt' % datetime.date.today().year
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
import json
# The full version, including alpha/beta/rc tags.
release = json.load(open('../package.json'))['version']
# The short X.Y version.
version = release.rsplit('.', 1)[0]
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'raven-jsdoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'raven-js.tex', u'raven-js Documentation',
u'Matt Robenolt', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'raven-js', u'raven-js Documentation',
[u'Matt Robenolt'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'raven-js', u'raven-js Documentation',
u'Matt Robenolt', 'raven-js', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

View File

@ -0,0 +1,220 @@
Configuration
=============
We must first configure Sentry to allow certain hosts to report errors. This prevents abuse so somebody else couldn't start sending errors to your account from their site.
**Note**: Without setting this, all messages will be rejected!
This can be found under the *Project Details* page in Sentry.
.. image:: https://i.imgur.com/S09MeSM.png
Now need to set up Raven.js to use your Sentry DSN.
.. code-block:: javascript
Raven.config('https://public@getsentry.com/1').install()
At this point, Raven is ready to capture any uncaught exception.
Although, this technically works, this is not going to yield the greatest results. It's highly recommended to next check out :doc:`/usage/index`.
Optional settings
~~~~~~~~~~~~~~~~~
``Raven.config()`` can be passed an optional object for extra configuration.
logger
------
The name of the logger used by Sentry. Default: ``javascript``
.. code-block:: javascript
{
logger: 'javascript'
}
release
-------
Track the version of your application in Sentry.
.. code-block:: javascript
{
release: '721e41770371db95eee98ca2707686226b993eda'
}
Can also be defined with ``Raven.setReleaseContext('721e41770371db95eee98ca2707686226b993eda')``.
.. _config-whitelist-urls:
tags
----
Additional `tags <https://www.getsentry.com/docs/tags/>`__ to assign to each event.
.. code-block:: javascript
{
tags: {git_commit: 'c0deb10c4'}
}
whitelistUrls
-------------
The inverse of ``ignoreUrls``. Only report errors from whole urls matching a regex pattern or an exact string. ``whitelistUrls`` should match the url of your actual JavaScript files. It should match the url of your site if and only if you are inlining code inside ``<script>`` tags.
Does not affect captureMessage or when non-error object is passed in as argument to captureException.
.. code-block:: javascript
{
whitelistUrls: [/getsentry\.com/, /cdn\.getsentry\.com/]
}
ignoreErrors
------------
Very often, you will come across specific errors that are a result of something other than your application, or errors that you're completely not interested in. `ignoreErrors` is a list of these messages to be filtered out before being sent to Sentry as either regular expressions or strings.
Does not affect captureMessage or when non-error object is passed in as argument to captureException.
.. code-block:: javascript
{
ignoreErrors: ['fb_xd_fragment']
}
ignoreUrls
----------
The inverse of ``whitelistUrls`` and similar to ``ignoreErrors``, but will ignore errors from whole urls matching a regex pattern or an exact string.
.. code-block:: javascript
{
ignoreUrls: [/graph\.facebook\.com/, 'http://example.com/script2.js']
}
Does not affect captureMessage or when non-error object is passed in as argument to captureException.
includePaths
------------
An array of regex patterns to indicate which urls are a part of your app in the stack trace. All other frames will appear collapsed inside Sentry to make it easier to discern between frames that happened in your code vs other code. It'd be suggested to add the current page url, and the host for your CDN.
.. code-block:: javascript
{
includePaths: [/https?:\/\/getsentry\.com/, /https?:\/\/cdn\.getsentry\.com/]
}
dataCallback
------------
A function that allows mutation of the data payload right before being sent to Sentry.
.. code-block:: javascript
{
dataCallback: function(data) {
// do something to data
return data;
}
}
Can also be set at runtime with `Raven.setDataCallback(function(data) { ... })`.
shouldSendCallback
------------------
A callback function that allows you to apply your own filters to determine if the message should be sent to Sentry.
.. code-block:: javascript
{
shouldSendCallback: function(data) {
return false;
}
}
Can also be set at runtime with `Raven.setShouldSendCallback(function(data) { ... })`.
maxMessageLength
------------------
By default, raven truncates messages to a max length of 100 characters. You can customize the max length with this parameter.
Putting it all together
~~~~~~~~~~~~~~~~~~~~~~~
.. parsed-literal::
<!DOCTYPE html>
<html>
<head>
<title>Awesome stuff happening here</title>
</head>
<body>
...
<script src="jquery.min.js"></script>
<script src="//cdn.ravenjs.com/|release|/jquery,native/raven.min.js"></script>
<script>
var options = {
logger: 'my-logger',
whitelistUrls: [
/disqus\\.com/, /getsentry\\.com/
],
ignoreErrors: [
'fb_xd_fragment', /ReferenceError:.*/
],
includePaths: [
/https?:\\/\\/(www\\.)?getsentry\\.com/
]
};
Raven.config('https://public@app.getsentry.com/1', options).install();
</script>
<script src="myapp.js"></script>
</body>
</html>
TraceKit specific optional settings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Usually there is no need to touch these settings, but they exist in case you need to tweak something.
fetchContext
------------
Enable TraceKit to attempt to fetch source files to look up anonymous function names, this can be useful to enable if you don't get the context for some entries in the stack trace. Default value is ``false``.
.. code-block:: javascript
{
fetchContext: true
}
linesOfContext
--------------
The count of lines surrounding the error line that should be used as context in the stack trace, default value is ``11``. Only applicable when ``fetchContext` is enabled.
.. code-block:: javascript
{
linesOfContext: 11
}
collectWindowErrors
-------------------
Enable or disable the TraceKit ``window.onerror`` handler, default value is ``true``.
.. code-block:: javascript
{
collectWindowErrors: true
}

View File

@ -0,0 +1,99 @@
Contributing
============
Setting up an Environment
~~~~~~~~~~~~~~~~~~~~~~~~~
To run the test suite and run our code linter, node.js and npm are required. If you don't have node installed, `get it here <http://nodejs.org/download/>`_ first.
Installing all other dependencies is as simple as:
.. code-block:: sh
$ npm install
And if you don't have `Grunt <http://gruntjs.com/>`_ already, feel free to install that globally:
.. code-block:: sh
$ npm install -g grunt-cli
Running the Test Suite
~~~~~~~~~~~~~~~~~~~~~~
The test suite is powered by `Mocha <http://visionmedia.github.com/mocha/>`_ and can both run from the command line, or in the browser.
From the command line:
.. code-block:: sh
$ grunt test
From your browser:
.. code-block:: sh
$ grunt run:test
Then visit: http://localhost:8000/test/
Compiling Raven.js
~~~~~~~~~~~~~~~~~~
The simplest way to compile your own version of Raven.js is with the supplied grunt command:
.. code-block:: sh
$ grunt build
By default, this will compile raven.js and all of the included plugins.
If you only want to compile the core raven.js:
.. code-block:: sh
$ grunt build.core
Files are compiled into ``build/``.
Contributing Back Code
~~~~~~~~~~~~~~~~~~~~~~
Please, send over suggestions and bug fixes in the form of pull requests on `GitHub <https://github.com/getsentry/raven-js>`_. Any nontrivial fixes/features should include tests.
Do not include any changes to the ``dist/`` folder or bump version numbers yourself.
Documentation
-------------
The documentation is written using `reStructuredText <http://en.wikipedia.org/wiki/ReStructuredText>`_, and compiled using `Sphinx <http://sphinx-doc.org/>`_. If you don't have Sphinx installed, you can do it using following command (assuming you have Python already installed in your system):
.. code-block:: sh
$ pip install sphinx
Documentation can be then compiled by running:
.. code-block:: sh
$ make docs
Afterwards you can view it in your browser by running following command and than pointing your browser to http://127.0.0.1:8000/:
.. code-block:: sh
$ grunt run:docs
Releasing New Version
~~~~~~~~~~~~~~~~~~~~~
* Bump version numbers in both ``package.json`` and ``bower.json``.
* ``$ grunt dist`` This will compile a new version and update it in the ``dist/`` folder.
* Confirm that build was fine, etc.
* Commit new version, create a tag. Push to GitHub.
* ``$ grunt publish`` to recompile all plugins and all permutations and upload to S3.
* ``$ npm publish`` to push to npm.
* Confirm that the new version exists behind ``cdn.ravenjs.com``
* Update version in the ``gh-pages`` branch specifically for http://ravenjs.com/.
* glhf

View File

@ -0,0 +1,42 @@
Raven.js
========
Raven.js is a tiny standalone JavaScript client for `Sentry <http://www.getsentry.com/>`_.
**This version of Raven.js requires Sentry 6.0 or newer.**
Getting Started
---------------
.. toctree::
:maxdepth: 2
install/index
plugins/index
config/index
usage/index
tips/index
Developers
----------
.. toctree::
:maxdepth: 2
contributing/index
What's New?
-----------
.. toctree::
:maxdepth: 2
changelog/index
Resources
---------
* `Download <http://ravenjs.com>`_
* `Bug Tracker <https://github.com/getsentry/raven-js/issues>`_
* `Code <https://github.com/getsentry/raven-js>`_
* `IRC <irc://irc.freenode.net/sentry>`_ (irc.freenode.net, #sentry)
* :doc:`Changelog </changelog/index>`
* Follow `@mattrobenolt <https://twitter.com/mattrobenolt>`_ on Twitter for updates!

View File

@ -0,0 +1,61 @@
Installation
============
Raven is distributed in a few different methods, and should get included after any other libraries are included, but before your own scripts.
So for example:
.. parsed-literal::
<script src="jquery.js"></script>
<script src="//cdn.ravenjs.com/|release|/jquery,native/raven.min.js"></script>
<script>Raven.config('...').install();</script>
<script src="app.js"></script>
This allows the ability for Raven's plugins to instrument themselves. If included before something like jQuery, it'd be impossible to use for example, the jquery plugin.
Using our CDN
~~~~~~~~~~~~~
We serve our own builds off of `Fastly <http://www.fastly.com/>`_. They are accessible over both http and https, so we recommend leaving the protocol off.
Our CDN distributes builds with and without :doc:`plugins </plugins/index>`.
.. parsed-literal::
<script src="//cdn.ravenjs.com/|release|/raven.min.js"></script>
**We highly recommend trying out a plugin or two since it'll greatly improve the chances that we can collect good information.**
This version does not include any plugins. See `ravenjs.com <http://ravenjs.com/>`_ for more information about plugins and getting other builds.
Bower
~~~~~
We also provide a way to deploy Raven via `bower
<http://bower.io/>`_. Useful if you want serve your own scripts instead of depending on our CDN and mantain a ``bower.json`` with a list of dependencies and versions (adding the ``--save`` flag would automatically add it to ``bower.json``).
.. code-block:: sh
$ bower install raven-js --save
.. code-block:: html
<script src="/bower_components/raven-js/dist/raven.js"></script>
Also note that the file is uncompresed but is ready to pass to any decent JavaScript compressor like `uglify <https://github.com/mishoo/UglifyJS2>`_.
npm
~~~
Raven is published to npm as well. https://www.npmjs.com/package/raven-js
.. code-block:: sh
$ npm install raven-js --save
Requirements
~~~~~~~~~~~~
Raven expects the browser to provide `window.JSON` and `window.JSON.stringify`. In Internet Explorer 8+ these are available in `standards mode <http://msdn.microsoft.com/en-us/library/cc288325(VS.85).aspx>`_.
You can also use `json2.js <https://github.com/douglascrockford/JSON-js>`_ to provide the JSON implementation in browsers/modes which doesn't support native JSON

View File

@ -0,0 +1,190 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\raven-js.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\raven-js.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

View File

@ -0,0 +1,20 @@
Plugins
=======
What are plugins?
~~~~~~~~~~~~~~~~~
In Raven.js, plugins are little snippets of code to augment functionality for a specific application/framework. It is highly recommended to checkout the list of plugins and use what apply to your project.
In order to keep the core small, we have opted to only include the most basic functionality by default, and you can pick and choose which plugins are applicable for you.
Why are plugins needed at all?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
JavaScript is pretty restrictive when it comes to exception handling, and there are a lot of things that make it difficult to get relevent information, so it's important that we inject code and wrap things magically so we can extract what we need. See :doc:`/usage/index` for tips regarding that.
All Plugins
~~~~~~~~~~~
* https://github.com/getsentry/raven-js/tree/master/plugins
* `Download <http://ravenjs.com>`_

View File

@ -0,0 +1,79 @@
Pro Tips™
=========
Decluttering Sentry
~~~~~~~~~~~~~~~~~~~
The first thing to do is to consider constructing a whitelist of domains in which might raise acceptable exceptions.
If your scripts are loaded from ``cdn.example.com`` and your site is ``example.com`` it'd be reasonable to set ``whitelistUrls`` to:
.. code-block:: javascript
whitelistUrls: [
/https?:\/\/((cdn|www)\.)?example\.com/
]
Since this accepts a regular expression, that would catch anything \*.example.com or example.com exactly. See also: :ref:`Config: whitelistUrls<config-whitelist-urls>`.
Next, checkout the list of :doc:`plugins </plugins/index>` we provide and see which are applicable to you.
The community has compiled a list of common ignore rules for common things, like Facebook, Chrome extensions, etc. So it's recommended to at least check these out and see if they apply to you. `Check out the original gist <https://gist.github.com/impressiver/5092952>`_.
.. code-block:: javascript
var ravenOptions = {
ignoreErrors: [
// Random plugins/extensions
'top.GLOBALS',
// See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error. html
'originalCreateNotification',
'canvas.contentDocument',
'MyApp_RemoveAllHighlights',
'http://tt.epicplay.com',
'Can\'t find variable: ZiteReader',
'jigsaw is not defined',
'ComboSearch is not defined',
'http://loading.retry.widdit.com/',
'atomicFindClose',
// Facebook borked
'fb_xd_fragment',
// ISP "optimizing" proxy - `Cache-Control: no-transform` seems to reduce this. (thanks @acdha)
// See http://stackoverflow.com/questions/4113268/how-to-stop-javascript-injection-from-vodafone-proxy
'bmi_SafeAddOnload',
'EBCallBackMessageReceived',
// See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx
'conduitPage'
],
ignoreUrls: [
// Facebook flakiness
/graph\.facebook\.com/i,
// Facebook blocked
/connect\.facebook\.net\/en_US\/all\.js/i,
// Woopra flakiness
/eatdifferent\.com\.woopra-ns\.com/i,
/static\.woopra\.com\/js\/woopra\.js/i,
// Chrome extensions
/extensions\//i,
/^chrome:\/\//i,
// Other plugins
/127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb
/webappstoolbarba\.texthelp\.com\//i,
/metrics\.itunes\.apple\.com\.edgesuite\.net\//i
]
};
Sampling Data
~~~~~~~~~~~~~
It happens frequently that errors sent from your frontend can be overwhelming. One solution here is to only send a sample of the events that happen. You can do this via the ``shouldSendCallback`` setting:
.. code-block:: javascript
shouldSendCallback: function(data) {
// only send 10% of errors
var sampleRate = 10;
return (Math.random() * 100 <= sampleRate);
}

View File

@ -0,0 +1,156 @@
Usage
=====
By default, Raven makes a few efforts to try its best to capture meaningful stack traces, but browsers make it pretty difficult.
The easiest solution is to prevent an error from bubbling all of the way up the stack to ``window``.
How to actually capture an error correctly
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
try...catch
-----------
The simplest way, is to try and explicitly capture and report potentially problematic code with a ``try...catch`` block and ``Raven.captureException``.
.. code-block:: javascript
try {
doSomething(a[0])
} catch(e) {
Raven.captureException(e)
}
**Do not** throw strings! Always throw an actual ``Error`` object. For example:
.. code-block:: javascript
throw new Error('broken') // good
throw 'broken' // bad
It's impossible to retrieve a stack trace from a string. If this happens, Raven transmits the error as a plain message.
context/wrap
------------
``Raven.context`` allows you to wrap any function to be immediately executed. Behind the scenes, Raven is just wrapping your code in a ``try...catch`` block to record the exception before re-throwing it.
.. code-block:: javascript
Raven.context(function() {
doSomething(a[0])
})
``Raven.wrap`` wraps a function in a similar way to ``Raven.context``, but instead of executing the function, it returns another function. This is totally awesome for use when passing around a callback.
.. code-block:: javascript
var doIt = function() {
// doing cool stuff
}
setTimeout(Raven.wrap(doIt), 1000)
Tracking authenticated users
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
While a user is logged in, you can tell Sentry to associate errors with user data.
.. code-block:: javascript
Raven.setUserContext({
email: 'matt@example.com',
id: '123'
})
If at any point, the user becomes unauthenticated, you can call ``Raven.setUserContext()`` with no arguments to remove their data. *This would only really be useful in a large web app where the user logs in/out without a page reload.*
Capturing a specific message
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: javascript
Raven.captureMessage('Broken!')
Passing additional data
~~~~~~~~~~~~~~~~~~~~~~~
``captureException``, ``context``, ``wrap``, and ``captureMessage`` functions all allow passing additional data to be tagged onto the error, such as ``tags`` or ``extra`` for additional context.
.. code-block:: javascript
Raven.captureException(e, {tags: { key: "value" }})
Raven.captureMessage('Broken!', {tags: { key: "value" }})
Raven.context({tags: { key: "value" }}, function(){ ... })
Raven.wrap({logger: "my.module"}, function(){ ... })
Raven.captureException(e, {extra: { foo: "bar" }})
You can also set context variables globally to be merged in with future exceptions with ``setExtraContext`` and ``setTagsContext``.
.. code-block:: javascript
Raven.setExtraContext({ foo: "bar" })
Raven.setTagsContext({ key: "value" })
Getting back an event id
~~~~~~~~~~~~~~~~~~~~~~~~
An event id is a globally unique id for the event that was just sent. This event id can be used to find the exact event from within Sentry.
This is often used to display for the user and report an error to customer service.
.. code-block:: javascript
Raven.lastEventId()
``Raven.lastEventId()`` will be undefined until an event is sent. After an event is sent, it will contain the string id.
.. code-block:: javascript
Raven.captureMessage('Broken!')
alert(Raven.lastEventId())
Check if Raven is setup and ready to go
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: javascript
Raven.isSetup()
Dealing with minified source code
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Raven and Sentry now support `Source Maps <http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/>`_.
We have provided some instructions to creating Source Maps over at https://www.getsentry.com/docs/sourcemaps/. Also, checkout our `Gruntfile <https://github.com/getsentry/raven-js/blob/master/Gruntfile.js>`_ for a good example of what we're doing.
You can use `Source Map Validator <http://sourcemap-validator.herokuapp.com/>`_ to help verify that things are correct.
CORS
~~~~
If you're hosting your scripts on another domain and things don't get caught by Raven, it's likely that the error will bubble up to ``window.onerror``. If this happens, the error will report some ugly ``Script error`` and Raven will drop it on the floor
since this is a useless error for everybody.
To help mitigate this, we can tell the browser that these scripts are safe and we're allowing them to expose their errors to us.
In your ``<script>`` tag, specify the ``crossorigin`` attribute:
.. code-block:: html
<script src="//cdn.example.com/script.js" crossorigin="anonymous"></script>
And set an ``Access-Control-Allow-Origin`` HTTP header on that file.
.. code-block:: console
Access-Control-Allow-Origin: *
**Note: both of these steps need to be done or your scripts might not even get executed**

View File

@ -0,0 +1,3 @@
build:
../node_modules/.bin/uglifyjs --source-map=file.sourcemap.js -c -o file.min.js file1.js file2.js

View File

@ -0,0 +1,2 @@
function add(a,b){"use strict";return a+b}function multiply(a,b){"use strict";return a*b}function divide(a,b){"use strict";try{return multiply(add(a,b),a,b)/c}catch(e){Raven.captureException(e)}}
//@ sourceMappingURL=file.sourcemap.js

View File

@ -0,0 +1 @@
{"version":3,"file":"file.min.js","sources":["file1.js","file2.js"],"names":["add","a","b","multiply","divide","c","e","Raven","captureException"],"mappings":"AAAA,QAASA,KAAIC,EAAGC,GACf,YACA,OAAOD,GAAIC,ECFZ,QAASC,UAASF,EAAGC,GACpB,YACA,OAAOD,GAAIC,EAEZ,QAASE,QAAOH,EAAGC,GAClB,YACA,KACC,MAAOC,UAASH,IAAIC,EAAGC,GAAID,EAAGC,GAAKG,EAClC,MAAOC,GACRC,MAAMC,iBAAiBF"}

View File

@ -0,0 +1,4 @@
function add(a, b) {
"use strict";
return a + b;
}

View File

@ -0,0 +1,12 @@
function multiply(a, b) {
"use strict";
return a * b;
}
function divide(a, b) {
"use strict";
try {
return multiply(add(a, b), a, b) / c;
} catch (e) {
Raven.captureException(e);
}
}

View File

@ -0,0 +1,41 @@
<!doctype html>
<html>
<head>
<title>Scratch Disk</title>
</head>
<script src="../vendor/TraceKit/tracekit.js"></script>
<script src="../src/raven.js"></script>
<!-- <script src="scratch.min.js"></script> -->
<script src="scratch.js" crossorigin></script>
<script src="file.min.js" crossorigin></script>
<script>
//cool
//really cool
//awesome
Raven.config('http://50dbe04cd1224d439e9c49bf1d0464df@localhost:8000/1', {
whitelistUrls: [
/localhost/
],
dataCallback: function(data) {
console.log(data);
return data;
}
}).install();
Raven.setUserContext({
email: 'matt@ydekproductions.com',
id: 5
})
</script>
<body>
<button id="test">Break me</button>
<script>ready()</script>
<button onclick="divide(1, 0)">Sourcemap breakage</button>
<button onclick="derp()">window.onerror</button>
<button onclick="testOptions()">test options</button>
<button onclick="throwString()">throw string</button>
</body>
</html>

View File

@ -0,0 +1,42 @@
function foo() {
console.log("lol, i don't do anything")
}
function foo2() {
foo()
console.log('i called foo')
}
function broken() {
try {
/*fkjdsahfdhskfhdsahfudshafuoidashfudsa*/ fdasfds[0]; // i throw an error h sadhf hadsfdsakf kl;dsjaklf jdklsajfk ljds;klafldsl fkhdas;hf hdsaf hdsalfhjldksahfljkdsahfjkl dhsajkfl hdklsahflkjdsahkfj hdsjakhf dkashfl diusafh kdsjahfkldsahf jkdashfj khdasjkfhdjksahflkjdhsakfhjdksahfjkdhsakf hdajskhf kjdash kjfads fjkadsh jkfdsa jkfdas jkfdjkas hfjkdsajlk fdsajk fjkdsa fjdsa fdkjlsa fjkdaslk hfjlkdsah fhdsahfui
}catch(e) {
Raven.captureException(e);
}
}
function ready() {
document.getElementById('test').onclick = broken;
}
function foo3() {
document.getElementById('crap').value = 'barfdasjkfhoadshflkaosfjadiosfhdaskjfasfadsfads';
}
function somethingelse() {
document.getElementById('somethingelse').value = 'this is some realy really long message just so our minification is largeeeeeeeeee!';
}
function derp() {
fdas[0];
}
function testOptions() {
Raven.context({tags: {foo: 'bar'}}, function() {
throw new Error('foo');
});
}
function throwString() {
throw 'oops';
}

View File

@ -0,0 +1,32 @@
{
"name": "raven-js",
"version": "1.1.19",
"license": "BSD-2-Clause",
"homepage": "https://getsentry.com",
"scripts": {
"pretest": "npm install",
"test": "grunt test"
},
"repository": {
"type": "git",
"url": "git://github.com/getsentry/raven-js.git"
},
"main": "dist/raven.js",
"devDependencies": {
"chai": "~1.8.1",
"grunt": "~0.4.1",
"grunt-cli": "~0.1.9",
"grunt-contrib-jshint": "~0.6.3",
"grunt-contrib-uglify": "~0.2.2",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-clean": "~0.4.0",
"grunt-mocha": "~0.4.1",
"grunt-release": "~0.6.0",
"grunt-s3": "~0.2.0-alpha.3",
"grunt-gitinfo": "~0.1.1",
"grunt-contrib-connect": "~0.5.0",
"grunt-contrib-copy": "~0.4.1",
"sinon": "~1.7.3",
"lodash": "~2.4.0"
}
}

View File

@ -0,0 +1,36 @@
/**
* Angular.js plugin
*
* Provides an $exceptionHandler for Angular.js
*/
;(function(Raven, angular) {
'use strict';
// quit if angular isn't on the page
if (!angular) {
return;
}
function ngRavenProvider($provide) {
$provide.decorator('$exceptionHandler', [
'RavenConfig', '$delegate',
ngRavenExceptionHandler
]);
}
function ngRavenExceptionHandler(RavenConfig, $delegate) {
if (!RavenConfig)
throw new Error('RavenConfig must be set before using this');
Raven.config(RavenConfig.dsn, RavenConfig.config).install();
return function angularExceptionHandler(ex, cause) {
$delegate(ex, cause);
Raven.captureException(ex, {extra: {cause: cause}});
};
}
angular.module('ngRaven', [])
.config(['$provide', ngRavenProvider])
.value('Raven', Raven);
})(window.Raven, window.angular);

View File

@ -0,0 +1,55 @@
/**
* Backbone.js plugin
*
* Patches Backbone.Events callbacks.
*/
;(function(window, Raven, Backbone) {
'use strict';
// quit if Backbone isn't on the page
if (!Backbone) {
return;
}
function makeBackboneEventsOn(oldOn) {
return function BackboneEventsOn(name, callback, context) {
var wrapCallback = function (cb) {
if (Object.prototype.toString.call(cb) === '[object Function]') {
var _callback = cb._callback || cb;
cb = Raven.wrap(cb);
cb._callback = _callback;
}
return cb;
};
if (Object.prototype.toString.call(name) === '[object Object]') {
// Handle event maps.
for (var key in name) {
if (name.hasOwnProperty(key)) {
name[key] = wrapCallback(name[key]);
}
}
} else {
callback = wrapCallback(callback);
}
return oldOn.call(this, name, callback, context);
};
}
// We're too late to catch all of these by simply patching Backbone.Events.on
var affectedObjects = [
Backbone.Events,
Backbone,
Backbone.Model.prototype,
Backbone.Collection.prototype,
Backbone.View.prototype,
Backbone.Router.prototype,
Backbone.History.prototype
], i = 0, l = affectedObjects.length;
for (; i < l; i++) {
var affected = affectedObjects[i];
affected.on = makeBackboneEventsOn(affected.on);
affected.bind = affected.on;
}
}(window, window.Raven, window.Backbone));

View File

@ -0,0 +1,43 @@
/**
* console plugin
*
* Monkey patches console.* calls into Sentry messages with
* their appropriate log levels. (Experimental)
*/
;(function(window, Raven, console) {
'use strict';
var originalConsole = console,
logLevels = ['debug', 'info', 'warn', 'error'],
level = logLevels.pop();
var logForGivenLevel = function(level) {
var originalConsoleLevel = console[level];
// warning level is the only level that doesn't map up
// correctly with what Sentry expects.
if (level === 'warn') level = 'warning';
return function () {
var args = [].slice.call(arguments);
Raven.captureMessage('' + args, {level: level, logger: 'console'});
// this fails for some browsers. :(
if (originalConsoleLevel) {
// IE9 doesn't allow calling apply on console functions directly
// See: https://stackoverflow.com/questions/5472938/does-ie9-support-console-log-and-is-it-a-real-function#answer-5473193
Function.prototype.bind
.call(originalConsoleLevel, originalConsole)
.apply(originalConsole, args);
}
};
};
while(level) {
console[level] = logForGivenLevel(level);
level = logLevels.pop();
}
// export
window.console = console;
}(window, window.Raven, window.console || {}));

View File

@ -0,0 +1,29 @@
/**
* Ember.js plugin
*
* Patches event handler callbacks and ajax callbacks.
*/
;(function(window, Raven, Ember) {
'use strict';
// quit if Ember isn't on the page
if (!Ember) {
return;
}
var _oldOnError = Ember.onerror;
Ember.onerror = function EmberOnError(error) {
Raven.captureException(error);
if (typeof _oldOnError === 'function') {
_oldOnError.call(this, error);
}
};
Ember.RSVP.on('error', function (reason) {
if (reason instanceof Error) {
Raven.captureException(reason, {extra: {context: 'Unhandled Promise error detected'}});
} else {
Raven.captureMessage('Unhandled Promise error detected', {extra: {reason: reason}});
}
});
}(window, window.Raven, window.Ember));

View File

@ -0,0 +1,75 @@
/**
* jQuery plugin
*
* Patches event handler callbacks and ajax callbacks.
*/
;(function(window, Raven, $) {
'use strict';
// quit if jQuery isn't on the page
if (!$) {
return;
}
var _oldEventAdd = $.event.add;
$.event.add = function ravenEventAdd(elem, types, handler, data, selector) {
var _handler;
if (handler && handler.handler) {
_handler = handler.handler;
handler.handler = Raven.wrap(handler.handler);
} else {
_handler = handler;
handler = Raven.wrap(handler);
}
// If the handler we are attaching doesnt have the same guid as
// the original, it will never be removed when someone tries to
// unbind the original function later. Technically as a result of
// this our guids are no longer globally unique, but whatever, that
// never hurt anybody RIGHT?!
if (_handler.guid) {
handler.guid = _handler.guid;
} else {
handler.guid = _handler.guid = $.guid++;
}
return _oldEventAdd.call(this, elem, types, handler, data, selector);
};
var _oldReady = $.fn.ready;
$.fn.ready = function ravenjQueryReadyWrapper(fn) {
return _oldReady.call(this, Raven.wrap(fn));
};
var _oldAjax = $.ajax;
$.ajax = function ravenAjaxWrapper(url, options) {
var keys = ['complete', 'error', 'success'], key;
// Taken from https://github.com/jquery/jquery/blob/eee2eaf1d7a189d99106423a4206c224ebd5b848/src/ajax.js#L311-L318
// If url is an object, simulate pre-1.5 signature
if (typeof url === 'object') {
options = url;
url = undefined;
}
// Force options to be an object
options = options || {};
/*jshint -W084*/
while(key = keys.pop()) {
if ($.isFunction(options[key])) {
options[key] = Raven.wrap(options[key]);
}
}
/*jshint +W084*/
try {
return _oldAjax.call(this, url, options);
} catch (e) {
Raven.captureException(e);
throw e;
}
};
}(window, window.Raven, window.jQuery));

View File

@ -0,0 +1,33 @@
/**
* native plugin
*
* Extends support for global error handling for asynchronous browser
* functions. Adopted from Closure Library's errorhandler.js.
*/
;(function extendToAsynchronousCallbacks(window, Raven) {
"use strict";
var _helper = function _helper(fnName) {
var originalFn = window[fnName];
window[fnName] = function ravenAsyncExtension() {
// Make a copy of the arguments
var args = [].slice.call(arguments);
var originalCallback = args[0];
if (typeof (originalCallback) === 'function') {
args[0] = Raven.wrap(originalCallback);
}
// IE < 9 doesn't support .call/.apply on setInterval/setTimeout, but it
// also supports only two arguments and doesn't care what this is, so we
// can just call the original function directly.
if (originalFn.apply) {
return originalFn.apply(this, args);
} else {
return originalFn(args[0], args[1]);
}
};
};
_helper('setTimeout');
_helper('setInterval');
}(window, window.Raven));

View File

@ -0,0 +1,14 @@
/**
* require.js plugin
*
* Automatically wrap define/require callbacks. (Experimental)
*/
;(function(window, Raven) {
'use strict';
if (typeof define === 'function' && define.amd) {
window.define = Raven.wrap({deep: false}, define);
window.require = Raven.wrap({deep: false}, require);
}
}(window, window.Raven));

View File

@ -0,0 +1,830 @@
'use strict';
// First, check for JSON support
// If there is no JSON, we no-op the core features of Raven
// since JSON is required to encode the payload
var _Raven = window.Raven,
hasJSON = !!(typeof JSON === 'object' && JSON.stringify),
lastCapturedException,
lastEventId,
globalServer,
globalUser,
globalKey,
globalProject,
globalOptions = {
logger: 'javascript',
ignoreErrors: [],
ignoreUrls: [],
whitelistUrls: [],
includePaths: [],
collectWindowErrors: true,
tags: {},
maxMessageLength: 100,
extra: {}
},
authQueryString,
isRavenInstalled = false,
objectPrototype = Object.prototype,
startTime = now();
/*
* The core Raven singleton
*
* @this {Raven}
*/
var Raven = {
VERSION: '<%= pkg.version %>',
debug: true,
/*
* Allow multiple versions of Raven to be installed.
* Strip Raven from the global context and returns the instance.
*
* @return {Raven}
*/
noConflict: function() {
window.Raven = _Raven;
return Raven;
},
/*
* Configure Raven with a DSN and extra options
*
* @param {string} dsn The public Sentry DSN
* @param {object} options Optional set of of global options [optional]
* @return {Raven}
*/
config: function(dsn, options) {
if (globalServer) {
logDebug('error', 'Error: Raven has already been configured');
return Raven;
}
if (!dsn) return Raven;
var uri = parseDSN(dsn),
lastSlash = uri.path.lastIndexOf('/'),
path = uri.path.substr(1, lastSlash);
// merge in options
if (options) {
each(options, function(key, value){
globalOptions[key] = value;
});
}
// "Script error." is hard coded into browsers for errors that it can't read.
// this is the result of a script being pulled in from an external domain and CORS.
globalOptions.ignoreErrors.push(/^Script error\.?$/);
globalOptions.ignoreErrors.push(/^Javascript error: Script error\.? on line 0$/);
// join regexp rules into one big rule
globalOptions.ignoreErrors = joinRegExp(globalOptions.ignoreErrors);
globalOptions.ignoreUrls = globalOptions.ignoreUrls.length ? joinRegExp(globalOptions.ignoreUrls) : false;
globalOptions.whitelistUrls = globalOptions.whitelistUrls.length ? joinRegExp(globalOptions.whitelistUrls) : false;
globalOptions.includePaths = joinRegExp(globalOptions.includePaths);
globalKey = uri.user;
globalProject = uri.path.substr(lastSlash + 1);
// assemble the endpoint from the uri pieces
globalServer = '//' + uri.host +
(uri.port ? ':' + uri.port : '') +
'/' + path + 'api/' + globalProject + '/store/';
if (uri.protocol) {
globalServer = uri.protocol + ':' + globalServer;
}
if (globalOptions.fetchContext) {
TraceKit.remoteFetching = true;
}
if (globalOptions.linesOfContext) {
TraceKit.linesOfContext = globalOptions.linesOfContext;
}
TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
setAuthQueryString();
// return for chaining
return Raven;
},
/*
* Installs a global window.onerror error handler
* to capture and report uncaught exceptions.
* At this point, install() is required to be called due
* to the way TraceKit is set up.
*
* @return {Raven}
*/
install: function() {
if (isSetup() && !isRavenInstalled) {
TraceKit.report.subscribe(handleStackInfo);
isRavenInstalled = true;
}
return Raven;
},
/*
* Wrap code within a context so Raven can capture errors
* reliably across domains that is executed immediately.
*
* @param {object} options A specific set of options for this context [optional]
* @param {function} func The callback to be immediately executed within the context
* @param {array} args An array of arguments to be called with the callback [optional]
*/
context: function(options, func, args) {
if (isFunction(options)) {
args = func || [];
func = options;
options = undefined;
}
return Raven.wrap(options, func).apply(this, args);
},
/*
* Wrap code within a context and returns back a new function to be executed
*
* @param {object} options A specific set of options for this context [optional]
* @param {function} func The function to be wrapped in a new context
* @return {function} The newly wrapped functions with a context
*/
wrap: function(options, func) {
// 1 argument has been passed, and it's not a function
// so just return it
if (isUndefined(func) && !isFunction(options)) {
return options;
}
// options is optional
if (isFunction(options)) {
func = options;
options = undefined;
}
// At this point, we've passed along 2 arguments, and the second one
// is not a function either, so we'll just return the second argument.
if (!isFunction(func)) {
return func;
}
// We don't wanna wrap it twice!
if (func.__raven__) {
return func;
}
function wrapped() {
var args = [], i = arguments.length,
deep = !options || options && options.deep !== false;
// Recursively wrap all of a function's arguments that are
// functions themselves.
while(i--) args[i] = deep ? Raven.wrap(options, arguments[i]) : arguments[i];
try {
/*jshint -W040*/
return func.apply(this, args);
} catch(e) {
Raven.captureException(e, options);
throw e;
}
}
// copy over properties of the old function
for (var property in func) {
if (hasKey(func, property)) {
wrapped[property] = func[property];
}
}
// Signal that this function has been wrapped already
// for both debugging and to prevent it to being wrapped twice
wrapped.__raven__ = true;
wrapped.__inner__ = func;
return wrapped;
},
/*
* Uninstalls the global error handler.
*
* @return {Raven}
*/
uninstall: function() {
TraceKit.report.uninstall();
isRavenInstalled = false;
return Raven;
},
/*
* Manually capture an exception and send it over to Sentry
*
* @param {error} ex An exception to be logged
* @param {object} options A specific set of options for this error [optional]
* @return {Raven}
*/
captureException: function(ex, options) {
// If not an Error is passed through, recall as a message instead
if (!isError(ex)) return Raven.captureMessage(ex, options);
// Store the raw exception object for potential debugging and introspection
lastCapturedException = ex;
// TraceKit.report will re-raise any exception passed to it,
// which means you have to wrap it in try/catch. Instead, we
// can wrap it here and only re-raise if TraceKit.report
// raises an exception different from the one we asked to
// report on.
try {
TraceKit.report(ex, options);
} catch(ex1) {
if(ex !== ex1) {
throw ex1;
}
}
return Raven;
},
/*
* Manually send a message to Sentry
*
* @param {string} msg A plain message to be captured in Sentry
* @param {object} options A specific set of options for this message [optional]
* @return {Raven}
*/
captureMessage: function(msg, options) {
// config() automagically converts ignoreErrors from a list to a RegExp so we need to test for an
// early call; we'll error on the side of logging anything called before configuration since it's
// probably something you should see:
if (!!globalOptions.ignoreErrors.test && globalOptions.ignoreErrors.test(msg)) {
return;
}
// Fire away!
send(
objectMerge({
message: msg + '' // Make sure it's actually a string
}, options)
);
return Raven;
},
/*
* Set/clear a user to be sent along with the payload.
*
* @param {object} user An object representing user data [optional]
* @return {Raven}
*/
setUserContext: function(user) {
globalUser = user;
return Raven;
},
/*
* Set extra attributes to be sent along with the payload.
*
* @param {object} extra An object representing extra data [optional]
* @return {Raven}
*/
setExtraContext: function(extra) {
globalOptions.extra = extra || {};
return Raven;
},
/*
* Set tags to be sent along with the payload.
*
* @param {object} tags An object representing tags [optional]
* @return {Raven}
*/
setTagsContext: function(tags) {
globalOptions.tags = tags || {};
return Raven;
},
/*
* Set release version of application
*
* @param {string} release Typically something like a git SHA to identify version
* @return {Raven}
*/
setReleaseContext: function(release) {
globalOptions.release = release;
return Raven;
},
/*
* Set the dataCallback option
*
* @param {function} callback The callback to run which allows the
* data blob to be mutated before sending
* @return {Raven}
*/
setDataCallback: function(callback) {
globalOptions.dataCallback = callback;
return Raven;
},
/*
* Set the shouldSendCallback option
*
* @param {function} callback The callback to run which allows
* introspecting the blob before sending
* @return {Raven}
*/
setShouldSendCallback: function(callback) {
globalOptions.shouldSendCallback = callback;
return Raven;
},
/*
* Get the latest raw exception that was captured by Raven.
*
* @return {error}
*/
lastException: function() {
return lastCapturedException;
},
/*
* Get the last event id
*
* @return {string}
*/
lastEventId: function() {
return lastEventId;
},
/*
* Determine if Raven is setup and ready to go.
*
* @return {boolean}
*/
isSetup: function() {
return isSetup();
}
};
Raven.setUser = Raven.setUserContext; // To be deprecated
function triggerEvent(eventType, options) {
var event, key;
options = options || {};
eventType = 'raven' + eventType.substr(0,1).toUpperCase() + eventType.substr(1);
if (document.createEvent) {
event = document.createEvent('HTMLEvents');
event.initEvent(eventType, true, true);
} else {
event = document.createEventObject();
event.eventType = eventType;
}
for (key in options) if (hasKey(options, key)) {
event[key] = options[key];
}
if (document.createEvent) {
// IE9 if standards
document.dispatchEvent(event);
} else {
// IE8 regardless of Quirks or Standards
// IE9 if quirks
try {
document.fireEvent('on' + event.eventType.toLowerCase(), event);
} catch(e) {}
}
}
var dsnKeys = 'source protocol user pass host port path'.split(' '),
dsnPattern = /^(?:(\w+):)?\/\/(\w+)(:\w+)?@([\w\.-]+)(?::(\d+))?(\/.*)/;
function RavenConfigError(message) {
this.name = 'RavenConfigError';
this.message = message;
}
RavenConfigError.prototype = new Error();
RavenConfigError.prototype.constructor = RavenConfigError;
/**** Private functions ****/
function parseDSN(str) {
var m = dsnPattern.exec(str),
dsn = {},
i = 7;
try {
while (i--) dsn[dsnKeys[i]] = m[i] || '';
} catch(e) {
throw new RavenConfigError('Invalid DSN: ' + str);
}
if (dsn.pass)
throw new RavenConfigError('Do not specify your private key in the DSN!');
return dsn;
}
function isUndefined(what) {
return what === void 0;
}
function isFunction(what) {
return typeof what === 'function';
}
function isString(what) {
return objectPrototype.toString.call(what) === '[object String]';
}
function isObject(what) {
return typeof what === 'object' && what !== null;
}
function isEmptyObject(what) {
for (var k in what) return false;
return true;
}
// Sorta yanked from https://github.com/joyent/node/blob/aa3b4b4/lib/util.js#L560
// with some tiny modifications
function isError(what) {
return isObject(what) &&
objectPrototype.toString.call(what) === '[object Error]' ||
what instanceof Error;
}
/**
* hasKey, a better form of hasOwnProperty
* Example: hasKey(MainHostObject, property) === true/false
*
* @param {Object} host object to check property
* @param {string} key to check
*/
function hasKey(object, key) {
return objectPrototype.hasOwnProperty.call(object, key);
}
function each(obj, callback) {
var i, j;
if (isUndefined(obj.length)) {
for (i in obj) {
if (hasKey(obj, i)) {
callback.call(null, i, obj[i]);
}
}
} else {
j = obj.length;
if (j) {
for (i = 0; i < j; i++) {
callback.call(null, i, obj[i]);
}
}
}
}
function setAuthQueryString() {
authQueryString =
'?sentry_version=4' +
'&sentry_client=raven-js/' + Raven.VERSION +
'&sentry_key=' + globalKey;
}
function handleStackInfo(stackInfo, options) {
var frames = [];
if (stackInfo.stack && stackInfo.stack.length) {
each(stackInfo.stack, function(i, stack) {
var frame = normalizeFrame(stack);
if (frame) {
frames.push(frame);
}
});
}
triggerEvent('handle', {
stackInfo: stackInfo,
options: options
});
processException(
stackInfo.name,
stackInfo.message,
stackInfo.url,
stackInfo.lineno,
frames,
options
);
}
function normalizeFrame(frame) {
if (!frame.url) return;
// normalize the frames data
var normalized = {
filename: frame.url,
lineno: frame.line,
colno: frame.column,
'function': frame.func || '?'
}, context = extractContextFromFrame(frame), i;
if (context) {
var keys = ['pre_context', 'context_line', 'post_context'];
i = 3;
while (i--) normalized[keys[i]] = context[i];
}
normalized.in_app = !( // determine if an exception came from outside of our app
// first we check the global includePaths list.
!globalOptions.includePaths.test(normalized.filename) ||
// Now we check for fun, if the function name is Raven or TraceKit
/(Raven|TraceKit)\./.test(normalized['function']) ||
// finally, we do a last ditch effort and check for raven.min.js
/raven\.(min\.)?js$/.test(normalized.filename)
);
return normalized;
}
function extractContextFromFrame(frame) {
// immediately check if we should even attempt to parse a context
if (!frame.context || !globalOptions.fetchContext) return;
var context = frame.context,
pivot = ~~(context.length / 2),
i = context.length, isMinified = false;
while (i--) {
// We're making a guess to see if the source is minified or not.
// To do that, we make the assumption if *any* of the lines passed
// in are greater than 300 characters long, we bail.
// Sentry will see that there isn't a context
if (context[i].length > 300) {
isMinified = true;
break;
}
}
if (isMinified) {
// The source is minified and we don't know which column. Fuck it.
if (isUndefined(frame.column)) return;
// If the source is minified and has a frame column
// we take a chunk of the offending line to hopefully shed some light
return [
[], // no pre_context
context[pivot].substr(frame.column, 50), // grab 50 characters, starting at the offending column
[] // no post_context
];
}
return [
context.slice(0, pivot), // pre_context
context[pivot], // context_line
context.slice(pivot + 1) // post_context
];
}
function processException(type, message, fileurl, lineno, frames, options) {
var stacktrace, label, i;
// In some instances message is not actually a string, no idea why,
// so we want to always coerce it to one.
message += '';
// Sometimes an exception is getting logged in Sentry as
// <no message value>
// This can only mean that the message was falsey since this value
// is hardcoded into Sentry itself.
// At this point, if the message is falsey, we bail since it's useless
if (type === 'Error' && !message) return;
if (globalOptions.ignoreErrors.test(message)) return;
if (frames && frames.length) {
fileurl = frames[0].filename || fileurl;
// Sentry expects frames oldest to newest
// and JS sends them as newest to oldest
frames.reverse();
stacktrace = {frames: frames};
} else if (fileurl) {
stacktrace = {
frames: [{
filename: fileurl,
lineno: lineno,
in_app: true
}]
};
}
// Truncate the message to a max of characters
message = truncate(message, globalOptions.maxMessageLength);
if (globalOptions.ignoreUrls && globalOptions.ignoreUrls.test(fileurl)) return;
if (globalOptions.whitelistUrls && !globalOptions.whitelistUrls.test(fileurl)) return;
label = lineno ? message + ' at ' + lineno : message;
// Fire away!
send(
objectMerge({
// sentry.interfaces.Exception
exception: {
type: type,
value: message
},
// sentry.interfaces.Stacktrace
stacktrace: stacktrace,
culprit: fileurl,
message: label
}, options)
);
}
function objectMerge(obj1, obj2) {
if (!obj2) {
return obj1;
}
each(obj2, function(key, value){
obj1[key] = value;
});
return obj1;
}
function truncate(str, max) {
return str.length <= max ? str : str.substr(0, max) + '\u2026';
}
function now() {
return +new Date();
}
function getHttpData() {
var http = {
url: document.location.href,
headers: {
'User-Agent': navigator.userAgent
}
};
if (document.referrer) {
http.headers.Referer = document.referrer;
}
return http;
}
function send(data) {
if (!isSetup()) return;
data = objectMerge({
project: globalProject,
logger: globalOptions.logger,
platform: 'javascript',
// sentry.interfaces.Http
request: getHttpData()
}, data);
// Merge in the tags and extra separately since objectMerge doesn't handle a deep merge
data.tags = objectMerge(objectMerge({}, globalOptions.tags), data.tags);
data.extra = objectMerge(objectMerge({}, globalOptions.extra), data.extra);
// Send along our own collected metadata with extra
data.extra = objectMerge({
'session:duration': now() - startTime
}, data.extra);
// If there are no tags/extra, strip the key from the payload alltogther.
if (isEmptyObject(data.tags)) delete data.tags;
if (globalUser) {
// sentry.interfaces.User
data.user = globalUser;
}
// Include the release iff it's defined in globalOptions
if (globalOptions.release) data.release = globalOptions.release;
if (isFunction(globalOptions.dataCallback)) {
data = globalOptions.dataCallback(data) || data;
}
// Why??????????
if (!data || isEmptyObject(data)) {
return;
}
// Check if the request should be filtered or not
if (isFunction(globalOptions.shouldSendCallback) && !globalOptions.shouldSendCallback(data)) {
return;
}
// Send along an event_id if not explicitly passed.
// This event_id can be used to reference the error within Sentry itself.
// Set lastEventId after we know the error should actually be sent
lastEventId = data.event_id || (data.event_id = uuid4());
makeRequest(data);
}
function makeRequest(data) {
var img = newImage(),
src = globalServer + authQueryString + '&sentry_data=' + encodeURIComponent(JSON.stringify(data));
img.crossOrigin = 'anonymous';
img.onload = function success() {
triggerEvent('success', {
data: data,
src: src
});
};
img.onerror = img.onabort = function failure() {
triggerEvent('failure', {
data: data,
src: src
});
};
img.src = src;
}
// Note: this is shitty, but I can't figure out how to get
// sinon to stub document.createElement without breaking everything
// so this wrapper is just so I can stub it for tests.
function newImage() {
return document.createElement('img');
}
function isSetup() {
if (!hasJSON) return false; // needs JSON support
if (!globalServer) {
logDebug('error', 'Error: Raven has not been configured.');
return false;
}
return true;
}
function joinRegExp(patterns) {
// Combine an array of regular expressions and strings into one large regexp
// Be mad.
var sources = [],
i = 0, len = patterns.length,
pattern;
for (; i < len; i++) {
pattern = patterns[i];
if (isString(pattern)) {
// If it's a string, we need to escape it
// Taken from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
sources.push(pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"));
} else if (pattern && pattern.source) {
// If it's a regexp already, we want to extract the source
sources.push(pattern.source);
}
// Intentionally skip other cases
}
return new RegExp(sources.join('|'), 'i');
}
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
function uuid4() {
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0,
v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}
function logDebug(level, message) {
if (window.console && console[level] && Raven.debug) {
console[level](message);
}
}
function afterLoad() {
// Attempt to initialize Raven on load
var RavenConfig = window.RavenConfig;
if (RavenConfig) {
Raven.config(RavenConfig.dsn, RavenConfig.config).install();
}
}
afterLoad();

View File

@ -0,0 +1,11 @@
/*! Raven.js <%= pkg.release %> (<%= gitinfo.local.branch.current.shortSHA %>) | github.com/getsentry/raven-js */
/*
* Includes TraceKit
* https://github.com/getsentry/TraceKit
*
* Copyright <%= grunt.template.today('yyyy') %> Matt Robenolt and other contributors
* Released under the BSD license
* https://github.com/getsentry/raven-js/blob/master/LICENSE
*
*/

View File

@ -0,0 +1,19 @@
// Expose Raven to the world
if (typeof define === 'function' && define.amd) {
// AMD
window.Raven = Raven;
define('raven', [], function() {
return Raven;
});
} else if (typeof module === 'object') {
// browserify
module.exports = Raven;
} else if (typeof exports === 'object') {
// CommonJS
exports = Raven;
} else {
// Everything else
window.Raven = Raven;
}
})(typeof window !== 'undefined' ? window : this);

View File

@ -0,0 +1,2 @@
;(function(window, undefined){
'use strict';

View File

@ -0,0 +1,62 @@
<!doctype html>
<html>
<head>
<title>Raven.js Test Suite</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="../node_modules/grunt-mocha/node_modules/mocha/mocha.css" />
</head>
<body>
<div id="mocha"></div>
<!-- Mocha -->
<script src="../node_modules/grunt-mocha/node_modules/mocha/mocha.js"></script>
<script src="../node_modules/chai/chai.js"></script>
<script>
mocha.ui('bdd');
mocha.reporter('html');
var assert = chai.assert
</script>
<!-- Mocking -->
<script src="../node_modules/sinon/pkg/sinon.js"></script>
<script>
beforeEach(function() {
this.sinon = sinon.sandbox.create();
});
afterEach(function() {
this.sinon.restore();
});
</script>
<!-- Raven -->
<script src="../vendor/TraceKit/tracekit.js"></script>
<script src="../src/raven.js"></script>
<!-- Tests -->
<script src="raven.test.js"></script>
<script>
if (!window.PHANTOMJS) {
(function(runner){
var failed = [];
runner.on('fail', function(test, err){
failed.push({
title: test.title,
fullTitle: test.fullTitle(),
error: {
message: err.message,
stack: err.stack
}
});
});
runner.on('end', function(){
runner.stats.failed = failed;
global.mochaResults = runner.stats;
});
})(mocha.run());
}
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1244,6 +1244,16 @@ function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs
print '<script type="text/javascript" src="'.$pathckeditor.$jsckeditor.($ext?'?'.$ext:'').'"></script>'."\n";
}
// Raven.js for client-side Sentry logging support
if (array_key_exists('mod_syslog_sentry', $conf->loghandlers)) {
print '<!-- Includes Raven.js for Sentry -->' . "\n";
print '<script src="' . DOL_URL_ROOT . '/includes/raven-js/dist/raven.min.js"></script>' . "\n";
print '<script src="' . DOL_URL_ROOT . '/includes/raven-js/plugins/native.js"></script>' . "\n";
if (! defined('DISABLE_JQUERY')) {
print '<script src="' . DOL_URL_ROOT . '/includes/raven-js/plugins/jquery.js"></script>' . "\n";
}
}
// Global js function
print '<!-- Includes JS of Dolibarr -->'."\n";
print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/lib_head.js'.($ext?'?'.$ext:'').'"></script>'."\n";
@ -1321,7 +1331,7 @@ function top_menu($head, $title='', $target='', $disablejs=0, $disablehead=0, $a
// For backward compatibility with old modules
if (empty($conf->headerdone)) top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
print '<body id="mainbody">';
print '<body id="mainbody">' . "\n";
if ($conf->use_javascript_ajax)
{
@ -1376,15 +1386,29 @@ function top_menu($head, $title='', $target='', $disablejs=0, $disablehead=0, $a
paneSelector: "#mainContent"
}
}
</script>';
}
</script>' . "\n";
}
// Wrapper to show tooltips
print "\n".'<script type="text/javascript">
jQuery(document).ready(function () {
jQuery(".classfortooltip").tipTip({maxWidth: "'.dol_size(600,'width').'px", edgeOffset: 10, delay: 50, fadeIn: 50, fadeOut: 50});
});
</script>';
// Wrapper to show tooltips
print '<script type="text/javascript">
jQuery(document).ready(function () {
jQuery(".classfortooltip").tipTip({maxWidth: "'.dol_size(600,'width').'px", edgeOffset: 10, delay: 50, fadeIn: 50, fadeOut: 50});
});
</script>' . "\n";
// Raven.js for client-side Sentry logging support
if (array_key_exists('mod_syslog_sentry', $conf->loghandlers) && ! empty($conf->global->SYSLOG_SENTRY_DSN)) {
// Filter out secret key
$dsn = parse_url($conf->global->SYSLOG_SENTRY_DSN);
$public_dsn = $dsn['scheme'] . '://' . $dsn['user'] .'@' . $dsn['host'] . $dsn['path'];
print '<script type="text/javascript">' . "\n";
print "Raven.config('" . $public_dsn . "').install()\n";
print "Raven.setUserContext({username: '" . $user->login . "'})\n";
print "Raven.setTagsContext({version: '" . DOL_VERSION . "'})\n";
print "</script>\n";
}
}
/*