FileDocCategorySizeDatePackage
LogManager.javaAPI DocAndroid 1.5 API23506Wed May 06 22:41:04 BST 2009java.util.logging

LogManager

public class LogManager extends Object
{@code LogManager} is used to maintain configuration properties of the logging framework, and to manage a hierarchical namespace of all named {@code Logger} objects.

There is only one global {@code LogManager} instance in the application, which can be get by calling static method {@link #getLogManager()}. This instance is created and initialized during class initialization and cannot be changed.

The {@code LogManager} class can be specified by java.util.logging.manager system property, if the property is unavailable or invalid, the default class {@link java.util.logging.LogManager} will be used.

When initialization, {@code LogManager} read its configuration from a properties file, which by default is the "lib/logging.properties" in the JRE directory.

However, two optional system properties can be used to customize the initial configuration process of {@code LogManager}.

  • "java.util.logging.config.class"
  • "java.util.logging.config.file"

These two properties can be set in three ways, by the Preferences API, by the "java" command line property definitions, or by system property definitions passed to JNI_CreateJavaVM.

The "java.util.logging.config.class" should specifies a class name. If it is set, this given class will be loaded and instantiated during {@code LogManager} initialization, so that this object's default constructor can read the initial configuration and define properties for {@code LogManager}.

If "java.util.logging.config.class" property is not set, or it is invalid, or some exception is thrown during the instantiation, then the "java.util.logging.config.file" system property can be used to specify a properties file. The {@code LogManager} will read initial configuration from this file.

If neither of these properties is defined, or some exception is thrown during these two properties using, the {@code LogManager} will read its initial configuration from default properties file, as described above.

The global logging properties may include:

  • "handlers". This property's values should be a list of class names for handler classes separated by whitespace, these classes must be subclasses of {@code Handler} and each must have a default constructor, these classes will be loaded, instantiated and registered as handlers on the root {@code Logger} (the {@code Logger} named ""). These {@code Handler}s maybe initialized lazily.
  • "config". The property defines a list of class names separated by whitespace. Each class must have a default constructor, in which it can update the logging configuration, such as levels, handlers, or filters for some logger, etc. These classes will be loaded and instantiated during {@code LogManager} configuration

This class, together with any handler and configuration classes associated with it, must be loaded from the system classpath when {@code LogManager} configuration occurs.

Besides global properties, the properties for loggers and Handlers can be specified in the property files. The names of these properties will start with the complete dot separated names for the handlers or loggers.

In the {@code LogManager}'s hierarchical namespace, {@code Loggers} are organized based on their dot separated names. For example, "x.y.z" is child of "x.y".

Levels for {@code Loggers} can be defined by properties whose name end with ".level". Thus "alogger.level" defines a level for the logger named as "alogger" and for all its children in the naming hierarchy. Log levels properties are read and applied in the same order as they are specified in the property file. The root logger's level can be defined by the property named as ".level".

All methods on this type can be taken as being thread safe.

Fields Summary
private static final String
lineSeparator
private static final LoggingPermission
perm
static LogManager
manager
public static final String
LOGGING_MXBEAN_NAME
The {@code String} value of the {@link LoggingMXBean}'s ObjectName.
private Hashtable
loggers
private Properties
props
private PropertyChangeSupport
listeners
Constructors Summary
protected LogManager()
Default constructor. This is not public because there should be only one {@code LogManager} instance, which can be get by {@code LogManager.getLogManager(}. This is protected so that application can subclass the object.

        // init LogManager singleton instance
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            public Object run() {
                String className = System.getProperty(
                        "java.util.logging.manager"); //$NON-NLS-1$
                
                if (null != className) {
                    manager = (LogManager) getInstanceByClass(className);
                }
                if (null == manager) {
                    manager = new LogManager();
                }

                // read configuration
                try {
                    manager.readConfiguration();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                // if global logger has been initialized, set root as its parent
                Logger root = new Logger("", null); //$NON-NLS-1$
                root.setLevel(Level.INFO);
                Logger.global.setParent(root);
                
                manager.addLogger(root);
                manager.addLogger(Logger.global);
                return null;
            }
        });
    
        loggers = new Hashtable<String, Logger>();
        props = new Properties();
        listeners = new PropertyChangeSupport(this);
        // add shutdown hook to ensure that the associated resource will be
        // freed when JVM exits
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
                Runtime.getRuntime().addShutdownHook(new Thread() {
                    @Override
                    public void run() {
                        reset();
                    }
                });
                return null;
            }
        });
    
Methods Summary
public synchronized booleanaddLogger(java.util.logging.Logger logger)
Add a given logger into the hierarchical namespace. The {@code Logger.addLogger()} factory methods call this method to add newly created Logger. This returns false if a logger with the given name has existed in the namespace

Note that the {@code LogManager} may only retain weak references to registered loggers. In order to prevent {@code Logger} objects from being unexpectedly garbage collected it is necessary for applications to maintain references to them.

