All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.avalon.excalibur.logger.LogKitLoggerManager Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed  under the  License is distributed on an "AS IS" BASIS,
 * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
 * implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
package org.apache.avalon.excalibur.logger;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.avalon.excalibur.logger.util.LoggerUtil;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.container.ContainerUtil;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.LogKitLogger;
import org.apache.avalon.framework.logger.Logger;
import org.apache.log.ErrorHandler;
import org.apache.log.Hierarchy;
import org.apache.log.LogEvent;
import org.apache.log.LogTarget;
import org.apache.log.Priority;
import org.apache.log.util.Closeable;

/**
 * LogKitLoggerManager implementation.  It populates the LoggerManager
 * from a configuration file.
 *
 * @author Avalon Development Team
 * @version SVN $Id$
 * @since 4.0
 */
public class LogKitLoggerManager extends AbstractLoggerManager
    implements LoggerManager, Contextualizable, Configurable, Disposable
{
    /** Set of log targets */
    final private Set m_targets = new HashSet();

    /** The context object */
    private Context m_context;

    /** The hierarchy private to LogKitManager */
    private final Hierarchy m_hierarchy;

    /**
     * Creates a new LogKitLoggerManager;
     * one of the preferred constructors.
     * Please also invoke enableLogging()
     * to supply a fallback logger.
     */
    public LogKitLoggerManager()
    {
        this( (String)null, (Hierarchy)null, (String)null, (Logger)null, (Logger)null );
    }

    /**
     * Creates a new LogKitLoggerManager;
     * one of the preferred constructors.
     * Please also invoke enableLogging()
     * to supply a fallback logger.
     *
     * @param prefix to prepended to category name on each
     *         invocation of getLoggerForCategory().
     */
    public LogKitLoggerManager( final String prefix )
    {
        this( prefix, (Hierarchy)null, (String)null, (Logger)null, (Logger)null );
    }

    /**
     * Creates a new LogKitLoggerManager;
     * one of the preferred constructors,
     * intended for the widest usage.
     *
     * Please also invoke enableLogging()
     * to supply a fallback logger.
     * 

* Example: *

     * LogKitLoggerManager l = new LogKitLoggerManager( "fortress", "system.logkit" );
     * l.enableLogging( bootstrapLogger );
     * l.configure( loggerManagerConfiguration );
     * 
* * @param prefix to prepended to category name on each * invocation of getLoggerForCategory(). * @param switchToCategory if this parameter is not null * after start() * LogKitLoggerManager will start * to log its own debug and error messages to * a logger obtained via * this.getLoggerForCategory( switchToCategory ). * Note that prefix will be prepended to * the value of switchToCategory also. */ public LogKitLoggerManager( final String prefix, final String switchToCategory ) { this( prefix, (Hierarchy)null, switchToCategory, (Logger)null, (Logger)null ); } /** * Creates a new LogKitLoggerManager * with an existing Hierarchy; * use with caution. * * Please also invoke enableLogging() * to supply a fallback logger. * See comments on the root constructor * for details on why constructors supplying an existing hierarchy * should be used with caution. * * @param prefix to prepended to category name on each * invocation of getLoggerForCategory(). * @param switchToCategory if this parameter is not null * after start() * LogKitLoggerManager will start * to log its own debug and error messages to * a logger obtained via * this.getLoggerForCategory( switchToCategory ). * Note that prefix will be prepended to * the value of switchToCategory also. */ public LogKitLoggerManager( final String prefix, final Hierarchy hierarchy, final String switchToCategory ) { this( prefix, hierarchy, switchToCategory, (Logger)null, (Logger)null ); } /** * Creates a new LogKitLoggerManager * with an existing Hierarchy; * use with caution. * * Please also invoke enableLogging() * to supply a fallback logger. * See comments on the root constructor * for details on why constructors supplying an existing hierarchy * should be used with caution. */ public LogKitLoggerManager( final Hierarchy hierarchy ) { this( (String)null, hierarchy, (String)null, (Logger)null, (Logger)null ); } /** * Creates a new LogKitLoggerManager * with an existing Hierarchy; * use with caution. * * Please also invoke enableLogging() * to supply a fallback logger. * See comments on the root constructor * for details on why constructors supplying an existing hierarchy * should be used with caution. * * @param prefix to prepended to category name on each * invocation of getLoggerForCategory(). */ public LogKitLoggerManager( final String prefix, final Hierarchy hierarchy ) { this( prefix, hierarchy, (String)null, (Logger)null, (Logger)null ); } /** * Creates a new LogKitLoggerManager * with an existing Hierarchy using * specified logger name as a fallback logger and to * forcibly override the root logger; * compatibility constructor. * * The configuration for the "" * category in the configuration will supply the defaults for * all other categories, but getDefaultLogger() * and getLoggerForCategory() will still * use logger supplied by this constructor. * *

* See comments on the root constructor * for details on why constructors supplying an existing hierarchy * should be used with caution. * *

* As this constructor provides a logger to be used as a fallback * a subsequent enableLogging() stage is unnecessary. * Moreover, it will fail. * * @param prefix to prepended to category name on each * invocation of getLoggerForCategory(). * @param defaultOverrideAndFallback the logger used to * a) forcibly * override the root logger that will further be obtained from * the configuration and b) as the fallback logger. Note that * specifying a logger as this parameter crucially differs from * supplying it via enableLogging(). The logger * supplied via enableLogging will only be used * as the fallback logger and to log messages during initialization * while this constructor argument also has the described * override semantics. */ public LogKitLoggerManager( final String prefix, final Hierarchy hierarchy, final Logger defaultOverrideAndFallback ) { this( prefix, hierarchy, (String)null, defaultOverrideAndFallback, defaultOverrideAndFallback ); } /** * Creates a new LogKitLoggerManager * with an existing Hierarchy using * specified loggers to forcibly override * the default logger and to provide a fallback logger; * compatibility constructor. * * See comments on the root constructor * for details on why constructors supplying an existing hierarchy * should be used with caution. *

* As this constructor provides a logger to be used as a fallback * a subsequent enableLogging() stage is unnecessary. * Moreover, it will fail. * * @param prefix to prepended to category name on each * invocation of getLoggerForCategory(). * @param defaultLoggerOverride the logger to be used to forcibly * override the root logger that will further be obtained from * the configuration * @param fallbackLogger the logger to as a fallback logger * (passing non-null as this argument eliminates the need * to invoke enableLogging()) */ public LogKitLoggerManager( final String prefix, final Hierarchy hierarchy, final Logger defaultLoggerOverride, final Logger fallbackLogger ) { this( prefix, hierarchy, (String)null, defaultLoggerOverride, fallbackLogger ); } /** * * * Creates a new LogKitLoggerManager; * "root" constructor invoked by all other constructors. *

* * If the hierarchy parameter is not null * this instructs this constructor to use an existing hierarchy * instead of creating a new one. This also disables removing * the default log target configured by the Hierarchy() * constructor (this target logs to System.out) and * installing our own ErrorHandler for our * Hierarchy (the default ErrorHandler * writes to System.err). *

* The configuration of the resulting Hierarchy * is a combination of the original configuraiton that * existed when this Hierarchy was handled to us * and the configuration supplied to use via configure(). * LogTargets for those categories for which a * configuration node has been supplied in the configuration * supplied via configure() are replaced during * the configure() process. LogTargets * for those categories for which configuration nodes have * not been supplied are left as they were. A special case * is when a node in configuration for a category exists but * it does not enlist log targets. In this case the original * targets if any are left as they were. * *

* Generally it is preferrable to *

* That's why it is preferrable to pass null * for the hierarchy parameter of this constructor * or, which is easier to read but has the same effect, to * invoke a constructor which does not accept a Hierarchy * argument. *

* *

The defaultLoggerOverride and fallbackLogger * are a special case too. defaultLoggerOverride * forcibly overrides * the root logger configured via configure(). * As there is little reason to take away users's freedom to configure * whatever he likes as the default logger, it is preferrable to pass * null for this parameter or better still to invoke * a constructor without Logger parameters at all.

* *

There is nothing wrong with passing fallbackLogger * via this constructor, but as this constructor is not convinient to * be invoked (too many arguments, some of them likely to be null) and the * {@link #LogKitLoggerManager(String,Hierarchy,Logger)} * constructor is broken * in using its Logger argument both as * fallbackLogger (which is okay) and as * a defaultLoggerOverride (which is probably not * desired for the reasons given above) it is preferrable not to * specify a logger * as a constructor argument but rather supply it via * enableLogging() call, like this happens with all * other normal Avalon components after all. * * @param prefix to prepended to category name on each * invocation of getLoggerForCategory(). * @param switchToCategory if this parameter is not null * after start() * LogKitLoggerManager will start * to log its own debug and error messages to * a logger obtained via * this.getLoggerForCategory( switchToCategory ). * Note that prefix will be prepended to * the value of switchToCategory also. * @param defaultLoggerOverride the logger to be used to * forcibly override * the root logger that would further be obtained from * the configuration * @param fallbackLogger the logger to as a fallback logger * (passing non-null as this argument eliminates the need * to invoke enableLogging()) */ public LogKitLoggerManager( final String prefix, final Hierarchy hierarchy, final String switchToCategory, final Logger defaultLoggerOverride, final Logger fallbackLogger ) { super( prefix, switchToCategory, defaultLoggerOverride ); m_prefix = prefix; if ( hierarchy == null ) { m_hierarchy = new Hierarchy(); m_hierarchy.getRootLogger().unsetLogTargets( true ); final ErrorHandler errorHandler = new OurErrorHandler( getLogger() ); m_hierarchy.setErrorHandler( errorHandler ); } else { m_hierarchy = hierarchy; } if ( fallbackLogger != null ) { this.enableLogging( fallbackLogger ); } } /** * Reads a context object that will be supplied to the log target factory manager. * * @param context The context object. * @throws ContextException if the context is malformed */ public final void contextualize( final Context context ) throws ContextException { m_context = context; } /** * Actually create a logger for the given category. * The result will be cached by * AbstractLoggerManager.getLoggerForCategory(). */ protected Logger doGetLoggerForCategory( final String fullCategoryName ) { return new LogKitLogger( m_hierarchy.getLoggerFor( fullCategoryName ) ); } /** * Reads a configuration object and creates the category mapping. * * @param configuration The configuration object. * @throws ConfigurationException if the configuration is malformed */ public void configure( final Configuration configuration ) throws ConfigurationException { final Configuration factories = configuration.getChild( "factories" ); final LogTargetFactoryManager targetFactoryManager = setupTargetFactoryManager( factories ); final Configuration targets = configuration.getChild( "targets" ); final LogTargetManager targetManager = setupTargetManager( targets, targetFactoryManager ); final Configuration categories = configuration.getChild( "categories" ); final Configuration[] category = categories.getChildren( "category" ); setupLoggers( targetManager, m_prefix, category, true, categories.getAttributeAsBoolean( "additive", false ) ); } /** * Setup a LogTargetFactoryManager * * @param configuration The configuration object. * @throws ConfigurationException if the configuration is malformed */ private final LogTargetFactoryManager setupTargetFactoryManager( final Configuration configuration ) throws ConfigurationException { final DefaultLogTargetFactoryManager targetFactoryManager = new DefaultLogTargetFactoryManager(); ContainerUtil.enableLogging( targetFactoryManager, getLogger() ); try { ContainerUtil.contextualize( targetFactoryManager, m_context ); } catch( final ContextException ce ) { throw new ConfigurationException( "cannot contextualize default factory manager", ce ); } ContainerUtil.configure( targetFactoryManager, configuration ); return targetFactoryManager; } /** * Setup a LogTargetManager * * @param configuration The configuration object. * @throws ConfigurationException if the configuration is malformed */ private final LogTargetManager setupTargetManager( final Configuration configuration, final LogTargetFactoryManager targetFactoryManager ) throws ConfigurationException { final DefaultLogTargetManager targetManager = new DefaultLogTargetManager(); ContainerUtil.enableLogging( targetManager, getLogger() ); targetManager.setLogTargetFactoryManager( targetFactoryManager ); ContainerUtil.configure( targetManager, configuration ); return targetManager; } /** * Setup Loggers * * @param categories [] The array object of configurations for categories. * @param root shows if we're processing the root of the configuration * @throws ConfigurationException if the configuration is malformed */ private final void setupLoggers( final LogTargetManager targetManager, final String parentCategory, final Configuration[] categories, boolean root, final boolean defaultAdditive ) throws ConfigurationException { boolean rootLoggerAlive = false; for( int i = 0; i < categories.length; i++ ) { final String category = categories[ i ].getAttribute( "name" ); final String fullCategory = LoggerUtil.getFullCategoryName( parentCategory, category ); final String loglevel = categories[ i ].getAttribute( "log-level" ).toUpperCase(); final boolean additive = categories[ i ]. getAttributeAsBoolean( "additive", defaultAdditive ); final Configuration[] targets = categories[ i ].getChildren( "log-target" ); final LogTarget[] logTargets = new LogTarget[ targets.length ]; for( int j = 0; j < targets.length; j++ ) { final String id = targets[ j ].getAttribute( "id-ref" ); logTargets[ j ] = targetManager.getLogTarget( id ); if (logTargets[ j ] == null) { throw new ConfigurationException("Category <" + fullCategory + ">: " + "Target <" + id + "> is not defined."); } if( !m_targets.contains( logTargets[ j ] ) ) { m_targets.add( logTargets[ j ] ); } } if( root && "".equals( category ) && logTargets.length > 0 ) { m_hierarchy.setDefaultPriority( Priority.getPriorityForName( loglevel ) ); m_hierarchy.setDefaultLogTargets( logTargets ); rootLoggerAlive = true; } final org.apache.log.Logger logger = m_hierarchy.getLoggerFor( fullCategory ); m_loggers.put( fullCategory, new LogKitLogger( logger ) ); if( getLogger().isDebugEnabled() ) { getLogger().debug( "added logger for category " + fullCategory ); } logger.setPriority( Priority.getPriorityForName( loglevel ) ); logger.setLogTargets( logTargets ); logger.setAdditivity( additive ); final Configuration[] subCategories = categories[ i ].getChildren( "category" ); if( null != subCategories ) { setupLoggers( targetManager, fullCategory, subCategories, false, defaultAdditive ); } } if ( root && !rootLoggerAlive ) { final String message = "No log targets configured for the root logger."; throw new ConfigurationException( message ); } } /** * Closes all our LogTargets. */ public void dispose() { final Iterator iterator = m_targets.iterator(); while( iterator.hasNext() ) { final LogTarget target = (LogTarget)iterator.next(); if( target instanceof Closeable ) { ( (Closeable)target ).close(); } } } private static class OurErrorHandler implements ErrorHandler { /** * This will be initialized to an instance of LoggerSwitch.SwitchingLogger; * that is really reliable. */ private Logger m_reliableLogger; OurErrorHandler( final Logger reliableLogger ) { if ( reliableLogger == null ) { throw new NullPointerException( "reliableLogger" ); } m_reliableLogger = reliableLogger; } public void error( final String message, final Throwable throwable, final LogEvent event ) { // let them know we're not OK m_reliableLogger.fatalError( message, throwable ); // transmit the original error final Priority p = event.getPriority(); final String nestedMessage = "nested log event: " + event.getMessage(); if ( p == Priority.DEBUG ) { m_reliableLogger.debug( nestedMessage, event.getThrowable() ); } else if ( p == Priority.INFO ) { m_reliableLogger.info( nestedMessage, event.getThrowable() ); } else if ( p == Priority.WARN ) { m_reliableLogger.warn( nestedMessage, event.getThrowable() ); } else if ( p == Priority.ERROR ) { m_reliableLogger.error( nestedMessage, event.getThrowable() ); } else if ( p == Priority.FATAL_ERROR) { m_reliableLogger.fatalError( nestedMessage, event.getThrowable() ); } else { /** This just plainly can't happen :-)*/ m_reliableLogger.error( "unrecognized priority " + nestedMessage, event.getThrowable() ); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy