Can I get exception stacktrace in kotlin-js? - javascript

I've been writing simple web-frontend for application with kotlin-js and faced with a problem of exception handling.
As I see, there is no API to get exception stacktrace: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html
Is it so?
If it is, may be anyone know some library or snippets to get stacktrace out of Throwable object?
Currently, I've got some workaround for this:
import kotlin.browser.window
fun main() {
window.onload = {
try {
throw RuntimeException()
} catch (e: Throwable) {
console.log(e)
throw e
}
}
}
Console output is:
Object {
"message_8yp7un$_0": null,
"cause_th0jdv$_0": null,
"stack": "captureStack#http://localhost:9080/js/kotlin.js:1767:27\nException#http://localhost:9080/js/kotlin.js:3244:14\nRuntimeException#http://localhost:9080/js/kotlin.js:3255:17\nRuntimeException_init#http://localhost:9080/js/kotlin.js:3261:24\nmain$lambda#http://localhost:9080/js/web-client.js:34:13\n",
"name": "RuntimeException"
}
Here, console.log(Throwable) exposes underlying JavaScript object properties, and there is stack one, but it points to JavaScript code, that is hard to use without source mapping back to kotlin.
UPD: it seems like stack is not standard exception property, but common one for modern browsers.

Since Kotlin 1.4 the stdlib contains two extensions for this exact purpose
fun Throwable.stackTraceToString()
fun Throwable.printStackTrace()
Using these we can write
window.onload = {
try {
throw RuntimeException()
} catch (e: Throwable) {
e.printStackTrace()
}
}

Just change your console.log to console.error
import kotlin.browser.window
fun main() {
window.onload = {
try {
throw RuntimeException()
} catch (e: Throwable) {
console.error(e) // change here
throw e
}
}
}

Not perfect, not standard, but it works.
It also handles the source map in Firefox, so I get proper file names and line numbers:
try {
throw IllegalStateException("ops...")
}
catch (ex : Throwable) {
val stack = ex.asDynamic().stack
if (stack is String) {
val error = js("Error()")
error.name = ex.toString().substringBefore(':')
error.message = ex.message?.substringAfter(':')
error.stack = stack
console.error(error)
} else {
console.log(ex)
}
}

Related

SSJS Platform.Response.Redirect throws error in Try Catch Statement

I suspect threadabortexception issue of .NET but I couldn't fix it with possible options.
In short Redirect function throws an errors and goes to the catch, no matter to set the second parameter true or false).
The code below is just an example (but I faced this a couple of times before in real-time projects).
...
try {
var TSD = TriggeredSend.Init("DE_Name");
var Status = TSD.Send(data.subscriber, data.attributes);
if (Status != "OK") {
Platform.Response.Redirect(Variable.GetValue("#error_page"));
} else {
Platform.Response.Redirect(Variable.GetValue("#thanks_page")); //<<<-- This redirect throw error
}
} catch (err) {
Platform.Response.Redirect(Variable.GetValue("#error_page")); // <---- here it comes
}
...
Resources might helps:
1# https://support.microsoft.com/en-us/help/312629/prb-threadabortexception-occurs-if-you-use-response-end-response-redir
2# https://developer.salesforce.com/docs/atlas.en-us.mc-programmatic-content.meta/mc-programmatic-content/ssjs_platformClientBrowserRedirect.htm?search_text=Redirect
Any workaround is welcome.
I know this is an older question but I think it would be good to share findings.
There is no logical explanation to me why this is happen but the Redirect always throws an error and if it is used in a try block, the catch part will be executed.
Here is a simple workaround:
...
try {
var TSD = TriggeredSend.Init("DE_Name");
var Status = TSD.Send(data.subscriber, data.attributes);
try {
if (Status != "OK") {
Platform.Response.Redirect(Variable.GetValue("#error_page"));
} else {
Platform.Response.Redirect(Variable.GetValue("#thanks_page")); //<<<-- This redirect throw error
}
} catch(e) {}
} catch (err) {
Platform.Response.Redirect(Variable.GetValue("#error_page")); // <---- here it comes
}
...

How to capture "ReferenceError: Can't find variable"

I have the following Code:
if(AdMob) { ... }
Then I get the error:
ReferenceError: Can't find variable AdMob
How to capture this error that I don't see it in the console anymore?
EDIT:
Why AdMob is not just falsy and I'm not getting any error.
The only real way to avoid errors being logged is to put the code in a try/catch block.
try {
if(AdMob){
}
} catch(e){
}
Verify it does not result in errors on this Fiddle
Of course you could solve it as easy as defining the variable (assuming this should not be a global variable):
var AdMob;
try {
if(AdMob) { }
}
catch(err){
//Do something here
}
or you can throw custom exception
try {
if(AdMob) { }
}
catch(err){
throw new Error("Error: AdMob is not defined");
}
Use try-catch to capture the error
try {
if (AdMob) {
}
} catch (e) {
console.log(e);
}