param
logger the logger to be added.
return
true if the given logger is added into the namespace successfully, false if the given logger exists in the namespace.

        String name = logger.getName();
        if (null != loggers.get(name)) {
            return false;
        }
        addToFamilyTree(logger, name);
        loggers.put(name, logger);
        logger.setManager(this);
        return true;
    
public voidaddPropertyChangeListener(java.beans.PropertyChangeListener l)
Add a {@code PropertyChangeListener}, which will be invoked when the properties are reread.

param
l the {@code PropertyChangeListener} to be added.
throws
SecurityException if security manager exists and it determines that caller does not have the required permissions to perform this action.

        if(l == null){
            throw new NullPointerException();
        }
        checkAccess();
        listeners.addPropertyChangeListener(l);
    
private voidaddToFamilyTree(java.util.logging.Logger logger, java.lang.String name)

        Logger parent = null;
        // find parent
        int lastSeparator;
        String parentName = name;
        while ((lastSeparator = parentName.lastIndexOf('.")) != -1) {
            parentName = parentName.substring(0, lastSeparator);
            parent = loggers.get(parentName);
            if (parent != null) {
                logger.internalSetParent(parent);
                break;
            } else if (getProperty(parentName+".level") != null || //$NON-NLS-1$
                    getProperty(parentName+".handlers") != null) { //$NON-NLS-1$
                parent = Logger.getLogger(parentName);
                logger.internalSetParent(parent);
                break;
            }
        }
        if (parent == null && null != (parent = loggers.get(""))) { //$NON-NLS-1$
            logger.internalSetParent(parent);
        }

        // find children
        //TODO: performance can be improved here?
        Collection<Logger> allLoggers = loggers.values();
        for (Logger child : allLoggers) {
            Logger oldParent = child.getParent();
            if (parent == oldParent
                    && (name.length() == 0 || child.getName().startsWith(
                            name + '."))) {
                child.setParent(logger);
                if (null != oldParent) {
                    //-- remove from old parent as the parent has been changed
                    oldParent.removeChild(child);
                }
            }
        }
    
public voidcheckAccess()
Check that the caller has {@code LoggingPermission("control")} so that it is trusted to modify the configuration for logging framework. If the check passes, just return, otherwise {@code SecurityException} will be thrown.

throws
SecurityException if there is a security manager in operation and the invoker of this method does not have the required security permission {@code LoggingPermission("control")}

        if (null != System.getSecurityManager()) {
            System.getSecurityManager().checkPermission(perm);
        }
    
static java.lang.ObjectgetInstanceByClass(java.lang.String className)

        try {
            Class<?> clazz = ClassLoader.getSystemClassLoader().loadClass(
                    className);
            return clazz.newInstance();
        } catch (Exception e) {
            try {
                Class<?> clazz = Thread.currentThread()
                        .getContextClassLoader().loadClass(className);
                return clazz.newInstance();
            } catch (Exception innerE) {
                //logging.20=Loading class "{0}" failed
                System.err.println(Messages.getString(
                        "logging.20", className)); //$NON-NLS-1$
                System.err.println(innerE);
                return null;
            }
        }

    
public static java.util.logging.LogManagergetLogManager()
Get the global {@code LogManager} instance.

return
the global {@code LogManager} instance

        return manager;
    
public synchronized java.util.logging.LoggergetLogger(java.lang.String name)
Get the logger with the given name.

param
name name of logger
return
logger with given name, or {@code null} if nothing is found.

        return loggers.get(name);
    
public synchronized java.util.EnumerationgetLoggerNames()
Get a {@code Enumeration} of all registered logger names.

return
enumeration of registered logger names

        return loggers.keys();
    
public static java.util.logging.LoggingMXBeangetLoggingMXBean()
Get the {@code LoggingMXBean} instance. this implementation always throws an UnsupportedOperationException.

return
the {@code LoggingMXBean} instance

 //$NON-NLS-1$

                          
        
        // BEGIN android-added
        throw new UnsupportedOperationException();
        // END android-added        
        // BEGIN android-removed
        // try {
        //     ObjectName loggingMXBeanName = new ObjectName(LOGGING_MXBEAN_NAME);
        //     MBeanServer platformBeanServer =
        //             ManagementFactory.getPlatformMBeanServer();
        //     Set loggingMXBeanSet = platformBeanServer.queryMBeans(
        //             loggingMXBeanName, null);
        // 
        //     if (loggingMXBeanSet.size() != 1) {
        //         // logging.21=There Can Be Only One logging MX bean.
        //         throw new AssertionError(Messages.getString("logging.21"));
        //     }
        //
        //     Iterator i = loggingMXBeanSet.iterator();
        //     ObjectInstance loggingMXBeanOI = (ObjectInstance) i.next();
        //     String lmxbcn = loggingMXBeanOI.getClassName();
        //     Class lmxbc = Class.forName(lmxbcn);
        //     Method giMethod = lmxbc.getDeclaredMethod("getInstance");
        //     giMethod.setAccessible(true);
        //     LoggingMXBean lmxb = (LoggingMXBean)
        //             giMethod.invoke(null, new Object[] {});
        //
        //     return lmxb;
        // } catch (Exception e) {
        //     //TODO
        //     //e.printStackTrace();
        // }
        // // logging.22=Exception occurred while getting the logging MX bean.
        // throw new AssertionError(Messages.getString("logging.22")); //$NON-NLS-1$
        // END android-removed
     
static java.lang.StringgetPrivilegedSystemProperty(java.lang.String key)

        return AccessController.doPrivileged(new PrivilegedAction<String>() {
            public String run() {
                return System.getProperty(key);
            }
        });
    
public java.lang.StringgetProperty(java.lang.String name)
Get the value of property with given name.

param
name the name of property
return
the value of property

        return props.getProperty(name);
    
static java.lang.StringgetSystemLineSeparator()

        return lineSeparator;
    
public voidreadConfiguration()
Re-initialize the properties and configuration. The initialization process is same as the {@code LogManager} instantiation.

Notice : No {@code PropertyChangeEvent} are fired.

throws
IOException if any IO related problems happened.
throws
SecurityException if security manager exists and it determines that caller does not have the required permissions to perform this action.

        checkAccess();
        // check config class
        String configClassName = System.getProperty(
                "java.util.logging.config.class"); //$NON-NLS-1$
        if (null == configClassName || null == getInstanceByClass(configClassName)) {
            // if config class failed, check config file       
            String configFile = System.getProperty(
                    "java.util.logging.config.file"); //$NON-NLS-1$

            if (null == configFile) {
                // if cannot find configFile, use default logging.properties
                configFile = new StringBuilder().append(
                        System.getProperty("java.home")).append(File.separator) //$NON-NLS-1$
                        .append("lib").append(File.separator).append( //$NON-NLS-1$
                        "logging.properties").toString(); //$NON-NLS-1$
            }

            InputStream input = null;
            try {
                // BEGIN android-removed
                // input = new BufferedInputStream(new FileInputStream(configFile));
                // END android-removed
                
                // BEGIN android-added
                try {
                    input = new BufferedInputStream(
                            new FileInputStream(configFile), 8192);
                } catch (Exception ex) {
                    // consult fixed resource as a last resort
                    input = new BufferedInputStream(
                            getClass().getResourceAsStream(
                                    "logging.properties"), 8192);
                }
                // END android-added
                readConfigurationImpl(input);
            } finally {
                if (input != null) {
                    try {
                        input.close();
                    } catch (Exception e) {// ignore
                    }
                }
            }
        }
    
public voidreadConfiguration(java.io.InputStream ins)
Re-initialize the properties and configuration from the given {@code InputStream}

Notice : No {@code PropertyChangeEvent} are fired.

param
ins the input stream
throws
IOException if any IO related problems happened.
throws
SecurityException if security manager exists and it determines that caller does not have the required permissions to perform this action.

        checkAccess();
        readConfigurationImpl(ins);
    
private synchronized voidreadConfigurationImpl(java.io.InputStream ins)

        reset();
        props.load(ins);
        
        // parse property "config" and apply setting
        String configs = props.getProperty("config"); //$NON-NLS-1$
        if (null != configs) {
            StringTokenizer st = new StringTokenizer(configs, " "); //$NON-NLS-1$
            while (st.hasMoreTokens()) {
                String configerName = st.nextToken();
                getInstanceByClass(configerName);
            }
        }
        
        // set levels for logger
        Collection<Logger> allLoggers = loggers.values();
        for(Logger logger : allLoggers){
            String property = props.getProperty(
                    logger.getName()+".level"); //$NON-NLS-1$
            if(null != property){
                logger.setLevel(Level.parse(property));
            }
        }
        listeners.firePropertyChange(null, null, null);
    
public voidremovePropertyChangeListener(java.beans.PropertyChangeListener l)
Remove a {@code PropertyChangeListener}, do nothing if the given listener is not found.

param
l the {@code PropertyChangeListener} to be removed.
throws
SecurityException if security manager exists and it determines that caller does not have the required permissions to perform this action.

        checkAccess();
        listeners.removePropertyChangeListener(l);
    
public voidreset()
Reset configuration.

All handlers are closed and removed from any named loggers. All loggers' level is set to null, except the root logger's level is set to {@code Level.INFO}.

throws
SecurityException if security manager exists and it determines that caller does not have the required permissions to perform this action.

        checkAccess();
        props = new Properties();
        Enumeration<String> names = getLoggerNames();
        while(names.hasMoreElements()){
            String name = names.nextElement();
            Logger logger = getLogger(name);
            if(logger != null){
                logger.reset();
            }
        }
        Logger root = loggers.get(""); //$NON-NLS-1$
        if (null != root) {
            root.setLevel(Level.INFO);
        }