Excalibur Logger - OverviewIntroductionFind 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). Not just for logkitThough 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. Not just for ECMThough 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. Example configurationsLook 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).
Design principles and implementation details of Excalibur-LoggerThe 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. |