diff --git a/src/console.js b/src/console.js index 644ed1d804ea..939698c9c3a0 100644 --- a/src/console.js +++ b/src/console.js @@ -1,3 +1,5 @@ +var utils = require('./utils'); + var wrapMethod = function(console, level, callback) { var originalConsoleLevel = console[level]; var originalConsole = console; @@ -11,13 +13,14 @@ var wrapMethod = function(console, level, callback) { console[level] = function() { var args = [].slice.call(arguments); - var msg = '' + args.join(' '); + var msg = utils.safeJoin(args, ' '); var data = {level: sentryLevel, logger: 'console', extra: {arguments: args}}; if (level === 'assert') { if (args[0] === false) { // Default browsers message - msg = 'Assertion failed: ' + (args.slice(1).join(' ') || 'console.assert'); + msg = + 'Assertion failed: ' + (utils.safeJoin(args.slice(1), ' ') || 'console.assert'); data.extra.arguments = args.slice(1); callback && callback(msg, data); } diff --git a/src/utils.js b/src/utils.js index 882cc044b6ad..619068332bc7 100644 --- a/src/utils.js +++ b/src/utils.js @@ -397,6 +397,28 @@ function fill(obj, name, replacement, track) { } } +/** + * Join values in array + * @param input array of values to be joined together + * @param delimiter string to be placed in-between values + * @returns {string} + */ +function safeJoin(input, delimiter) { + if (!isArray(input)) return ''; + + var output = []; + + for (var i = 0; i < input.length; i++) { + try { + output.push(String(input[i])); + } catch (e) { + output.push('[value cannot be serialized]'); + } + } + + return output.join(delimiter); +} + module.exports = { isObject: isObject, isError: isError, @@ -423,5 +445,6 @@ module.exports = { isSameException: isSameException, isSameStacktrace: isSameStacktrace, parseUrl: parseUrl, - fill: fill + fill: fill, + safeJoin: safeJoin }; diff --git a/test/utils.test.js b/test/utils.test.js index 2cab75b730d1..fd63389efe78 100644 --- a/test/utils.test.js +++ b/test/utils.test.js @@ -23,6 +23,7 @@ var urlencode = utils.urlencode; var htmlTreeAsString = utils.htmlTreeAsString; var htmlElementAsString = utils.htmlElementAsString; var parseUrl = utils.parseUrl; +var safeJoin = utils.safeJoin; describe('utils', function() { describe('isUndefined', function() { @@ -421,4 +422,35 @@ describe('utils', function() { ); }); }); + + describe('safeJoin', function() { + it('should return empty string if not-array input provided', function() { + assert.equal(safeJoin('asd'), ''); + assert.equal(safeJoin(undefined), ''); + assert.equal(safeJoin({foo: 123}), ''); + }); + + it('should default to comma, as regular join() call', function() { + assert.equal(safeJoin(['a', 'b', 'c']), 'a,b,c'); + }); + + it('should stringify complex values, as regular String() call', function() { + assert.equal( + safeJoin([1, 'a', {foo: 42}, [1, 2, 3]], ' '), + '1 a [object Object] 1,2,3' + ); + }); + + it('should still work with unserializeable values', function() { + function Foo() {} + Foo.prototype.toString = function() { + throw Error('whoops!'); + }; + + assert.equal( + safeJoin([new Foo(), 'abc', new Foo(), 42], ' X '), + '[value cannot be serialized] X abc X [value cannot be serialized] X 42' + ); + }); + }); });