Each logger object has several methods that you can use in order to interact with the logger's appenders. You can add, remove, clear or list the appenders on a specific logger instance. Below are the methods you can use in the logger class to interact with appenders:
So you can easily add/remove/check the appenders on any logger at any time.
Method
Return Type
Description
hasAppenders()
Boolean
Checks if the logger has any appenders attached to it
getAppenders()
Struct
Returns the map of registered appenders
getAppender(name)
Appender
Return a named appender if it is registered in the logger
appenderExists(name)
Boolean
Checks if a named appender exists in the logger
addAppender(Appender)
void
Register an appender with the logger at runtime
removeAppender(name)
Boolean
Will un-register an appender from this logger
removeAllAppenders()
void
Will try to un-register all appenders from this logger
We have a convention for our category names where each category name uses dot-notation according to the components path. Using a class-path convention for our category names allows one to pseudo-inherit for logging levels and appenders! The following example should help clarify this concept.
The overall premise is that when you request a logger with a category name LogBox will search for it's configuration. If LogBox does not find a configuration for the category name it will try to locate its closest ancestor for logging levels and appenders. If LogBox cannot find an ancestor the message will be logged using the root logger information. For example, let's say we define some appenders like this:
And some categories like this:
Then, let's say we request the following logger objects and logged some info:
Information All example code snippets are using a
getLogger( "categoryname" )
call instead of our preferred approach ofgetLogger( this )
because we want to showcase which category we are talking about. Please take this into consideration.
Since we requested the category: coldbox.system.plugins.BeanFactory
, LogBox tries to locate it, but it has not been defined, so it takes off the last item in the category name. Now it will search for a category of: coldbox.system.plugins
via pseudo-inheritance. However, now coldbox.system.plugins
has been found and it has been configured to only listen to error
messages. Therefore, the coldbox.system.plugins.BeanFactory
logger can ONLY log error messages according to it's inherited category. So the info()
message will be ignored, and the error()
message will be sent to both the FileAppender and the ConsoleAppender!
The second logger is called coldbox.system.interceptors.SES
, LogBox tries to match a category but fails, so it now searches for a logger called coldbox.system.interceptors
. It still cannot find it so it continues up the package chain and finds the coldbox.system
logger which has been set with a minimum of INFO
level and ONLY the console appender. So the messages that get logged is the logger.info()
and the logger.debug()
message and they will be sent to the console appender.
These examples should give you insight into category inheritance and the power they provide. You can easily turn toggle logging for entire packages with a single category definition. However, this is great only if you follow the dot notation conventions. Below is a sample generic chart sample:
Category
Configured Levels
Assigned Levels
Appenders
root
FATAL-DEBUG
FATAL-DEBUG
console,file
coldbox.system
INFO-DEBUG
INFO-DEBUG
console
coldbox.system.plugins
ERROR
ERROR
*
coldbox.system.interceptors.SES
coldbox.system.interceptors.SES
INFO-DEBUG from coldbox.system
console from coldbox.system
coldbox.system.plugins.BeanFactory
NONE
ERROR from coldbox.system.plugins
*
Category
Configured Levels
Assigned Levels
root
FATAL-DEBUG
FATAL-DEBUG
x
NONE
FATAL-DEBUG from root
x.y
INFO
INFO
x.y.z
NONE
INFO from x.y