Find Avalon Excalibur's Log Management System in the
org.apache.avalon.excalibur.logger
package.
Excalibur-Logger integrates neatly into the Avalon ECM
and Fortress. The main goal is to
be able to define the log categories on a component basis by
specifying a 'logger' attribute which denotes the log category
to use for a particular component (given the
component is
LogEnabled
or
Loggable
).
Though the documentation doesn't reflect this accurately yet (patches welcome), excalibur-logger has been updated to support other logging toolkits like jdk1.4 logging and log4j as well.
Though the documentation doesn't reflect this accurately yet (patches welcome), excalibur-logger is not just used by (or usable by) ECM. Other containers can and do make use of logger, too.
Look at this example of a component definition:
<component role="my.component.role" class="my.component.roleImpl" logger="category.subcategory"/>
And now let's have a look at a hypothetical Excalibur-Logger configuration using Logkit:
<?xml version="1.0"?> <logkit> <factories> <factory type="file" class="org.apache.avalon.excalibur.logger.factory.FileTargetFactory"/> <factory type="priority-filter" class="org.apache.avalon.excalibur.logger.factory.PriorityFilterTargetFactory"/> </factories> <targets> <file id="root"> <filename>lolo/${current-dir}/lala/${foo}/logs/main.log</filename> <format type="extended"> %7.7{priority} %5.5{time} [%8.8{category}] (%{context}): %{message}\n%{throwable} </format> <append>true</append> </file> <file id="classloader"> <filename>logs/classloader.log</filename> <format type="raw"/> </file> <priority-filter id="foo" log-level="WARN"> <file> <filename>logs/foo.log</filename> <format type="extended"> %7.7{priority} %5.5{time}: %{message}\n%{throwable} </format> </file> </priority-filter> </targets> <categories> <category name="cocoon" log-level="INFO"> <log-target id-ref="root"/> <category name="classloader" log-level="DEBUG"> <log-target id-ref="classloader"/> </category> </category> <category name="foo" log-level="DEBUG"> <log-target id-ref="foo"/> </category> </categories> </logkit>
As you've seen the configuration file for excalibur-logger when used with logkit has three sections (beside the root element).
LogTargetFactory
s
that are used to create the needed
LogTargets
. You'll
find the factories available in the
org.apache.avalon.excalibur.logger.factory
package. You can write your own factories which
only needs to implement the
org.apache.avalon.excalibur.logger.LogTargetFactory
interface or you extend one of the available factories
in the mentioned package.
LogTargets
.
The element name of a target definition corresponds
to a type attribute of a <factory> element. You'll
probably need to consult the javadocs of the corresponding
factory to get familiar with the configuration
options available for a particular target.
Logger
of that category. <category>
elements have <log-targets> children which, you
already guessed, defines the
LogTarget
s
for a particular logging category. You'll also see in the
sample above that category elements can be nested to define
sub-categories.
The first abstraction is the
LogKitManager
:
public interface LogKitManager { Logger getLogger( String categoryName ); }
There is a implementation named
DefaultLogKitManager
which is the only class exposed to clients. As a convenient a
additional interface is introduced for the
ComponentManager
(stolen from the role management
system) which states that a class is willing to get a
LogKitManager
:
public interface LogKitManageable { void setLogKitManager( LogKitManager logmanager ); }
This method has to be called before the configure method but after the contextualize method.
The
DefaultLogKitManager
is
Configurable
(as well as
Loggable
[the initial default logger] and
Contextualizable
[to pass along for ie.
ServletOutputLogTarget
]) and gets a
Configuration
object as expressed in the logkit
xml syntax above. This
DefaultLogKitManager
then uses
a object of type
public interface LogTargetFactoryManager { LogTargetFactory getLogTargetFactory( String factoryName ); }
The
DefaultLogTargetFactoryManager
is
Configurable
(as well as
Loggable
and
Contextualizable
) and gets the
Configuration
object located at the <factories>
element. It will instanciate the concrete factories into a map
keyed by the type attribute. So we are at the
LogTargetFactory
abstraction which is:
public interface LogTargetFactory { LogTarget createTarget( Configuration configuration ) throws ConfigurationException; }
It may happen that a
LogTargetFactory
needs to
create
LogTarget
s they don't know in advance
and thus an additional interface is needed:
public interface LogTargetFactoryManageable { void setLogTargetFactoryManager( LogTargetFactoryManager logTargetFactoryManager ); }
This eases writing factories which acts like decorators
(
AsyncLogTarget
,
PriorityFilter
)
and thus need a LogTargetFactoryManager to create the decorated
LogTargets
which are embeded in the configuration
of them (see <priority-filter> above).
After initializing the
LogTargetFactoryManager
a
LogTargetManager
public interface LogTargetManager { LogTarget getLogTarget( String targetId ); }
is created. The implementation
DefaultLogTargetManager
is, you guess it,
Configurable
(as well as
Loggable
and
Contextualizable
). The
Configuration
object is the <targets> element
in the xml syntax and is put into a map keyed by the id
attribute of the target element. It is also
LogTargetFactoryManageable
tob e able to create
the
LogTargets
.
The last step of the
DefaultLogKitManagers
configure
method is to create the actual categories based on the categories
elements content. It does it as the syntax will show in a
recursive way populating the Loggers retrieved by
Hierarchy.getDefaultHierarchy().getLoggerFor( full_category )
with the denoted
LogTargets
from the
LogTargetManager
.
After that the
LogKitManager
is ready to be asked
for
Logger
s.
Now ECM is aware of a
"magic attributes" named logger and used like
logger="category"
on the component definition syntax.
The classes building up ECM
are made
LogTargetFactoryManageable
. If you pass along
a
LogKitManager
to the
ExcaliburComponentManager
it will retrieve the denoted logger
category specified with the logger attribute from the
LogKitManager
and pass it to
Component
s
implementing
Loggable
.