Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
LogBox is the core framework you need to instantiate in order to work with logging in your application. You have to instantiate it with a LogBoxConfig
object that will hold your logging configurations. After the library is instantiated and configured you can ask from it a named Logger object so you can start logging or tracing messages.
You have two ways to use LogBox:
Standalone Framework
Within a ColdBox application
If you have downloaded LogBox as a standalone framework, then the initial namespace for the core is logbox.system
. This allows you to use logbox as a standalone framework that is integrated into your proprietary application.
The ColdBox Framework already has an instance of LogBox created for you in every application and it is stored in the main application controller: controller.getLogBox()
. The namespace within the ColdBox framework is coldbox.system
.
LogBox has four main components:
LogBox
Logger
Appenders
Layouts.
These four (4) components work in unison to deliver the logging and tracing of messages and to control how they are logged. You will mostly interact with the Logger component as it will send your statements to the Appenders you have configured. Users can extend LogBox and build their own appenders and layouts.
The layout component defines the format of the message to store in an appender repository. Be default, each appender already has a pre-defined message format. However, if you do not like the format of the message you can easily change it by creating your own layout component and registering it with the appender. You can do this in the configuration object when you add appenders:
Note: Not all appenders use a layout object (e.g. the
DBAppender
).
So to create your very own layout object, you just need to extend the LogBox abstract layout object: logbox.system.logging.Layout
and implement the format()
method.
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:
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.
An appender is an object that LogBox uses to log statements to a destination repository. All appenders act as destinations that can include: databases, JMS, files, consoles, sockets, etc. The appender has the responsibility of taking the logged message and persisting the message or sending the message to an external service. LogBox comes bundled with the following appenders that can be found in the package coldbox.system.logging.appenders
:
Asynchronous Appenders
You may wish your logs to be asynchronous. You can do so by passing an async
property in your configuration. ( This happens at the logger
level and is available to all appenders out of the box, even ones that you create yourself!
You can configure LogBox to use one or all of these appenders at any point in time. You can even register as many instances of any appender by defining a unique name for each. Here are examples of how one can configure appenders programmatically or via the simple configuration CFC:
Programmatic Approach
Configuration CFC approach
Another feature of a LogBox appender is that you can extend
them or create new ones simply by leveraging the LogBox API. To customize LogBox appenders for your own unique needs you would simply extend the core appender class: coldbox.system.logging.AbstractAppender
and implementing the init()
and logMessage()
methods. Extending LogBox will be reviewed in greater detail over the next few sections.
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
Appender
Description
CFAppender
Will deliver messages to the coldfusion logs.
ConsoleAppender
Will deliver messages to the server's console via system.out
DBAppender
Will deliver messages to a database table. It can auto create the table for you.
DummyAppender
An endless void of nothingness
EmailAppender
Will deliver messages to any email address.
FileAppender
Will deliver messages a file.
RollingFileAppender
A file appender that can do file rotation and archiving.
ScopeAppender
Will deliver messages to any ColdFusion variable scope.
SocketAppender
Will connect to any server socket and deliver messages.
TracerAppender
Will deliver messages to the ColdFusion tag cftrace.
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