From 1be9e927db64ebe92c4e971cc9a120b3b03bcf80 Mon Sep 17 00:00:00 2001 From: rhart Date: Thu, 19 May 2016 09:56:53 +0100 Subject: [PATCH 1/3] Add error message to report --- spec/stacktrace-spec.js | 8 +++++--- stacktrace.js | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/spec/stacktrace-spec.js b/spec/stacktrace-spec.js index 5850d9d..8b60d2e 100755 --- a/spec/stacktrace-spec.js +++ b/spec/stacktrace-spec.js @@ -194,15 +194,16 @@ describe('StackTrace', function() { it('sends POST request to given URL', function(done) { var url = 'http://domain.ext/endpoint'; + var errorMsg = 'BOOM'; var stackframes = [new StackFrame('fn', undefined, 'file.js', 32, 1)]; - StackTrace.report(stackframes, url).then(callback, done.fail)['catch'](done.fail); + StackTrace.report(errorMsg, stackframes, url).then(callback, done.fail)['catch'](done.fail); var postRequest = jasmine.Ajax.requests.mostRecent(); postRequest.respondWith({status: 201, contentType: 'text/plain', responseText: 'OK'}); function callback() { - expect(postRequest.data()).toEqual({stack: stackframes}); + expect(postRequest.data()).toEqual({message: errorMsg, stack: stackframes}); expect(postRequest.method).toBe('post'); expect(postRequest.url).toBe(url); done(); @@ -211,10 +212,11 @@ describe('StackTrace', function() { it('rejects if POST request fails', function(done) { var url = 'http://domain.ext/endpoint'; + var errorMsg = 'BOOM'; var stackframes = [new StackFrame('fn', undefined, 'file.js', 32, 1)]; jasmine.Ajax.stubRequest(url).andError(); - StackTrace.report(stackframes, url).then(done.fail, done)['catch'](done); + StackTrace.report(errorMsg, stackframes, url).then(done.fail, done)['catch'](done); }); }); }); diff --git a/stacktrace.js b/stacktrace.js index d7be057..65d0f7b 100644 --- a/stacktrace.js +++ b/stacktrace.js @@ -163,12 +163,12 @@ }, /** - * Given an Array of StackFrames, serialize and POST to given URL. + * Given an error message and Array of StackFrames, serialize and POST to given URL. * * @param {Array} stackframes * @param {String} url */ - report: function StackTrace$$report(stackframes, url) { + report: function StackTrace$$report(errorMsg, stackframes, url) { return new Promise(function(resolve, reject) { var req = new XMLHttpRequest(); req.onerror = reject; @@ -183,7 +183,7 @@ }; req.open('post', url); req.setRequestHeader('Content-Type', 'application/json'); - req.send(JSON.stringify({stack: stackframes})); + req.send(JSON.stringify({message: errorMsg, stack: stackframes})); }); } }; From f812877bed5b4bd89bca19a190bd03b41d24cfcc Mon Sep 17 00:00:00 2001 From: rhart Date: Thu, 19 May 2016 10:06:29 +0100 Subject: [PATCH 2/3] Update docs --- README.md | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index c15ed76..f19ffe1 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ Generate, parse and enhance JavaScript stack traces in all browsers Debug and profile your JavaScript with a [stack trace](http://en.wikipedia.org/wiki/Stack_trace) of function calls leading to an error (or any condition you specify). -stacktrace.js uses browsers' `Error.stack` mechanism to generate stack traces, parses them, enhances them with -[source maps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/) and uses +stacktrace.js uses browsers' `Error.stack` mechanism to generate stack traces, parses them, enhances them with +[source maps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/) and uses [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) to return an Array of [StackFrames](https://github.com/stacktracejs/stackframe). @@ -16,10 +16,10 @@ to return an Array of [StackFrames](https://github.com/stacktracejs/stackframe). #### Get a stack trace from current location ```js var callback = function(stackframes) { - var stringifiedStack = stackframes.map(function(sf) { - return sf.toString(); - }).join('\n'); - console.log(stringifiedStack); + var stringifiedStack = stackframes.map(function(sf) { + return sf.toString(); + }).join('\n'); + console.log(stringifiedStack); }; var errback = function(err) { console.log(err.message); }; @@ -40,7 +40,7 @@ window.onerror = function(msg, file, line, col, error) { #### Get stack trace from an Error ```js -var error = new Error('BOOM!'); +var error = new Error('BOOM!'); StackTrace.fromError(error).then(callback).catch(errback) => Promise(Array[StackFrame], Error) @@ -81,21 +81,21 @@ http://cdnjs.com/libraries/stacktrace.js Generate a backtrace from invocation point, then parse and enhance it. **(Optional) options: Object** -* *filter: Function([StackFrame](https://github.com/stacktracejs/stackframe) => Boolean)* - Only include stack entries matching for which `filter` returns `true` +* *filter: Function([StackFrame](https://github.com/stacktracejs/stackframe) => Boolean)* - Only include stack entries matching for which `filter` returns `true` * *sourceCache: Object (String URL => String Source)* - Pre-populate source cache to avoid network requests * *offline: Boolean (default: false)* - Set to `true` to prevent all network requests - + #### `StackTrace.fromError(error, /*optional*/ options)` => [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)(Array[[StackFrame](https://github.com/stacktracejs/stackframe)]) Given an Error object, use [error-stack-parser](https://github.com/stacktracejs/error-stack-parser) to parse it and enhance location information with [stacktrace-gps](https://github.com/stacktracejs/stacktrace-gps). - + **error: Error** **(Optional) options: Object** * *filter: Function([StackFrame](https://github.com/stacktracejs/stackframe) => Boolean)* - Only include stack entries matching for which `filter` returns `true` * *sourceCache: Object (String URL => String Source)* - Pre-populate source cache to avoid network requests * *offline: Boolean (default: false)* - Set to `true` to prevent all network requests - + #### `StackTrace.generateArtificially(/*optional*/ options)` => [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)(Array[[StackFrame](https://github.com/stacktracejs/stackframe)]) Use [stack-generator](https://github.com/stacktracejs/stack-generator) to generate a backtrace by walking the `arguments.callee.caller` chain. @@ -103,26 +103,27 @@ Use [stack-generator](https://github.com/stacktracejs/stack-generator) to genera * *filter: Function([StackFrame](https://github.com/stacktracejs/stackframe) => Boolean)* - Only include stack entries matching for which `filter` returns `true` * *sourceCache: Object (String URL => String Source)* - Pre-populate source cache to avoid network requests * *offline: Boolean (default: false)* - Set to `true` to prevent all network requests - + #### `StackTrace.instrument(fn, callback, /*optional*/ errback)` => Function * Given a function, wrap it such that invocations trigger a callback that is called with a stack trace. * **fn: Function** - to wrap, call callback on invocation and call-through * **callback: Function** - to call with stack trace (generated by `StackTrace.get()`) when fn is called -* **(Optional) errback: Function** - to call with Error object if there was a problem getting a stack trace. +* **(Optional) errback: Function** - to call with Error object if there was a problem getting a stack trace. Fails silently (though `fn` is still called) if a stack trace couldn't be generated. - + #### `StackTrace.deinstrument(fn)` => Function Given a function that has been instrumented, revert the function to it's original (non-instrumented) state. * **fn: Function** - Instrumented Function -#### `StackTrace.report(stackframes, url)` => [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)(String) -Given an Array of StackFrames, serialize and POST to given URL. Promise is resolved with response text from POST request. +#### `StackTrace.report(message, stackframes, url)` => [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)(String) +Given an an error message and Array of StackFrames, serialize and POST to given URL. Promise is resolved with response text from POST request. Example JSON POST data: ``` { + message: 'BOOM', stack: [ {functionName: 'fn', fileName: 'file.js', lineNumber: 32, columnNumber: 1}, {functionName: 'fn2', fileName: 'file.js', lineNumber: 543, columnNumber: 32}, @@ -131,6 +132,7 @@ Example JSON POST data: } ``` +* **message: String** - The error message * **stackframes: Array([StackFrame](https://github.com/stacktracejs/stackframe))** - Previously wrapped Function * **url: String** - URL to POST stack JSON to @@ -140,8 +142,8 @@ Example JSON POST data: > **HEADS UP**: You won't get the benefit of [source maps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/) in IE9- or other very old browsers. -## Using node.js/io.js only? -I recommend the [stack-trace node package](https://www.npmjs.com/package/stack-trace) specifically built for node. +## Using node.js/io.js only? +I recommend the [stack-trace node package](https://www.npmjs.com/package/stack-trace) specifically built for node. It has a very similar API and also supports source maps. ## Contributing From 6d2b6cb4b4f1a59bf44a11ffeb40aef0c8dd972c Mon Sep 17 00:00:00 2001 From: rhart Date: Wed, 25 May 2016 18:46:06 +0100 Subject: [PATCH 3/3] Make error message optional when reporting --- README.md | 2 +- spec/stacktrace-spec.js | 24 ++++++++++++++++++++---- stacktrace.js | 11 +++++++++-- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f19ffe1..680e3be 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ Given a function that has been instrumented, revert the function to it's origina * **fn: Function** - Instrumented Function -#### `StackTrace.report(message, stackframes, url)` => [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)(String) +#### `StackTrace.report(stackframes, url, message)` => [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)(String) Given an an error message and Array of StackFrames, serialize and POST to given URL. Promise is resolved with response text from POST request. Example JSON POST data: diff --git a/spec/stacktrace-spec.js b/spec/stacktrace-spec.js index 8b60d2e..942f9c1 100755 --- a/spec/stacktrace-spec.js +++ b/spec/stacktrace-spec.js @@ -192,12 +192,12 @@ describe('StackTrace', function() { jasmine.Ajax.uninstall(); }); - it('sends POST request to given URL', function(done) { + it('sends POST request to given URL with a message', function(done) { var url = 'http://domain.ext/endpoint'; var errorMsg = 'BOOM'; var stackframes = [new StackFrame('fn', undefined, 'file.js', 32, 1)]; - StackTrace.report(errorMsg, stackframes, url).then(callback, done.fail)['catch'](done.fail); + StackTrace.report(stackframes, url, errorMsg).then(callback, done.fail)['catch'](done.fail); var postRequest = jasmine.Ajax.requests.mostRecent(); postRequest.respondWith({status: 201, contentType: 'text/plain', responseText: 'OK'}); @@ -210,13 +210,29 @@ describe('StackTrace', function() { } }); + it('sends POST request to given URL without a message', function(done) { + var url = 'http://domain.ext/endpoint'; + var stackframes = [new StackFrame('fn', undefined, 'file.js', 32, 1)]; + + StackTrace.report(stackframes, url).then(callback, done.fail)['catch'](done.fail); + + var postRequest = jasmine.Ajax.requests.mostRecent(); + postRequest.respondWith({status: 201, contentType: 'text/plain', responseText: 'OK'}); + + function callback() { + expect(postRequest.data()).toEqual({stack: stackframes}); + expect(postRequest.method).toBe('post'); + expect(postRequest.url).toBe(url); + done(); + } + }); + it('rejects if POST request fails', function(done) { var url = 'http://domain.ext/endpoint'; - var errorMsg = 'BOOM'; var stackframes = [new StackFrame('fn', undefined, 'file.js', 32, 1)]; jasmine.Ajax.stubRequest(url).andError(); - StackTrace.report(errorMsg, stackframes, url).then(done.fail, done)['catch'](done); + StackTrace.report(stackframes, url).then(done.fail, done)['catch'](done); }); }); }); diff --git a/stacktrace.js b/stacktrace.js index 65d0f7b..5b06ee9 100644 --- a/stacktrace.js +++ b/stacktrace.js @@ -167,8 +167,9 @@ * * @param {Array} stackframes * @param {String} url + * @param {String} errorMsg */ - report: function StackTrace$$report(errorMsg, stackframes, url) { + report: function StackTrace$$report(stackframes, url, errorMsg) { return new Promise(function(resolve, reject) { var req = new XMLHttpRequest(); req.onerror = reject; @@ -183,7 +184,13 @@ }; req.open('post', url); req.setRequestHeader('Content-Type', 'application/json'); - req.send(JSON.stringify({message: errorMsg, stack: stackframes})); + + var reportPayload = {stack: stackframes}; + if (errorMsg != undefined) { + reportPayload.message = errorMsg; + } + + req.send(JSON.stringify(reportPayload)); }); } };