jsish
Logging
Not logged in

Jsi applications facilitate debugging with statements LogDebug, LogTrace, ....

These provide log() output, when run with -Debug/-Trace, but are otherwise NoOps.

Commands

The low level output commands are:
Command Description
puts Quotes arguments to stdout
printf Formatted output to stdout
log Like puts but including file/line info
console.puts Like puts but outputs to stderr
console.log Like log but outputs to stderr
console.logf Like console.log but using printf formatting
assert When expression is false throw error (or output msg)

All commands except printf automatically add a newline.

See System and console.

puts

The puts command quotes all of it's arguments and outputs them to stdout. eg.

puts("Batman begins");
var X = {a:1, b:"two"};
puts(X);
puts(X.a, X.b);
Batman begins
{ a:1, b:"two" }
1 two

printf(fmt,...)

The printf command processes arguments according to format and outputs to stdout. eg.

printf("Batman begins: %d %s\n", X.a, X.b);

log(arg, ...)

The log command is like puts, but includes the current file, line and function.

log("Batman begins");
"Batman begins", file.jsi:12, func()

console.log(arg, ...)

The console.log is exactly like log, but output goes to stderr.

console.log("Batman begins");

console.logf(fmt, ...)

The console.logf is like printf and log, but it outputs to stderr and includes the current file, line and function with newline:

console.logf("Batman begins: %d %s", X.a, X.b);

assert(expr, msg, noThrow)

assert(expr:boolean|number|function, msg:string, noThrow=false)

The assert command is used for constraint checking. When disabled (the default) none of it's arguments get evaluted.

When enabled and the expression evaluates to false, an error is thrown, eg.

"use assert";
var m = 1, n = -1;
assert(m>0, "too small");
assert(n>=0 && n<100, "passed bad n", true);

If expression is a function, the invocations returned value is used.

Thus the following outputs 0 when assert is disabled.

var m = 0;
assert(++m>0);
puts(m);

When the argument noThrow is true, assert just outputs a message along with current file, line and function.

It can also be made to output a message rather than throw an error.


LogDebug

The logging facilitity in Jsi provides output messages that are particularly useful for debugging applications, because output messages include the file and line number:

var i = 0;
while  (i++ < 3) {
    LogInfo("test loop: %d", i);
}
mytest.jsi:3, "INFO:  test loop: 1", 
mytest.jsi:3, "INFO:  test loop: 2", 
mytest.jsi:3, "INFO:  test loop: 3", 

This can be useful when running scripts from geany, where you can navigate through the messages just as you would compiler warnings.

The available Log commands are:

Command Notes
LogDebug Outputs only when logOpts.Debug is true
LogTrace Outputs only when logOpts.Trace is true
LogTest Outputs only when logOpts.Test is true
LogInfo
LogWarn
LogError
LogFatal

Remember that these commands use printf style formatting, so a percent should be escaped with %%.

Debug Logging

The commands LogDebug, LogTrace, and LogTest are special in that unless enabled they produce no output.

We enable LogDebug with "use Debug" as in this example:

"use strict,Debug,Test";
var i = 0;
while  (i++ < 2) {
    LogDebug("test loop: %d", i);
    LogTrace("test loop: %d", i);
    LogTest("test loop: %d", i);
}
mydebug.jsi:4, "DEBUG: test loop: 1", 
mydebug.jsi:5, "TRACE: test loop: 1", 
mydebug.jsi:4, "DEBUG: test loop: 2", 
mydebug.jsi:5, "TRACE: test loop: 2", 

In the discussion below, descriptions mentioning LogDebug apply equally to LogTrace, and LogTest.

Enabling Logs

As shown above, one way logging can be enable is by inserting a use directive.

There are several other ways, such as from the command-line:

jsish -T Debug,Trace mydebug2.jsi 
JSI_INTERP_OPTS='{logOpts:{Debug:true,Trace:true}}' jsish mydebug2.jsi

Note however that command-line options are overriden by use directives:

"use !Debug";
LogDebug("can't appear");

Although, inside the script can also add:

Interp.conf({logOpts:{Debug:true,Trace:true}});

No-Op Arguments

It is important to understand that when disabled, the LogDebug functions and their arguments are essentially No-Ops, as in this example:

