📄 logmanager.java
字号:
/* * @(#)LogManager.java 1.28 04/06/08 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package java.util.logging;import java.io.*;import java.util.*;import java.security.*;import java.beans.PropertyChangeListener;import java.beans.PropertyChangeSupport;import java.net.URL;import sun.security.action.GetPropertyAction;/** * There is a single global LogManager object that is used to * maintain a set of shared state about Loggers and log services. * <p> * This LogManager object: * <ul> * <li> Manages a hierarchical namespace of Logger objects. All * named Loggers are stored in this namespace. * <li> Manages a set of logging control properties. These are * simple key-value pairs that can be used by Handlers and * other logging objects to configure themselves. * </ul> * <p> * The global LogManager object can be retrieved using LogManager.getLogManager(). * The LogManager object is created during class initialization and * cannot subsequently be changed. * <p> * At startup the LogManager class is located using the * java.util.logging.manager system property. * <p> * By default, the LogManager reads its initial configuration from * a properties file "lib/logging.properties" in the JRE directory. * If you edit that property file you can change the default logging * configuration for all uses of that JRE. * <p> * In addition, the LogManager uses two optional system properties that * allow more control over reading the initial configuration: * <ul> * <li>"java.util.logging.config.class" * <li>"java.util.logging.config.file" * </ul> * These two properties may be set via the Preferences API, or as * command line property definitions to the "java" command, or as * system property definitions passed to JNI_CreateJavaVM. * <p> * If the "java.util.logging.config.class" property is set, then the * property value is treated as a class name. The given class will be * loaded, an object will be instantiated, and that object's constructor * is responsible for reading in the initial configuration. (That object * may use other system properties to control its configuration.) The * alternate configuration class can use <tt>readConfiguration(InputStream)</tt> * to define properties in the LogManager. * <p> * If "java.util.logging.config.class" property is <b>not</b> set, * then the "java.util.logging.config.file" system property can be used * to specify a properties file (in java.util.Properties format). The * initial logging configuration will be read from this file. * <p> * If neither of these properties is defined then, as described * above, the LogManager will read its initial configuration from * a properties file "lib/logging.properties" in the JRE directory. * <p> * The properties for loggers and Handlers will have names starting * with the dot-separated name for the handler or logger. * <p> * The global logging properties may include: * <ul> * <li>A property "handlers". This defines a whitespace separated * list of class names for handler classes to load and register as * handlers on the root Logger (the Logger named ""). Each class * name must be for a Handler class which has a default constructor. * Note that these Handlers may be created lazily, when they are * first used. * * <li>A property "config". This property is intended to allow * arbitrary configuration code to be run. The property defines a * whitespace separated list of class names. A new instance will be * created for each named class. The default constructor of each class * may execute arbitrary code to update the logging configuration, such as * setting logger levels, adding handlers, adding filters, etc. * </ul> * <p> * Note that all classes loaded during LogManager configuration must * be on the system class path. That includes the LogManager class, * any config classes, and any handler classes. * <p> * Loggers are organized into a naming hierarchy based on their * dot separated names. Thus "a.b.c" is a child of "a.b", but * "a.b1" and a.b2" are peers. * <p> * All properties whose names end with ".level" are assumed to define * log levels for Loggers. Thus "foo.level" defines a log level for * the logger called "foo" and (recursively) for any of its children * in the naming hierarchy. Log Levels are applied in the order they * are defined in the properties file. Thus level settings for child * nodes in the tree should come after settings for their parents. * The property name ".level" can be used to set the level for the * root of the tree. * <p> * All methods on the LogManager object are multi-thread safe. * * @version 1.28, 06/08/04 * @since 1.4*/public class LogManager { // The global LogManager object private static LogManager manager; private final static Handler[] emptyHandlers = { }; private Properties props = new Properties(); private PropertyChangeSupport changes = new PropertyChangeSupport(LogManager.class); private final static Level defaultLevel = Level.INFO; // Table of known loggers. Maps names to Loggers. private Hashtable loggers = new Hashtable(); // Tree of known loggers private LogNode root = new LogNode(null); private Logger rootLogger; // Have we done the primordial reading of the configuration file? // (Must be done after a suitable amount of java.lang.System // initialization has been done) private volatile boolean readPrimordialConfiguration; // Have we initialized global (root) handlers yet? // This gets set to false in readConfiguration private boolean initializedGlobalHandlers = true; // True if JVM death is imminent and the exit hook has been called. private boolean deathImminent; static { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { String cname = null; String contextLoading = null; try { cname = System.getProperty("java.util.logging.manager"); if (cname != null) { try { Class clz = ClassLoader.getSystemClassLoader().loadClass(cname); manager = (LogManager) clz.newInstance(); } catch (ClassNotFoundException ex) { contextLoading = System.getProperty("java.util.logging.manager.altclassloader"); if (contextLoading != null) { Class clz = Thread.currentThread().getContextClassLoader().loadClass(cname); manager = (LogManager) clz.newInstance(); } else { throw ex; } } } } catch (Exception ex) { System.err.println("Could not load Logmanager \"" + cname + "\""); ex.printStackTrace(); } if (manager == null) { manager = new LogManager(); } // Create and retain Logger for the root of the namespace. manager.rootLogger = manager.new RootLogger(); manager.addLogger(manager.rootLogger); // We don't call readConfiguration() here, as we may be running // very early in the JVM startup sequence. Instead readConfiguration // will be called lazily in getLogManager(). return null; } }); } // This private class is used as a shutdown hook. // It does a "reset" to close all open handlers. private class Cleaner extends Thread { public void run() { // If the global handlershaven't been initialized yet, we // don't want to initialize them just so we can close them! synchronized (LogManager.this) { // Note that death is imminent. deathImminent = true; initializedGlobalHandlers = true; } // Do a reset to close all active handlers. reset(); } } /** * Protected constructor. This is protected so that container applications * (such as J2EE containers) can subclass the object. It is non-public as * it is intended that there only be one LogManager object, whose value is * retrieved by calling Logmanager.getLogManager. */ protected LogManager() { // Add a shutdown hook to close the global handlers. try { Runtime.getRuntime().addShutdownHook(new Cleaner()); } catch(IllegalStateException e) { // If the VM is already shutting down, // We do not need to register shutdownHook. } } /** * Return the global LogManager object. */ public static LogManager getLogManager() { if (manager != null) { manager.readPrimordialConfiguration(); } return manager; } private void readPrimordialConfiguration() { if (!readPrimordialConfiguration) { synchronized (this) { if (!readPrimordialConfiguration) { // If System.in/out/err are null, it's a good // indication that we're still in the // bootstrapping phase if (System.out == null) { return; } readPrimordialConfiguration = true; try { AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws Exception { readConfiguration(); return null; } }); } catch (Exception ex) { // System.err.println("Can't read logging configuration:"); // ex.printStackTrace(); } } } } } /** * Add an event listener to be invoked when the logging * properties are re-read. * * @param l event listener * @exception SecurityException if a security manager exists and if * the caller does not have LoggingPermission("control"). */ public void addPropertyChangeListener(PropertyChangeListener l) throws SecurityException { checkAccess(); changes.addPropertyChangeListener(l); } /** * Remove an event listener for property change events. * <P> * Returns silently if the given listener is not found. * * @param l event listener * @exception SecurityException if a security manager exists and if * the caller does not have LoggingPermission("control"). */ public void removePropertyChangeListener(PropertyChangeListener l) throws SecurityException { checkAccess(); changes.removePropertyChangeListener(l); } /** * Add a named logger. This does nothing and returns false if a logger * with the same name is already registered. * <p> * The Logger factory methods call this method to register each * newly created Logger. * <p> * The application should retain its own reference to the Logger * object to avoid it being garbage collected. The LogManager * may only retain a weak reference. * * @param logger the new logger. * @return true if the argument logger was registered successfully, * false if a logger of that name already exists. * @exception NullPointerException if the logger name is null. */ public synchronized boolean addLogger(Logger logger) { String name = logger.getName(); if (name == null) { throw new NullPointerException(); } Logger old = (Logger) loggers.get(name); if (old != null) { // We already have a registered logger with the given name. return false; } // We're adding a new logger. // Note that we are creating a strong reference here that will // keep the Logger in existence indefinitely. loggers.put(name, logger); // Apply any initial level defined for the new logger. Level level = getLevelProperty(name+".level", null); if (level != null) { doSetLevel(logger, level); } // If any of the logger's parents have levels defined, // make sure they are instantiated. int ix = 1; for (;;) { int ix2 = name.indexOf(".", ix); if (ix2 < 0) { break; } String pname = name.substring(0,ix2); if (getProperty(pname+".level") != null) { // This pname has a level definition. Make sure it exists. Logger plogger = Logger.getLogger(pname); } ix = ix2+1; } // Find the new node and its parent. LogNode node = findNode(name); node.logger = logger; Logger parent = null; LogNode nodep = node.parent; while (nodep != null) { if (nodep.logger != null) { parent = nodep.logger; break; } nodep = nodep.parent; } if (parent != null) { doSetParent(logger, parent); } // Walk over the children and tell them we are their new parent. node.walkAndSetParent(logger); return true; } // Private method to set a level on a logger. // If necessary, we raise privilege before doing the call. private static void doSetLevel(final Logger logger, final Level level) { SecurityManager sm = System.getSecurityManager(); if (sm == null) { // There is no security manager, so things are easy. logger.setLevel(level); return; } // There is a security manager. Raise privilege before // calling setLevel. AccessController.doPrivileged(new PrivilegedAction() { public Object run() { logger.setLevel(level); return null; }}); } // Private method to set a parent on a logger. // If necessary, we raise privilege before doing the setParent call. private static void doSetParent(final Logger logger, final Logger parent) { SecurityManager sm = System.getSecurityManager(); if (sm == null) { // There is no security manager, so things are easy. logger.setParent(parent); return; } // There is a security manager. Raise privilege before // calling setParent. AccessController.doPrivileged(new PrivilegedAction() { public Object run() { logger.setParent(parent); return null; }}); } // Find a node in our tree of logger nodes. // If necessary, create it. private LogNode findNode(String name) { if (name == null || name.equals("")) { return root; } LogNode node = root; while (name.length() > 0) { int ix = name.indexOf("."); String head; if (ix > 0) { head = name.substring(0,ix); name = name.substring(ix+1); } else { head = name; name = ""; } if (node.children == null) { node.children = new HashMap(); } LogNode child = (LogNode)node.children.get(head); if (child == null) { child = new LogNode(node); node.children.put(head, child); } node = child; } return node; } /** * Method to find a named logger. * <p> * Note that since untrusted code may create loggers with * arbitrary names this method should not be relied on to * find Loggers for security sensitive logging. * <p> * @param name name of the logger * @return matching logger or null if none is found */ public synchronized Logger getLogger(String name) { return (Logger) loggers.get(name); } /** * Get an enumeration of known logger names. * <p> * Note: Loggers may be added dynamically as new classes are loaded. * This method only reports on the loggers that are currently registered. * <p> * @return enumeration of logger name strings */ public synchronized Enumeration getLoggerNames() { return loggers.keys(); } /** * Reinitialize the logging properties and reread the logging configuration. * <p> * The same rules are used for locating the configuration properties * as are used at startup. So normally the logging properties will * be re-read from the same file that was used at startup.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -