Catching all javascript unhandled exceptions - javascript

I'm trying to find or figure out a way to display in an alert box all of the unhandled javascript exceptions in an application. I'd want all of this to be done on the client side, without using any server side code. I'm using MVC3 as an environment.
I've been researching for the last few days and haven't found exactly what I'm looking for.
I found 2 ways below that seem like they're almost what I'm looking for, except these ways are set up so that you have to pass a function name into a custom method to print the stack trace of all unhandled exceptions within that one specific function. I'm looking for a way to not have to manually pass a function name to a custom method that prints the stack trace of all of the unhandled exceptions. I'd want these custom method to just 'listen' for all unhandled exceptions within the whole application.
http://eriwen.com/javascript/js-stack-trace/
Also something similar to the previous link:
https://github.com/eriwen/javascript-stacktrace
Here's the basic code from the 2nd link above that prints the stack trace of a specified javascript function:
instrumentFunction: function (context, functionName, callback) {
context = context || window;
var original = context[functionName];
context[functionName] = function instrumented() {
callback.call(this, printStackTrace().slice(4));
return context[functionName]._instrumented.apply(this, arguments);
};
context[functionName]._instrumented = original;
}
function printStackTrace(options) {
options = options || {
guess: true
};
var ex = options.e || null,
guess = !! options.guess;
var p = new printStackTrace.implementation(),
result = p.run(ex);
return (guess) ? p.guessAnonymousFunctions(result) : result;
}
So, to sum this up, do you all know of any way to have some sort of 'listener' to listen for all javascript unhandled exceptions and then print them to the screen in an alert box?
Thanks!
Jason

You can do this by using window.onerror method.
window.onerror = function myErrorHandler(errorMsg, url, lineNumber) {
alert("Error occured: " + errorMsg);//or any message
return false;
}

You can either use window.onerror, or (amazingly!) bind to the 'error' event properly:
window.onerror = function (message, file, line, col, error) {
alert("Error occurred: " + error.message);
return false;
};
window.addEventListener("error", function (e) {
alert("Error occurred: " + e.error.message);
return false;
})
If you want to track JavaScript errors, you can try Atatus. I work at Atatus.

In addition to
window.onerror = function (message, file, line, col, error) {
alert("Error occurred: " + error.message);
return false;
};
window.addEventListener("error", function (e) {
alert("Error occurred: " + e.error.message);
return false;
})
You can also catch all the errors fired inside a promise callback (.then()) listening for unhandledrejection event
window.addEventListener('unhandledrejection', function (e) {
alert("Error occurred: " + e.reason.message);
})

Check out http://log4javascript.org it is based on Log4J. If most of your code is wrapped in try/catch statements to handle exceptions you can make use of this library as a common interface for sending output to an always available "dialog box" or logging window that your end user could see. You could even have a button that performs a window.print() to print the contents of the dialog box to the printer or PDF. Good luck.

Related

How can I hide an uncaught error from my browser?

I have some simple code that does the job but gives an uncaught error.
ck.setMode('source');
ck.setMode( 'wysiwyg');
This is giving me the message:
Uncaught TypeError: Cannot read property 'on' of undefined
I know it's probably a bad practice but the error does not cause any problems and I would like to avoid it showing in the browser. Is there some way that I could enclose this code so it does not give a browser console alert?
Here's the code that encloses the above:
ngModel.$render = function () {
if (typeof ngModel.$modelValue != 'undefined') {
if (ngModel.$modelValue != null) {
ck.setData(ngModel.$modelValue);
timer = setTimeout(function () {
ck.setData(ngModel.$modelValue);
}, 1000);
timer = setTimeout(function () {
ck.setMode('source');
ck.setMode('wysiwyg');
}, 1000);
}
}
};
You may use code like this:
window.onerror = function(message, url, lineNumber) {
// maybe some handling?
return true; // prevents browser error messages
};
It prevents all error messages, so use it with care.
You can put your code block inside a try catch. So your code would become like this.
try {
ck.setMode('source');
ck.setMode( 'wysiwyg');
}
catch (error) {
// handle your error
}

Proxy built-in errors?

Is it possible to influence errors thrown from the JS compiler? In particular, I want to create my own error type NullPointerException and then proxy the built-in errors (such as Error and TypeError) to potentially return my custom exception.
Consider the following simple attempt (yes, they are global variables – but they are supposed to be):
NullPointerException = function (msg) {
this.message = msg;
};
NullPointerException.prototype.toString = function () {
return "NullPointerException: " + this.message;
};
var ProxyTypeError = TypeError;
TypeError = function (msg) {
if (msg.indexOf('null') === -1) {
return new ProxyTypeError(msg);
}
return new NullPointerException(msg);
};
This will work fine for cases like
throw new TypeError('normal error'); // 'TypeError: normal error'
throw new TypeError('null'); // 'NullPointerException: null'
However, it won't work for the scenario I actually want it to work:
var obj = null;
console.log( obj.someMethod() ); // 'Uncaught TypeError: ...'
I am aware that browsers both use different messages and different errors, as well as that it's sketchy to even be wanting to do any of this. However, I'd still be interested if there is any actual solution to this? In the end, the use-case is something like
try {
// ... code ...
} catch( e ) {
if( e instanceof NullPointerException ) {
// handle NPE separately
}
// do something else
}
wherein I do not have access to the catch part, hence my desire to throw the error accordingly.
Is it possible to influence errors thrown from the JS interpreter?
No. However, if you want to throw your own errors you can do that for all exceptions that happened in your own code:
try {
/* some code, possibly foreign */
var obj = null;
obj.someMethod()
} catch (e) {
throw new CustomTypeError(e.msg);
}
but it would be much better to just check your types:
var obj = null;
if (obj == null)
throw new NullPointerException();
else
obj.someMethod();

SWFUpload startUpload() fails if not called within the file_dialog_complete_handler

I am trying to get SWFUpload to properly upload an image to my server, along with other post data that must come with the image. There is a form to fill up the data so after the user clicks the browse button and selects his image file, the image is not uploaded right away. It is kept in the queue until the user clicks a send button, I then call mySwfUploadInstance.startUpload() so that the upload starts.
But it fails miserably at line 452 of swfupload.js in the function 'callFlash':
Uncaught Call to ReturnUploadStart failed
The exception being caught before throwing this error is the following:
Object #<HTMLObjectElement> has no method 'CallFunction'
in the following function:
SWFUpload.prototype.callFlash = function (functionName, argumentArray) {
argumentArray = argumentArray || [];
var movieElement = this.getMovieElement();
var returnValue, returnString;
// Flash's method if calling ExternalInterface methods (code adapted from MooTools).
try {
returnString = movieElement.CallFunction('<invoke name="' + functionName + '" returntype="javascript">' + __flash__argumentsToXML(argumentArray, 0) + '</invoke>');
returnValue = eval(returnString);
} catch (ex) {
throw "Call to " + functionName + " failed";
}
// Unescape file post param values
if (returnValue != undefined && typeof returnValue.post === "object") {
returnValue = this.unescapeFilePostParams(returnValue);
}
return returnValue;
};
movieElement looks like being a valid flash object.
I do not get that error if I call startUpload() inside the function I pass to file_dialog_complete_handler when initializing SWFUpload:
function ImageFileDialogComplete(numFilesSelected, numFilesQueued)
{
try
{
this.startUpload();
}
catch (ex)
{
this.debug(ex);
}
}
I really need to be able to postpone the upload to when the user completes the form and click the send button.
Any idea what is wrong with SWFUPload when I call startUpload() out of the dialog complete handler?
It seems the problem was because I was hiding the div containing the flash object by setting display:none on it, right before calling startUpload(). I was doing this to hide the form and show a div with a progress bar instead.
For some reason the flash object must remain visible on screen else all calls made to it would fail.

Is there a way in JavaScript to listen console events?

I'm trying to write handler for uncaught exceptions and browser warnings in Javascript. All errors and warnings should be sent to server for later review.
Handled exceptions can be caught and easily logged with
console.error("Error: ...");
or
console.warn("Warning: ...");
So they are not problem if they are called from javascript code, even more, unhandled exceptions could be caught with this peace of code:
window.onerror = function(){
// add to errors Stack trace etc.
});
}
so exceptions are pretty covered but I've stuck with warnings which browser sends to console. For instance security or html validation warnings. Example below is taken from Google Chrome console
The page at https://domainname.com/ ran insecure content from
http://domainname.com/javascripts/codex/MANIFEST.js.
It would be great if there is some event like window.onerror but for warnings. Any thoughts?
You could just wrap the console methods yourself. For example, to record each call in an array:
var logOfConsole = [];
var _log = console.log,
_warn = console.warn,
_error = console.error;
console.log = function() {
logOfConsole.push({method: 'log', arguments: arguments});
return _log.apply(console, arguments);
};
console.warn = function() {
logOfConsole.push({method: 'warn', arguments: arguments});
return _warn.apply(console, arguments);
};
console.error = function() {
logOfConsole.push({method: 'error', arguments: arguments});
return _error.apply(console, arguments);
};
More Succint Way:
// this method will proxy your custom method with the original one
function proxy(context, method, message) {
return function() {
method.apply(context, [message].concat(Array.prototype.slice.apply(arguments)))
}
}
// let's do the actual proxying over originals
console.log = proxy(console, console.log, 'Log:')
console.error = proxy(console, console.error, 'Error:')
console.warn = proxy(console, console.warn, 'Warning:')
// let's test
console.log('im from console.log', 1, 2, 3);
console.error('im from console.error', 1, 2, 3);
console.warn('im from console.warn', 1, 2, 3);
I know it's an old post but it can be useful anyway as others solution are not compatible with older browsers.
You can redefine the behavior of each function of the console (and for all browsers) like this:
// define a new console
var console = (function(oldCons){
return {
log: function(text){
oldCons.log(text);
// Your code
},
info: function (text) {
oldCons.info(text);
// Your code
},
warn: function (text) {
oldCons.warn(text);
// Your code
},
error: function (text) {
oldCons.error(text);
// Your code
}
};
}(window.console));
//Then redefine the old console
window.console = console;
I needed to debug console output on mobile devices so I built this drop-in library to capture console output and category and dump it to the page. Check the source code, it's quite straightforward.
https://github.com/samsonradu/Consolify
In the same function that you are using to do console.log(), simply post the same message to a web service that you are recording the logs on.
You're going about this backwards. Instead of intercepting when an error is logged, trigger an event as part of the error handling mechanism and log it as one of the event listeners:
try
{
//might throw an exception
foo();
}
catch (e)
{
$(document).trigger('customerror', e);
}
function customErrorHandler(event, ex)
{
console.error(ex)
}
function customErrorHandler2(event, ex)
{
$.post(url, ex);
}
this code uses jQuery and is oversimplified strictly for use as an example.

Showing console errors and alerts in a div inside the page

I'm building a debugging tool for my web app and I need to show console errors in a div. I know I can use my own made console like object and use it, but for future use I need to send all console errors to window. Actually I want to catch console events.
To keep the console working:
if (typeof console != "undefined")
if (typeof console.log != 'undefined')
console.olog = console.log;
else
console.olog = function() {};
console.log = function(message) {
console.olog(message);
$('#debugDiv').append('<p>' + message + '</p>');
};
console.error = console.debug = console.info = console.log
Here's a way using closure, containing the old console log function in the scope of the new one.
console.log = (function (old_function, div_log) {
return function (text) {
old_function(text);
div_log.value += text;
};
} (console.log.bind(console), document.getElementById("error-log")));
None of the answers here consider console messages that get passed multiple parameters. E.g. console.log("Error:", "error details")).
The function that replaces the default log function better regards all function arguments (e.g. by using the arguments object). Here is an example:
console.log = function() {
log.textContent += Array.prototype.slice.call(arguments).join(' ');
}
(The Array.prototype.slice.call(...) simply converts the arguments object to an array, so it can be concatenated easily with join().)
When the original log should be kept working as well:
console.log = (function (old_log, log) {
return function () {
log.textContent += Array.prototype.slice.call(arguments).join(' ');
old_log.apply(console, arguments);
};
} (console.log.bind(console), document.querySelector('#log')));
A complete solution:
var log = document.querySelector('#log');
['log','debug','info','warn','error'].forEach(function (verb) {
console[verb] = (function (method, verb, log) {
return function () {
method.apply(console, arguments);
var msg = document.createElement('div');
msg.classList.add(verb);
msg.textContent = verb + ': ' + Array.prototype.slice.call(arguments).join(' ');
log.appendChild(msg);
};
})(console[verb], verb, log);
});
(An example of a framework that emits messages with multiple parameters is Video.js. But there is certainly many others.)
Edit: Another use of multiple parameters is the formatting capabilities of the console (e.g. console.log("Status code: %d", code).
About errors that are not shown
(Update Dec. 2021)
If any code crashes with an uncaught error, in might not show up in the div. One solution could be, if possible, to wrap all code in a try block to catch such errors and log them manually to the div.
try {
// Code that might throw errors...
} catch(err) {
// Pass the error to the overridden error log handler
console.error(err);
}
Else, if you were concerned at keeping log, warn and error separate from one another, you could do something like this (adapted from MST's answer):
var log = document.querySelector('#log');
['log','warn','error'].forEach(function (verb) {
console[verb] = (function (method, verb, log) {
return function (text) {
method(text);
// handle distinguishing between methods any way you'd like
var msg = document.createElement('code');
msg.classList.add(verb);
msg.textContent = verb + ': ' + text;
log.appendChild(msg);
};
})(console[verb].bind(console), verb, log);
});
where #log is your HTML element. The variable verb is one of 'log', 'warn', or 'error'. You can then use CSS to style the text in a distinguishable way. Note that a lot of this code isn't compatible with old versions of IE.
How about something as simple as:
console.log = function(message) {$('#debugDiv').append('<p>' + message + '</p>');};
console.error = console.debug = console.info = console.log
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<div id="logger" class="web_console"></div>
<script type="text/javascript">
// Overriding console object
var console = {};
// Getting div to insert logs
var logger = document.getElementById("logger");
// Adding log method from our console object
console.log = function(text)
{
var element = document.createElement("div");
var txt = document.createTextNode(text);
element.appendChild(txt);
logger.appendChild(element);
}
// testing
console.log("Hello World...");
console.log("WOW");
/**
console.log prints the message in the page instead browser console, useful to programming and debugging JS using a Android phone
*/
</script>
</body>
</html>
I created a zero-dependency npm module for this case: console-events (surely if you're okay to use nodejs :P)
You can add event listener like that:
const { console } = require('console-events');
console.addEventListener('log', (e) => {
e.preventDefault(); //if you need to prevent normal behaviour e.g. output to devtools console
$('#debugDiv').append('<p>' + message + '</p>');
})

Categories