throwing a debug from chrome extension content script

Short version
Trying to write a debug command that returns the call stack, minus the current position. I thought I'd use:
try {
throw new Error(options["msg"])
} catch (e) {
e.stack.shift;
throw (e);
}
but I don't know how to do it exactly. apparently I can't just e.stack.shift like that. Also that always makes it an Uncaught Error — but these should just be debug messages.
Long version
I decided I needed a debug library for my content scripts. Here it is:
debug.js
var debugKeys = {
"level": ["off", "event", "function", "timeouts"],
"detail": ["minimal", "detailed"]
};
var debugState = { "level": "off", "detail": "minimal" };
function debug(options) {
if ("level" in options) {
if (verifyDebugValue("level", options["level"]) == false)
return
}
if ("detail" in options) {
if (verifyDebugValue("detail", options["detail"]) == false)
return
}
console.log(options["msg"]);
}
function verifyDebugValue(lval, rval){
var state = 10; // sufficiently high
for (k in debugKeys[lval]) {
if (debugKeys[lval][k] == rval) {
return true;
}
if (debugKeys[lval][k] == debugState[lval]) { // rval was greater than debug key
return false;
}
}
}
When you using it, you can change the debugState in the code to suit your needs. it is still a work in progress but it works just fine.
To use it from another content script, just load it in the manifest like:
manifest.json
"content_scripts": [
{
"js": ["debug.js", "foobar.js"],
}
],
and then call it like:
debug({"level": "timeouts", "msg": "foobar.js waitOnElement() timeout"});
which generates:
foobar.js waitOnElement() timeout debug.js:17
And there is my problem. At the moment, it is using the console log and so all the debug statements come from the same debug.js line. I'd rather return the calling context. I imagine I need something like:
try {
throw new Error(options["msg"])
} catch (e) {
e.stack.shift;
throw (e);
}
but I don't know how to do it exactly. apparently I can't just e.stack.shift like that. Also that always makes it an Uncaught Error — but these should just be debug messages.
You can't avoid mentioning the line in your debug.js, because either using throw (...) or console.log/error(...) your debug.js will be issuing the command.
What you can do, is have some try-catch blocks in your code, then in the catch block pass the error object to your debug function, which will handle it according to its debugState.
In any case, it is not quite clear how you are using your debug library (and why you need to remove the last call from the stack-trace, but you could try something like this:
Split the stack-trace (which is actually a multiline string) into lines.
Isolate the first line (corresponding to the last call) that is not part of the error's message.
Put together a new stack-trace, with the removed line.
E.g.:
function removeLastFromStack(stack, errMsg) {
var firstLines = 'Error: ' + errMsg + '\n';
var restOfStack = stack
.substring(firstLines.length) // <-- skip the error's message
.split('\n') // <-- split into lines
.slice(1) // <-- "slice out" the first line
.join('\n'); // <-- put the rest back together
return firstLines + restOfStack;
}
function myDebug(err) {
/* Based on my `debugState` I should decide what to do with this error.
* E.g. I could ignore it, or print the message only,
* or print the full stack-trace, or alert the user, or whatever */
var oldStack = err.stack;
var newStack = removeLastFromStack(oldStack, err.message);
console.log(newStack);
//or: console.error(newStack);
}
/* Somewhere in your code */
function someFuncThatMayThrowAnErr(errMsg) {
throw new Error(errMsg);
}
try {
someFuncThatMayThrowAnErr('test');
} catch (err) {
myDebug(err);
}
...but I still don't see how removing the last call from the trace would be helpful

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();

creating an exception handler in HTML5/javascript

I am new to the web development world and I would like I am lost in the steps of creating an exception in a java script function
what I want to ideally do is something following the following syntax ...
function exceptionhandler (){
if (x===5)
{
//throw an exception
}
}
I found the following tutorial
http://www.sitepoint.com/exceptional-exception-handling-in-javascript/
But I don t know how to convert the above if statement into a try..catch...finally exception
thanks!
To create an error in JavaScript you have to throw something, which can be an Error, a specific type of Error, or any Object or String.
function five_is_bad(x) {
if (x===5) {
// `x` should never be 5! Throw an error!
throw new RangeError('Input was 5!');
}
return x;
}
console.log('a');
try {
console.log('b');
five_is_bad(5); // error thrown in this function so this
// line causes entry into catch
console.log('c'); // this line doesn't execute if exception in `five_is_bad`
} catch (ex) {
// this only happens if there was an exception in the `try`
console.log('in catch with', ex, '[' + ex.message + ']');
} finally {
// this happens either way
console.log('d');
}
console.log('e');
/*
a
b
in catch with RangeError {} [Input was 5!]
d
e
*/
You may be looking for something like this:
function exceptionhandler() {
try {
if (x===5) {
// do something
}
} catch(ex) {
throw new Error("Boo! " + ex.message)
}
}

Categories