Logging¶
As our programs become more complex, some logging/printf
capabilities are needed (sorry, no debugger yet). So, let’s take a short break from Behavioral Programming in BPjs, and meet bp.log
.
bp.log
is a logger object. Logging is done to standard out (System.out
, to be specific). There are four log levels, so while developing you can turn messages on and off, to help you focus on the problematic areas. The below program exercises the logger a bit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | bp.log.info("registering b-threads - start");
var LOG_LEVELS = ["Fine", "Info", "Warn", "Off"];
bp.registerBThread( "event generator", function(){
for (var i = 0; i < LOG_LEVELS.length; i++) {
bp.sync({request:bp.Event("event " + String(i))});
}
});
bp.registerBThread( "event logging", function() {
var idx = 0;
while (true) {
var evt = bp.sync({waitFor:bp.all});
bp.log.setLevel(LOG_LEVELS[idx]);
bp.log.warn( evt.name );
bp.log.info( evt.name );
bp.log.fine( evt.name );
idx++;
}
})
bp.log.info("registering b-threads - done");
|
The “event generator” creates four events, one for each logging level. The “event logging” b-thread waits for all events (note the use of bp.all
), sets the logger level (line 14), and attempts to log in all three log methods (lines 15-17). Here is the program output. Note that after event 3, where the level is set to "Off"
, no messages are emitted at all.
# [READ] /.../logging.js
[JS][Info] registering b-threads - start
-:BPjs Added event generator
-:BPjs Added event logging
[JS][Info] registering b-threads - done
# [ OK ] logging.js
---:BPjs Started
--:BPjs Event [BEvent name:event 0]
[JS][Warn] event 0
[JS][Info] event 0
[JS][Fine] event 0
--:BPjs Event [BEvent name:event 1]
[JS][Warn] event 1
[JS][Info] event 1
--:BPjs Event [BEvent name:event 2]
[JS][Warn] event 2
--:BPjs Event [BEvent name:event 3]
---:BPjs No Event Selected
---:BPjs Ended
Caution
Later versions might integrate BPjs with a full-blown logging system, such as logback or log4j2. Programs relying on the exact logging format may need to change once the logging is updated. If you need to write a program that relies on accurate interpretation a b-program life cycle and selected events, consider implementing a BProgramRunnerListener.
Note
Logging does not have to go to System.out
. Client code can set its destination PrintStream
by calling BProgram#setLoggerOutputStreamer
.
Message Formatting¶
The BPjs logger formats messages using Java’s MessageFormat. Under the hood, JavaScript objects are printed using a special formatter, which gives more information that the default cryptic [object object]
. The code below contains some formatting examples:
1 2 3 4 5 6 7 8 9 10 11 | const obj = {hello: "World", idioms:["request","waitFor","block"]};
const stuff = new Set();
stuff.add("thing 1");
stuff.add("thing 2");
stuff.add("thing 42");
bp.log.info("Here is field hello: {0} of object {1}", obj.hello, obj);
bp.log.info("Here is are some {1}: {0}", stuff, "stuff");
bp.log.info("I have a {0,number} reasons to block this event.", 1000000);
bp.log.info("{0} {0,number,#.##} {0,number,#.####}", 3.14159);
|
[BP][Info] Here is field hello: World of object {JS_Obj hello:"World", idioms:[JS_Array 0:"request" | 1:"waitFor" | 2:"block"]}
[BP][Info] Here is are some stuff: {JS_Set "thing 1", "thing 2", "thing 42"}
[BP][Info] I have a 1,000,000 reasons to block this event.
[BP][Info] 3.142 3.14 3.1416
Caution - Array Ambiguity¶
A curious API edge-case occurs when using message formatting, and passing a single variable for printing, AND said single variable is an array. The system auto-spreads the array, and only the first item of the array is printed. So the following code:
bp.registerBThread("t1",function(){
bp.log.info("array:{0}", ["x","y","z"]);
});
Prints this:
[BP][Info] array:x
To work around this, either include a dummy variable, or wrap the array in another array:
bp.log.info("array:{0}", [["x","y","z"]]);
bp.log.info("array:{0}", ["x","y","z"], "dummy val");