js/base/loggable.js
// NPM IMPORTS
import assert from 'assert'
// COMMON IMPORTS
import T from '../utils/types'
/**
* Contextual constant for this file logs.
* @private
*/
const context = 'common/base/loggable'
/**
* Base class to deal with traces.
* @abstract
*
* @author Luc BORIES
* @license Apache-2.0
*
* @example
* API:
* get_context():string - get instance context.
* get_class):string - get instance class.
* get_name():string - get instance name.
*
* should_trace(arg_traces_cfg:plain object):boolean - test if loggers should trace this instance.
*
* get_logger_manager():LoggerManager
* update_trace_enabled():nothing
*
* enable_trace():nothing
* disable_trace():nothing
* get_trace():boolean
* set_trace(arg_value):nothing
* toggle_trace():nothing
*
* debug(...args):nothing
* info(...args):nothing
* warn(...args):nothing
* error(...args):nothing
*
* enter_group(arg_group) leave_group(arg_group):nothing
* separate_level_1():nothing
* separate_level_2():nothing
* separate_level_3():nothing
*
*/
export default class Loggable
{
/**
* Create a Loggable instance.
*
* @param {string} arg_log_context - trace context.
* @param {LoggerManager} arg_logger_manager - logger manager instance.
*
* @returns {nothing}
*/
constructor(arg_log_context, arg_logger_manager)
{
/**
* Class type flag.
* @type {boolean}
*/
this.is_loggable = true
/**
* Log context.
* @type {string}
*/
this.$context = T.isString(arg_log_context) ? arg_log_context : context
/**
* Trace is enabled for this flag.
* @type {boolean}
*/
this.is_trace_enabled = true
/**
* Logger manager instance (default undefined)
* @type {LoggerManager}
*/
this._logger_manager = undefined
if ( T.isObject(arg_logger_manager) && arg_logger_manager.is_logger_manager )
{
this._logger_manager = arg_logger_manager
}
else {
// DEBUG
// console.warn(this.get_class() + ':' + this.get_name() + ':no logger manager')
// debugger
}
// TO SET IN SUB CLASSES
// if ( ! this.is_server_runtime )
// {
// this.update_trace_enabled()
// }
}
/**
* Get instance context.
*
* @returns {string}
*/
get_context()
{
return this.$context
}
/**
* Define get instance name method for non Instance classes.
*
* @returns {string}
*/
get_name()
{
return 'Loggable instance'
}
/**
* Define get class name method for non Instance classes.
*
* @returns {string}
*/
get_class()
{
return 'Loggable'
}
/**
* Calculate should trace flag.
*
* @param {object} arg_traces_cfg - traces settings object as { modules:{ 'pattern':boolean }, classes:{ 'pattern':boolean }, instances:{ 'pattern':boolean } }.
*
* @returns {boolean} - trace flag.
*/
should_trace(arg_traces_cfg)
{
if ( ! T.isObject(arg_traces_cfg) )
{
console.error(context + ':should_trace(instance):no traces cfg')
return false
}
let should_trace = false
// CALCULATE TRACE FLAG
should_trace = should_trace || this.should_trace_module(arg_traces_cfg)
should_trace = should_trace || this.should_trace_class(arg_traces_cfg)
should_trace = should_trace || this.should_trace_name(arg_traces_cfg)
return should_trace
}
/**
* Calculate should trace flag for modules.
*
* @param {object} arg_traces_cfg - traces settings object as { modules:{}, classes:{}, instances:{} }
*
* @returns {boolean} - trace flag.
*/
should_trace_module(arg_traces_cfg)
{
return this.should_trace_collection_item(arg_traces_cfg, 'modules', 'get_context')
}
/**
* Calculate should trace flag for classes.
*
* @param {object} arg_traces_cfg - traces settings object as { modules:{}, classes:{}, instances:{} }
*
* @returns {boolean} - trace flag.
*/
should_trace_class(arg_traces_cfg)
{
return this.should_trace_collection_item(arg_traces_cfg, 'classes', 'get_class')
}
/**
* Calculate should trace flag for instances names.
*
* @param {object} arg_traces_cfg - traces settings object as { modules:{}, classes:{}, instances:{} }
*
* @returns {boolean} - trace flag.
*/
should_trace_name(arg_traces_cfg)
{
return this.should_trace_collection_item(arg_traces_cfg, 'instances', 'get_name')
}
/**
* Calculate should trace flag for given collection of names or patterns.
*
* @param {object} arg_traces_cfg - traces settings object as { modules:{ 'pattern':boolean }, classes:{}, instances:{} }.
* @param {string} arg_collection_name - 'modules' or 'classes' or 'instances'
* @param {string} arg_this_item_accessor - this method name to access attribute value.
*
* @returns {boolean} - trace flag.
*/
should_trace_collection_item(arg_traces_cfg, arg_collection_name, arg_this_item_accessor)
{
// console.log(context + ':should_trace_collection_item: collection=%s this.aceessor=%s', arg_collection_name, arg_this_item_accessor, arg_traces_cfg)
if ( ! T.isObject(arg_traces_cfg) )
{
return false
}
let should_trace = false
// TRACES COLLECTION ?
if ( T.isObject(arg_traces_cfg) && (arg_collection_name in arg_traces_cfg) )
{
const collection = arg_traces_cfg[arg_collection_name]
const attribute = this[arg_this_item_accessor]()
if ( (attribute in collection) )
{
should_trace = collection[attribute]
// console.log(context + ':should_trace_collection_item: collection=%s attribute=%s should_trace=%b', arg_collection_name, attribute, should_trace)
}
else
{
// console.log(context + ':should_trace_collection_item: test patterns')
Object.keys(collection).forEach(
function(arg_item_pattern)
{
if (should_trace)
{
return
}
// console.log(context + ':should_trace_collection_item: collection=%s attribute=%s loop on pattern=%s should_trace=%n', arg_collection_name, attribute, arg_item_pattern, should_trace)
// CHECK PATTERN STRING
if ( ! T.isString(arg_item_pattern) || arg_item_pattern.length < 1 )
{
// console.log(context + ':should_trace_collection_item: bad pattern=%s', arg_item_pattern)
return
}
// REGEX
if (arg_item_pattern.indexOf('*') > -1 || arg_item_pattern.indexOf('[') > -1 || arg_item_pattern.indexOf('{') > -1)
{
// console.log(context + ':should_trace_collection_item: good pattern=%s this.attribute=%s', arg_item_pattern, attribute)
// NORMALIZE PATTERN
arg_item_pattern = arg_item_pattern == '*' ? '.*' : arg_item_pattern
// console.log(context + ':should_trace_collection_item: noarmalized pattern=%s', arg_item_pattern)
// CREATE REGEX AND TEST MATCHING
const re = new RegExp(arg_item_pattern, 'gi')
const found = re.test(attribute)
if (found)
{
const should_trace_pattern = collection[arg_item_pattern]
should_trace = should_trace_pattern ? true : false
// console.log(context + ':should_trace_collection_item: collection=%s pattern=%s this.attribute=%s should_trace_pattern=%b should_trace=%b', arg_collection_name, arg_item_pattern, attribute, should_trace_pattern, should_trace)
return
}
}
}
)
}
}
return should_trace
}
/**
* Get logger manager.
* @returns {LoggerManager}
*/
get_logger_manager()
{
if (!this._logger_manager)
{
// DEBUG
console.warn(this.get_class() + ':' + this.get_name(), 'bad logger manager')
// debugger
}
assert( T.isObject(this._logger_manager) && this._logger_manager.is_logger_manager, context + ':get_logger_manager:bad logger manager object')
return this._logger_manager
}
/**
* Update trace enabled flag.
*
* @returns {nothing}
*/
update_trace_enabled()
{
const logger_mgr = this.get_logger_manager()
const traces_settings = logger_mgr.get_traces_settings()
if (traces_settings)
{
const traces_enabled = this.should_trace(traces_settings)
if (traces_enabled)
{
this.enable_trace()
// console.log(context + ':update_trace_enabled:name=%s, is_trace_enabled', this.get_name(), this.is_trace_enabled)
} else {
this.disable_trace()
}
}
}
/**
* Enable traces.
* @returns {nothing}
*/
enable_trace()
{
this.is_trace_enabled = true
// this.get_logger_manager().enable_trace()
}
/**
* Disable traces.
* @returns {nothing}
*/
disable_trace()
{
this.is_trace_enabled = false
// this.get_logger_manager().disable_trace()
}
/**
* Get trace flag.
* @returns {boolean}
*/
get_trace()
{
return this.get_logger_manager().get_trace() && this.is_trace_enabled
}
/**
* Set trace flag.
* @param {boolean} arg_value - trace flag.
* @returns {nothing}
*/
set_trace(arg_value)
{
this.is_trace_enabled = arg_value ? true : false
if (this.is_trace_enabled)
{
this.get_logger_manager().enable_trace()
}
}
/**
* Toggle trace flag.
* @returns {boolean}
*/
toggle_trace()
{
this.is_trace_enabled = ! this.is_trace_enabled
this.get_logger_manager().toggle_trace()
}
/**
* Trace DEBUG formatted message.
* @param {string|array} args - variadic messages to format.
* @returns {nothing}
*/
debug(...args)
{
if(this.is_trace_enabled)
{
this.get_logger_manager().debug(Date.now(), this.$context, this.get_name(), '', 'trace', ...args)
}
}
/**
* Trace INFO formatted message.
* @param {string|array} args - variadic messages to format.
* @returns {nothing}
*/
info(...args)
{
if(this.is_trace_enabled)
{
this.get_logger_manager().info(Date.now(), this.$context, this.get_name(), '', 'trace', ...args)
}
}
/**
* Trace WARN formatted message.
* @param {string|array} args - variadic messages to format.
* @returns {nothing}
*/
warn(...args)
{
if(this.is_trace_enabled)
{
this.get_logger_manager().warn(Date.now(), this.$context, this.get_name(), '', 'trace', ...args)
}
}
/**
* Trace ERROR formatted message.
* @param {string|array} args - variadic messages to format.
* @returns {nothing}
*/
error(...args)
{
this.get_logger_manager().error(Date.now(), this.$context, this.get_name(), '', 'trace', ...args)
console.error(Date.now(), this.$context, this.get_name(), '', 'trace', ...args)
}
/**
* Trace INFO message on "enter trace group".
* @param {string} arg_group - trace group name.
* @returns {nothing}
*/
enter_group(arg_group)
{
if(this.is_trace_enabled)
{
this.get_logger_manager().debug(Date.now(), this.$context, this.get_name(), arg_group, 'enter', '[' + arg_group + '] ------- ENTER -------')
}
}
/**
* Trace INFO message on "leave trace group".
* @param {string} arg_group - trace group name.
* @returns {nothing}
*/
leave_group(arg_group)
{
if(this.is_trace_enabled)
{
this.get_logger_manager().debug(Date.now(), this.$context, this.get_name(), arg_group, 'leave', '[' + arg_group + '] ------- LEAVE -------')
}
}
/**
* Trace INFO trace level 1 separator.
* @returns {nothing}
*/
separate_level_1()
{
if(this.is_trace_enabled)
{
this.get_logger_manager().debug(Date.now(), this.$context, this.get_name(), '', 'trace', '==========================================================================================================================')
}
}
/**
* Trace INFO trace level 2 separator.
* @returns {nothing}
*/
separate_level_2()
{
if(this.is_trace_enabled)
{
this.get_logger_manager().debug(Date.now(), this.$context, this.get_name(), '', 'trace', '--------------------------------------------------------------------------------------------------------------------------')
}
}
/**
* Trace INFO trace level 3 separator.
* @returns {nothing}
*/
separate_level_3()
{
if(this.is_trace_enabled)
{
this.get_logger_manager().debug(Date.now(), this.$context, this.get_name(), '', 'trace', '*************************************************************************************************************************')
}
}
}