diff --git a/docs/config/index.rst b/docs/config/index.rst index fe197f1fd5f3..5840b727b822 100644 --- a/docs/config/index.rst +++ b/docs/config/index.rst @@ -143,6 +143,22 @@ maxMessageLength By default, raven truncates messages to a max length of 100 characters. You can customize the max length with this parameter. +transportMechanism +------------------ + +A function that accepts the data, and the endpoint details that allow you to +customise when and how errors are sent over the network. + +.. code-block:: javascript + + { + transportMechanism: function(data, server, authQueryString) { + var endpoint = server + authQueryString + '&sentry_data=' + encodeURIComponent(JSON.stringify(data)); + yourFetchMethod(endpoint); + } + } + + Putting it all together ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/raven.js b/src/raven.js index 7fd01f73169c..b695a4cf4865 100644 --- a/src/raven.js +++ b/src/raven.js @@ -20,6 +20,7 @@ var _Raven = window.Raven, collectWindowErrors: true, tags: {}, maxMessageLength: 100, + transportMechanism: makeRequest, extra: {} }, authQueryString, @@ -67,6 +68,8 @@ var Raven = { lastSlash = uri.path.lastIndexOf('/'), path = uri.path.substr(1, lastSlash); + globalOptions.transportMechanism = makeRequest; + // merge in options if (options) { each(options, function(key, value){ @@ -351,6 +354,10 @@ var Raven = { */ isSetup: function() { return isSetup(); + }, + + setTransportMethod: function(transport) { + globalOptions.transportMechanism = transport; } }; @@ -712,13 +719,13 @@ function send(data) { // Set lastEventId after we know the error should actually be sent lastEventId = data.event_id || (data.event_id = uuid4()); - makeRequest(data); + globalOptions.transportMechanism(data, globalServer, authQueryString); } -function makeRequest(data) { +function makeRequest(data, server, authQueryString) { var img = newImage(), - src = globalServer + authQueryString + '&sentry_data=' + encodeURIComponent(JSON.stringify(data)); + src = server + authQueryString + '&sentry_data=' + encodeURIComponent(JSON.stringify(data)); img.crossOrigin = 'anonymous'; img.onload = function success() { diff --git a/test/raven.test.js b/test/raven.test.js index a40821ed7af1..7d770942e03d 100644 --- a/test/raven.test.js +++ b/test/raven.test.js @@ -819,19 +819,20 @@ describe('globals', function() { it('should build a good data payload', function() { this.sinon.stub(window, 'isSetup').returns(true); - this.sinon.stub(window, 'makeRequest'); this.sinon.stub(window, 'getHttpData').returns({ url: 'http://localhost/?a=b', headers: {'User-Agent': 'lolbrowser'} }); + var transportMechanism = this.sinon.stub(); globalProject = '2'; globalOptions = { - logger: 'javascript' + logger: 'javascript', + transportMechanism: transportMechanism }; send({foo: 'bar'}); - assert.deepEqual(window.makeRequest.lastCall.args[0], { + assert.deepEqual(transportMechanism.lastCall.args[0], { project: '2', logger: 'javascript', platform: 'javascript', @@ -849,21 +850,22 @@ describe('globals', function() { it('should build a good data payload with a User', function() { this.sinon.stub(window, 'isSetup').returns(true); - this.sinon.stub(window, 'makeRequest'); this.sinon.stub(window, 'getHttpData').returns({ url: 'http://localhost/?a=b', headers: {'User-Agent': 'lolbrowser'} }); + var transportMechanism = this.sinon.stub(); globalProject = '2'; globalOptions = { - logger: 'javascript' + logger: 'javascript', + transportMechanism: transportMechanism }; globalUser = {name: 'Matt'}; send({foo: 'bar'}); - assert.deepEqual(window.makeRequest.lastCall.args, [{ + assert.deepEqual(transportMechanism.lastCall.args[0], { project: '2', logger: 'javascript', platform: 'javascript', @@ -879,7 +881,7 @@ describe('globals', function() { }, foo: 'bar', extra: {'session:duration': 100} - }]); + }); }); it('should merge in global tags', function() { @@ -890,15 +892,18 @@ describe('globals', function() { headers: {'User-Agent': 'lolbrowser'} }); + var transportMechanism = this.sinon.stub(); + globalProject = '2'; globalOptions = { logger: 'javascript', - tags: {tag1: 'value1'} + tags: {tag1: 'value1'}, + transportMechanism: transportMechanism }; send({tags: {tag2: 'value2'}}); - assert.deepEqual(window.makeRequest.lastCall.args, [{ + assert.deepEqual(transportMechanism.lastCall.args[0], { project: '2', logger: 'javascript', platform: 'javascript', @@ -911,30 +916,33 @@ describe('globals', function() { event_id: 'abc123', tags: {tag1: 'value1', tag2: 'value2'}, extra: {'session:duration': 100} - }]); + }); assert.deepEqual(globalOptions, { logger: 'javascript', - tags: {tag1: 'value1'} + tags: {tag1: 'value1'}, + transportMechanism: transportMechanism }); }); it('should merge in global extra', function() { this.sinon.stub(window, 'isSetup').returns(true); - this.sinon.stub(window, 'makeRequest'); this.sinon.stub(window, 'getHttpData').returns({ url: 'http://localhost/?a=b', headers: {'User-Agent': 'lolbrowser'} }); + var transportMechanism = this.sinon.stub(); + globalProject = '2'; globalOptions = { logger: 'javascript', - extra: {key1: 'value1'} + extra: {key1: 'value1'}, + transportMechanism: transportMechanism }; send({extra: {key2: 'value2'}}); - assert.deepEqual(window.makeRequest.lastCall.args, [{ + assert.deepEqual(transportMechanism.lastCall.args[0], { project: '2', logger: 'javascript', platform: 'javascript', @@ -946,50 +954,55 @@ describe('globals', function() { }, event_id: 'abc123', extra: {key1: 'value1', key2: 'value2', 'session:duration': 100} - }]); + }); assert.deepEqual(globalOptions, { logger: 'javascript', - extra: {key1: 'value1'} + extra: {key1: 'value1'}, + transportMechanism: transportMechanism }); }); it('should let dataCallback override everything', function() { this.sinon.stub(window, 'isSetup').returns(true); - this.sinon.stub(window, 'makeRequest'); + var transportMechanism = this.sinon.stub(); + globalOptions = { projectId: 2, logger: 'javascript', dataCallback: function() { return {lol: 'ibrokeit'}; - } + }, + transportMechanism: transportMechanism }; globalUser = {name: 'Matt'}; send({foo: 'bar'}); - assert.deepEqual(window.makeRequest.lastCall.args, [{ + assert.deepEqual(transportMechanism.lastCall.args[0], { lol: 'ibrokeit', event_id: 'abc123', - }]); + }); }); it('should strip empty tags', function() { this.sinon.stub(window, 'isSetup').returns(true); - this.sinon.stub(window, 'makeRequest'); this.sinon.stub(window, 'getHttpData').returns({ url: 'http://localhost/?a=b', headers: {'User-Agent': 'lolbrowser'} }); + var transportMechanism = this.sinon.stub(); + globalOptions = { projectId: 2, logger: 'javascript', - tags: {} + tags: {}, + transportMechanism: transportMechanism }; send({foo: 'bar', tags: {}, extra: {}}); - assert.deepEqual(window.makeRequest.lastCall.args[0], { + assert.deepEqual(transportMechanism.lastCall.args[0], { project: '2', logger: 'javascript', platform: 'javascript', @@ -1007,20 +1020,22 @@ describe('globals', function() { it('should attach release if available', function() { this.sinon.stub(window, 'isSetup').returns(true); - this.sinon.stub(window, 'makeRequest'); this.sinon.stub(window, 'getHttpData').returns({ url: 'http://localhost/?a=b', headers: {'User-Agent': 'lolbrowser'} }); + var makeRequestStub = this.sinon.stub(); + globalOptions = { projectId: 2, logger: 'javascript', release: 'abc123', + transportMechanism: makeRequestStub }; send({foo: 'bar'}); - assert.deepEqual(window.makeRequest.lastCall.args[0], { + assert.deepEqual(makeRequestStub.lastCall.args[0], { project: '2', release: 'abc123', logger: 'javascript', @@ -1040,12 +1055,12 @@ describe('globals', function() { describe('makeRequest', function() { it('should load an Image', function() { - authQueryString = '?lol'; - globalServer = 'http://localhost/'; + var authQueryString = '?lol'; + var globalServer = 'http://localhost/'; var imageCache = []; this.sinon.stub(window, 'newImage', function(){ var img = {}; imageCache.push(img); return img; }); - makeRequest({foo: 'bar'}); + makeRequest({foo: 'bar'}, globalServer, authQueryString); assert.equal(imageCache.length, 1); assert.equal(imageCache[0].src, 'http://localhost/?lol&sentry_data=%7B%22foo%22%3A%22bar%22%7D'); }); @@ -1074,7 +1089,8 @@ describe('globals', function() { }); it('should work as advertised #integration', function() { - this.sinon.stub(window, 'makeRequest'); + globalOptions.transportMechanism = this.sinon.stub(); + var stackInfo = { name: 'Error', message: 'crap', @@ -1107,7 +1123,7 @@ describe('globals', function() { }; handleStackInfo(stackInfo, {foo: 'bar'}); - assert.isTrue(window.makeRequest.calledOnce); + assert.isTrue(globalOptions.transportMechanism.calledOnce); /* This is commented out because chai is broken. assert.deepEqual(window.makeRequest.lastCall.args, [{