302 lines
8.4 KiB
JavaScript
302 lines
8.4 KiB
JavaScript
/*
|
|
Copyright (c) 2012, Oracle and/or its affiliates. All rights
|
|
reserved.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; version 2 of
|
|
the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
02110-1301 USA
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
|
|
var path = require("path"),
|
|
util = require("util"),
|
|
assert = require("assert"),
|
|
|
|
UDEB_OFF = 0,
|
|
UDEB_URGENT = 1,
|
|
UDEB_NOTICE = 2,
|
|
UDEB_INFO = 3,
|
|
UDEB_DEBUG = 4,
|
|
UDEB_DETAIL = 5,
|
|
|
|
udeb_on = 1, // initially on/off
|
|
udeb_level = UDEB_NOTICE, // initial level
|
|
destinationStream = process.stderr, // initial message destination
|
|
nativeCodeClients = [],
|
|
logListeners = [],
|
|
fileLoggers = {},
|
|
presetPerFileLevel= {},
|
|
myOwnLogger = null;
|
|
|
|
|
|
/* This is a common internal run-time debugging package for C and JavaScript.
|
|
* In the spirit of Fred Fish's dbug package, which is widely used in the
|
|
* MySQL server, this package manages "printf()-style" debugging of source
|
|
* code.
|
|
*
|
|
* It allows a JavaScript user to control debugging output both from
|
|
* JavaScript code and from compiled C code. The user can direct the debugging
|
|
* output to a particular file, and can enable output from indiviual source code
|
|
* files.
|
|
*
|
|
* SUMMARY:
|
|
*
|
|
* var unified_debug = require("unified_debug.js");
|
|
*
|
|
* var udebug = unified_debug.getLogger("myFilename.js");
|
|
*
|
|
* udebug.log(<message>) // write message (at DEBUG level)
|
|
* udebug.log_urgent(<message>) // write message at URGENT level
|
|
* udebug.log_notice(<message>) // write message at NOTICE level
|
|
* udebug.log_info(<message>) // write message at INFO level
|
|
* udebug.log_debug(<message>) // write message at DEBUG level
|
|
* udebug.log_detail(<message>) // write message at DETAIL level
|
|
* udebug.set_file_level(level) // override output level for this file
|
|
*
|
|
*
|
|
* unified_debug.on() // turn debugging on
|
|
* unified_debug.off() // turn debugging off
|
|
* unified_debug.level_urgent() // set output level to URGENT
|
|
* unified_debug.level_notice() // set output level to NOTICE
|
|
* unified_debug.level_info() // set output level to INFO
|
|
* unified_debug.level_debug() // set output level to DEBUG
|
|
* unified_debug.level_detail() // set output level to DETAIL
|
|
* unified_debug.level_meta() // also debug the debug system
|
|
* unified_debug.close() // close the destination stream
|
|
*
|
|
* // Set the destination stream for debugging messages:
|
|
* unified_debug.set_destination(writeableStream)
|
|
*
|
|
* // Register a native code module, which must export
|
|
* // setLogger() and setLevel() functions to JavaScript:
|
|
* unified_debug.register_client(module)
|
|
*
|
|
* // Set a per-filename output level:
|
|
* unifed_debug.set_file_level(filename, level)
|
|
*
|
|
* // Register a receiver function which will be called with
|
|
* // arguments (level, filename, message) whenever a message is logged.
|
|
* unified_debug.register_receiver(receiverFunction);
|
|
*
|
|
*/
|
|
|
|
|
|
/* Customize the destination stream
|
|
*/
|
|
exports.set_destination = function(writableStream) {
|
|
destinationStream = writableStream;
|
|
};
|
|
|
|
|
|
/* close the destination stream
|
|
*/
|
|
exports.close = function() {
|
|
if(destinationStream !== process.stderr && destinationStream !== process.stdout) {
|
|
destinationStream.end();
|
|
}
|
|
};
|
|
|
|
/* Register a log receiver
|
|
*/
|
|
exports.register_receiver = function(rFunc) {
|
|
logListeners.push(rFunc);
|
|
};
|
|
|
|
/* Set per-file debugging level
|
|
*/
|
|
exports.set_file_level = function(filename, level) {
|
|
var i;
|
|
if(fileLoggers[filename]) {
|
|
fileLoggers[filename].set_file_level(level);
|
|
}
|
|
else {
|
|
/* Maybe a file not yet registered */
|
|
presetPerFileLevel[filename] = level;
|
|
|
|
/* Maybe a C++ file */
|
|
for(i = 0 ; i < nativeCodeClients.length ; i++) {
|
|
var client = nativeCodeClients[i];
|
|
client.setFileLevel(filename,level);
|
|
}
|
|
}
|
|
};
|
|
|
|
/* Tell native code logging clients about the level
|
|
*/
|
|
function clientSetLevel(l) {
|
|
var i, client;
|
|
for(i = 0 ; i < nativeCodeClients.length ; i++) {
|
|
client = nativeCodeClients[i];
|
|
client.setLevel(l);
|
|
}
|
|
}
|
|
|
|
/* Turn debugging output on.
|
|
*/
|
|
exports.on = function() {
|
|
udeb_on = 1;
|
|
clientSetLevel(udeb_level);
|
|
myOwnLogger.log("unified debug enabled");
|
|
};
|
|
|
|
/* Turn debugging output off.
|
|
*/
|
|
exports.off = function() {
|
|
udeb_on = 0;
|
|
clientSetLevel(UDEB_OFF);
|
|
myOwnLogger.log("unified debug disabled");
|
|
};
|
|
|
|
|
|
/* Set the logging level
|
|
*/
|
|
function udeb_set_level(lvl) {
|
|
udeb_level = lvl;
|
|
clientSetLevel(udeb_level);
|
|
}
|
|
|
|
exports.level_urgent = function() {
|
|
udeb_set_level(UDEB_URGENT);
|
|
};
|
|
|
|
exports.level_notice = function() {
|
|
udeb_set_level(UDEB_NOTICE);
|
|
};
|
|
|
|
exports.level_info = function() {
|
|
udeb_set_level(UDEB_INFO);
|
|
};
|
|
|
|
exports.level_debug = function() {
|
|
udeb_set_level(UDEB_DEBUG);
|
|
};
|
|
|
|
exports.level_detail = function() {
|
|
udeb_set_level(UDEB_DETAIL);
|
|
};
|
|
|
|
|
|
/**********************************************************/
|
|
function handle_log_event(level, file, message) {
|
|
var i;
|
|
for(i = 0 ; i < logListeners.length ; i++) {
|
|
logListeners[i](level, file, message);
|
|
}
|
|
}
|
|
|
|
function write_log_message(level, file, message) {
|
|
message += "\n";
|
|
destinationStream.write(message, 'ascii');
|
|
}
|
|
|
|
/// INITIALIZATION TIME: REGISTER write_log_message as a listener: ///
|
|
logListeners.push(write_log_message);
|
|
|
|
|
|
/* Register a C client so that it can send debugging output up to JavaScript
|
|
*/
|
|
exports.register_client = function(client) {
|
|
var fileName;
|
|
assert(typeof client.setLogger === 'function');
|
|
assert(typeof client.setLevel === 'function');
|
|
|
|
client.setLogger(handle_log_event);
|
|
client.setLevel(udeb_level);
|
|
|
|
nativeCodeClients.push(client);
|
|
|
|
/* Register per-file logging levels */
|
|
for(fileName in presetPerFileLevel) {
|
|
if(presetPerFileLevel.hasOwnProperty(fileName)) {
|
|
client.setFileLevel(fileName, presetPerFileLevel[fileName]);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
function dispatch_log_message(level, filename, msg_array) {
|
|
var message = util.format.apply(null, msg_array);
|
|
if(level > UDEB_NOTICE) {
|
|
message = filename + " " + message;
|
|
}
|
|
handle_log_event(level, filename, message);
|
|
}
|
|
|
|
|
|
function Logger() {}
|
|
Logger.prototype = {
|
|
URGENT : UDEB_URGENT,
|
|
NOTICE : UDEB_NOTICE,
|
|
INFO : UDEB_INFO,
|
|
DEBUG : UDEB_DEBUG,
|
|
DETAIL : UDEB_DETAIL,
|
|
file_level : 0,
|
|
set_file_level : function(x) { this.file_level = x; }
|
|
};
|
|
|
|
/***********************************************************
|
|
* get a custom logger class for a source file
|
|
*
|
|
***********************************************************/
|
|
exports.getLogger = function(filename) {
|
|
assert(! fileLoggers[filename]); // A filename cannot be registered twice
|
|
|
|
|
|
function makeLogFunction(level) {
|
|
return function() {
|
|
if((udeb_level >= level) || (this.file_level >= level))
|
|
{
|
|
dispatch_log_message(level, filename, arguments);
|
|
}
|
|
};
|
|
}
|
|
|
|
function makeIsFunction(level) {
|
|
return function() {
|
|
return (udeb_level >= level) || (this.file_level >= level);
|
|
};
|
|
}
|
|
|
|
var theLogger = new Logger();
|
|
var perFileLevel;
|
|
if(presetPerFileLevel[filename]) {
|
|
theLogger.file_level = presetPerFileLevel[filename];
|
|
delete presetPerFileLevel[filename];
|
|
} else {
|
|
theLogger.file_level = UDEB_URGENT;
|
|
}
|
|
|
|
theLogger.log_urgent = makeLogFunction(1);
|
|
theLogger.log_notice = makeLogFunction(2);
|
|
theLogger.log_info = makeLogFunction(3);
|
|
theLogger.log_debug = makeLogFunction(4);
|
|
theLogger.log_detail = makeLogFunction(5);
|
|
theLogger.log = theLogger.log_debug;
|
|
|
|
theLogger.is_urgent = makeIsFunction(1);
|
|
theLogger.is_notice = makeIsFunction(2);
|
|
theLogger.is_info = makeIsFunction(3);
|
|
theLogger.is_debug = makeIsFunction(4);
|
|
theLogger.is_detail = makeIsFunction(5);
|
|
|
|
fileLoggers[filename] = theLogger;
|
|
|
|
return theLogger;
|
|
};
|
|
|
|
myOwnLogger = exports.getLogger("unified_debug.js");
|
|
|