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).
LogTargetFactorys
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
LogTargets
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
LogTargets 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
Loggers.
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
Components
implementing
Loggable.