var i = 0, k = 0;
while  (i++ < 3) {
    LogDebug("test loop: %d, %d", i, k++);
}
printf("K=%d\n", k);

Running the above may seem confusing at first:

jsish myincr.jsi
K=0;

jsish -T Debug myincr.jsi
myincr.jsi:3, "DEBUG: test loop: 1, 0", 
myincr.jsi:3, "DEBUG: test loop: 2, 1", 
myincr.jsi:3, "DEBUG: test loop: 3, 2", 
K=3

But the explanation is simply that when debugging is disabled, both calls and argument marshalling code are elided and have no effect.

This may seem counter-intuitive, but it means that code may be peppered with LogDebug commands while experiencing virtually no runtime penalty (until enabled).

It also means any breakpoint set on a disabled LogDebug will be ignored.

Module Logging

In a larger application it may be undesirable to turn on global logging. Which is where module-local logging comes in.

Here is a minimal module (mycall):

function mycall(args:array=void, conf:object=void) {
    var options = { Debug: false, Trace: false };
    var self = { cnt:0 };
    parseOpts(self,options,conf);
    
    LogDebug("MYLOC 1: %s", args.join(','));
    LogTrace("MYLOC 2: %s", args.join(','));
}

LogDebug("MYGLOB 1");
LogTrace("MYGLOB 2");
provide();
if (isMain())
    runModule(mycall);

which we run with local logging:

jsish mycall.jsi -debug true A B C
mycall.jsi:6,   "DEBUG: test 1: A,B,C", mycall()

jsish -T Debug mycall.jsi -Trace true A B C
mycall.jsi:10,  "DEBUG: MYGLOB 1"
mycall.jsi:6,   "DEBUG: MYLOC 1: A,B,C", mycall()
mycall.jsi:7,   "TRACE: MYLOC 2: A,B,C", mycall()

This demonstrates that logging can be local, global or a mixture of both.

Note that parseOpts implicitly accepts the boolean options Debug, Trace, Test.

More Modules

Here is a more complete module mytest1 using parseOpts and logging:

#!/usr/bin/env jsish
"use strict";
function mytest1(args:array, conf:object=void):object {
    var options = { // Here is my test.
        Debug       :false,     // Debugging output
        label       :''         // Some other argument
    };
    var self = {
        count: 0
    };
    
    parseOpts(self, options, conf);
    for (var msg of args) {
        self.count++;
        LogDebug("testing: %q", msg);
    }
    puts("Done");
    return self;
}

provide('mytest1');
LogDebug("Loading test1");

if (isMain())
    runModule(mytest1);

This allows us to turn on module-local debugging from the command line:

jsish mytest1.jsi a b c
Done

jsish mytest1.jsi -debug true a b c
mytest1.jsi:17, "DEBUG: testing: a", mytest1()
mytest1.jsi:17, "DEBUG: testing: b", mytest1()
mytest1.jsi:17, "DEBUG: testing: c", mytest1()
Done

jsish mytest1.jsi -h
/home/user/mytest1.jsi:121: error: ... 
OPTIONS FOR 'mytest1.jsi' // Here is my test.
    -Debug      false       // Debugging output.
    -label      ""          // Some other argument.
    -Test       false       // Testing output.
    -Trace      false       // Tracing output.

ERROR

Exec

By making your script executable, you can run it directly from Geany with F9.

Then you can employ jsish as an replacement for /usr/bin/env, with support for arguments:

#!/usr/local/bin/jsish -T debug %s -trace true myinput1.txt
puts(console.args.join(' '));

See Shell


Interp logOpts

The interp option logOpts is used to control when the above commands are to output the current file, line and function.

It can also arrange for all such messages to be directed to a log file.

If you are debugging a program and need to find where a puts is coming from, try adding to the top

Interp.conf({tracePuts:true});

The same can be done from the command-line eg:

"use assert";
JSI_INTERP_OPTS='{tracePuts:true}'   jsish tests/assert.js
"caught error" --> assert.js:16
"K" --> assert.js:24
"caught error2" --> assert.js:28
"this assert failed" --> assert.js:31
"assert also failed" --> assert.js:34
"done" --> assert.js:36

The Jsi_LogFile() command can be used to send logging to a file.