src/share/classes/java/util/logging/LogManager.java

Print this page

        

*** 142,152 **** * @since 1.4 */ public class LogManager { // The global LogManager object ! private static LogManager manager; private Properties props = new Properties(); private final static Level defaultLevel = Level.INFO; // The map of the registered listeners. The map value is the registration --- 142,152 ---- * @since 1.4 */ public class LogManager { // The global LogManager object ! private static final LogManager manager; private Properties props = new Properties(); private final static Level defaultLevel = Level.INFO; // The map of the registered listeners. The map value is the registration
*** 167,226 **** 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<Object>() { ! public Object run() { String cname = 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) { ! Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname); ! manager = (LogManager) clz.newInstance(); } } } 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(); - // since by design the global manager's userContext and - // systemContext don't have their requiresDefaultLoggers - // flag set - we make sure to add the root logger to - // the global manager's default contexts here. - manager.addLogger(manager.rootLogger); - manager.systemContext.addLocalLogger(manager.rootLogger, false); - manager.userContext.addLocalLogger(manager.rootLogger, false); - - // Adding the global Logger. Doing so in the Logger.<clinit> - // would deadlock with the LogManager.<clinit>. - // Do not call Logger.getGlobal() here as this might trigger - // the deadlock too. - @SuppressWarnings("deprecation") - final Logger global = Logger.global; - global.setLogManager(manager); - - // Make sure the global logger will be registered in the - // global manager's default contexts. - manager.addLogger(global); - manager.systemContext.addLocalLogger(global, false); - manager.userContext.addLocalLogger(global, false); - - // 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; } }); } --- 167,203 ---- private boolean initializedGlobalHandlers = true; // True if JVM death is imminent and the exit hook has been called. private boolean deathImminent; static { ! manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() { ! @Override ! public LogManager run() { ! LogManager mgr = null; String cname = null; try { cname = System.getProperty("java.util.logging.manager"); if (cname != null) { try { ! Class<?> clz = ClassLoader.getSystemClassLoader() ! .loadClass(cname); ! mgr = (LogManager) clz.newInstance(); } catch (ClassNotFoundException ex) { ! Class<?> clz = Thread.currentThread() ! .getContextClassLoader().loadClass(cname); ! mgr = (LogManager) clz.newInstance(); } } } catch (Exception ex) { System.err.println("Could not load Logmanager \"" + cname + "\""); ex.printStackTrace(); } ! if (mgr == null) { ! mgr = new LogManager(); } + return mgr; } }); }
*** 233,242 **** --- 210,220 ---- * keeping a strong reference to an application classloader. */ this.setContextClassLoader(null); } + @Override public void run() { // This is to ensure the LogManager.<clinit> is completed // before synchronized block. Otherwise deadlocks are possible. LogManager mgr = manager;
*** 269,284 **** // We do not need to register shutdownHook. } } /** * Returns the global LogManager object. * @return the global LogManager object */ public static LogManager getLogManager() { if (manager != null) { ! manager.readPrimordialConfiguration(); } return manager; } private void readPrimordialConfiguration() { --- 247,316 ---- // We do not need to register shutdownHook. } } /** + * Lazy initialization: if this instance of manager is the global + * manager then this method will read the initial configuration and + * add the root logger and global logger by calling addLogger(). + * + * Note that it is subtly different from what we do in LoggerContext. + * In LoggerContext we're patching up the logger context tree in order to add + * the root and global logger *to the context tree*. + * + * For this to work, addLogger() must have already have been called + * once on the LogManager instance for the default logger being + * added. + * + * This is why ensureLogManagerInitialized() needs to be called before + * any logger is added to any logger context. + * + **/ + private boolean initializedCalled=false; + final synchronized void ensureLogManagerInitialized() { + final LogManager owner = this; + if (initializedCalled || owner != manager) { + // we don't want to do this twice, and we don't want to do + // this on private manager instances. + return; + } + initializedCalled = true; + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + if (rootLogger == null) { + // Read configuration. This was previously triggered + // by the new RootLogger() constructor - but no longer. + owner.readPrimordialConfiguration(); + + // Create and retain Logger for the root of the namespace. + owner.rootLogger = owner.new RootLogger(); + owner.addLogger(owner.rootLogger); + + // Adding the global Logger. Doing so in the Logger.<clinit> + // would deadlock with the LogManager.<clinit>. + // Do not call Logger.getGlobal() here as this might trigger + // the deadlock too. + @SuppressWarnings("deprecation") + final Logger global = Logger.global; + + // Make sure the global logger will be registered in the + // global manager + owner.addLogger(global); + } + return null; + } + }); + } + + /** * Returns the global LogManager object. * @return the global LogManager object */ public static LogManager getLogManager() { if (manager != null) { ! manager.ensureLogManagerInitialized(); } return manager; } private void readPrimordialConfiguration() {
*** 293,302 **** --- 325,335 ---- } readPrimordialConfiguration = true; try { AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { + @Override public Void run() throws Exception { readConfiguration(); // Platform loggers begin to delegate to java.util.logging.Logger sun.util.logging.PlatformLogger.redirectPlatformLoggers();
*** 304,313 **** --- 337,347 ---- } }); } catch (Exception ex) { // System.err.println("Can't read logging configuration:"); // ex.printStackTrace(); + assert false : "Exception raised while reading logging configuration: " + ex; } } } } }
*** 390,400 **** } } } // LoggerContext maps from AppContext ! private static WeakHashMap<Object, LoggerContext> contextsMap = null; // Returns the LoggerContext for the user code (i.e. application or AppContext). // Loggers are isolated from each AppContext. private LoggerContext getUserContext() { LoggerContext context = null; --- 424,434 ---- } } } // LoggerContext maps from AppContext ! private WeakHashMap<Object, LoggerContext> contextsMap = null; // Returns the LoggerContext for the user code (i.e. application or AppContext). // Loggers are isolated from each AppContext. private LoggerContext getUserContext() { LoggerContext context = null;
*** 412,437 **** contextsMap = new WeakHashMap<>(); } context = contextsMap.get(ecx); if (context == null) { // Create a new LoggerContext for the applet. ! // The new logger context has its requiresDefaultLoggers ! // flag set to true - so that these loggers will be ! // lazily added when the context is firt accessed. ! context = new LoggerContext(true); contextsMap.put(ecx, context); } } } } // for standalone app, return userContext return context != null ? context : userContext; } private List<LoggerContext> contexts() { List<LoggerContext> cxs = new ArrayList<>(); ! cxs.add(systemContext); cxs.add(getUserContext()); return cxs; } // Find or create a specified logger instance. If a logger has --- 446,473 ---- contextsMap = new WeakHashMap<>(); } context = contextsMap.get(ecx); if (context == null) { // Create a new LoggerContext for the applet. ! context = new LoggerContext(); contextsMap.put(ecx, context); } } } } // for standalone app, return userContext return context != null ? context : userContext; } + // The system context. + final LoggerContext getSystemContext() { + return systemContext; + } + private List<LoggerContext> contexts() { List<LoggerContext> cxs = new ArrayList<>(); ! cxs.add(getSystemContext()); cxs.add(getUserContext()); return cxs; } // Find or create a specified logger instance. If a logger has
*** 448,458 **** // readConfiguration, and other methods. Logger demandLogger(String name, String resourceBundleName, Class<?> caller) { Logger result = getLogger(name); if (result == null) { // only allocate the new logger once ! Logger newLogger = new Logger(name, resourceBundleName, caller); do { if (addLogger(newLogger)) { // We successfully added the new Logger that we // created above so return it without refetching. return newLogger; --- 484,494 ---- // readConfiguration, and other methods. Logger demandLogger(String name, String resourceBundleName, Class<?> caller) { Logger result = getLogger(name); if (result == null) { // only allocate the new logger once ! Logger newLogger = new Logger(name, resourceBundleName, caller, this); do { if (addLogger(newLogger)) { // We successfully added the new Logger that we // created above so return it without refetching. return newLogger;
*** 475,485 **** return result; } Logger demandSystemLogger(String name, String resourceBundleName) { // Add a system logger in the system context's namespace ! final Logger sysLogger = systemContext.demandLogger(name, resourceBundleName); // Add the system logger to the LogManager's namespace if not exist // so that there is only one single logger of the given name. // System loggers are visible to applications unless a logger of // the same name has been added. --- 511,521 ---- return result; } Logger demandSystemLogger(String name, String resourceBundleName) { // Add a system logger in the system context's namespace ! final Logger sysLogger = getSystemContext().demandLogger(name, resourceBundleName); // Add the system logger to the LogManager's namespace if not exist // so that there is only one single logger of the given name. // System loggers are visible to applications unless a logger of // the same name has been added.
*** 499,508 **** --- 535,545 ---- // LogManager will set the sysLogger's handlers via LogManager.addLogger method. if (logger != sysLogger && sysLogger.getHandlers().length == 0) { // if logger already exists but handlers not set final Logger l = logger; AccessController.doPrivileged(new PrivilegedAction<Void>() { + @Override public Void run() { for (Handler hdl : l.getHandlers()) { sysLogger.addHandler(hdl); } return null;
*** 517,544 **** // context. The system context is used to maintain the namespace for // all system loggers and is queried by the system code. If a system logger // doesn't exist in the user context, it'll also be added to the user context. // The user context is queried by the user code and all other loggers are // added in the user context. ! static class LoggerContext { // Table of named Loggers that maps names to Loggers. private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>(); // Tree of named Loggers private final LogNode root; - private final boolean requiresDefaultLoggers; private LoggerContext() { - this(false); - } - private LoggerContext(boolean requiresDefaultLoggers) { this.root = new LogNode(null, this); ! this.requiresDefaultLoggers = requiresDefaultLoggers; } Logger demandLogger(String name, String resourceBundleName) { // a LogManager subclass may have its own implementation to add and // get a Logger. So delegate to the LogManager to do the work. ! return manager.demandLogger(name, resourceBundleName, null); } // Due to subtle deadlock issues getUserContext() no longer // calls addLocalLogger(rootLogger); --- 554,609 ---- // context. The system context is used to maintain the namespace for // all system loggers and is queried by the system code. If a system logger // doesn't exist in the user context, it'll also be added to the user context. // The user context is queried by the user code and all other loggers are // added in the user context. ! class LoggerContext { // Table of named Loggers that maps names to Loggers. private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>(); // Tree of named Loggers private final LogNode root; private LoggerContext() { this.root = new LogNode(null, this); ! } ! ! ! // Tells whether default loggers are required in this context. ! // If true, the default loggers will be lazily added. ! final boolean requiresDefaultLoggers() { ! final boolean requiresDefaultLoggers = (getOwner() == manager); ! if (requiresDefaultLoggers) { ! getOwner().ensureLogManagerInitialized(); ! } ! return requiresDefaultLoggers; ! } ! ! // This context's LogManager. ! final LogManager getOwner() { ! return LogManager.this; ! } ! ! // This context owner's root logger, which if not null, and if ! // the context requires default loggers, will be added to the context ! // logger's tree. ! final Logger getRootLogger() { ! return getOwner().rootLogger; ! } ! ! // The global logger, which if not null, and if ! // the context requires default loggers, will be added to the context ! // logger's tree. ! final Logger getGlobalLogger() { ! @SuppressWarnings("deprecated") // avoids initialization cycles. ! final Logger global = Logger.global; ! return global; } Logger demandLogger(String name, String resourceBundleName) { // a LogManager subclass may have its own implementation to add and // get a Logger. So delegate to the LogManager to do the work. ! final LogManager owner = getOwner(); ! return owner.demandLogger(name, resourceBundleName, null); } // Due to subtle deadlock issues getUserContext() no longer // calls addLocalLogger(rootLogger);
*** 546,559 **** // Checks that the context is properly initialized // This is necessary before calling e.g. find(name) // or getLoggerNames() // private void ensureInitialized() { ! if (requiresDefaultLoggers) { // Ensure that the root and global loggers are set. ! ensureDefaultLogger(manager.rootLogger); ! ensureDefaultLogger(Logger.global); } } synchronized Logger findLogger(String name) { --- 611,624 ---- // Checks that the context is properly initialized // This is necessary before calling e.g. find(name) // or getLoggerNames() // private void ensureInitialized() { ! if (requiresDefaultLoggers()) { // Ensure that the root and global loggers are set. ! ensureDefaultLogger(getRootLogger()); ! ensureDefaultLogger(getGlobalLogger()); } } synchronized Logger findLogger(String name) {
*** 578,594 **** // 'logger' is the context that will be added. // This method will ensure that the defaults loggers are added // before adding 'logger'. // private void ensureAllDefaultLoggers(Logger logger) { ! if (requiresDefaultLoggers) { final String name = logger.getName(); if (!name.isEmpty()) { ! ensureDefaultLogger(manager.rootLogger); ! } if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) { ! ensureDefaultLogger(Logger.global); } } } private void ensureDefaultLogger(Logger logger) { --- 643,659 ---- // 'logger' is the context that will be added. // This method will ensure that the defaults loggers are added // before adding 'logger'. // private void ensureAllDefaultLoggers(Logger logger) { ! if (requiresDefaultLoggers()) { final String name = logger.getName(); if (!name.isEmpty()) { ! ensureDefaultLogger(getRootLogger()); if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) { ! ensureDefaultLogger(getGlobalLogger()); ! } } } } private void ensureDefaultLogger(Logger logger) {
*** 596,607 **** // to a LoggerContext. // This check is simple sanity: we do not want that this // method be called for anything else than Logger.global // or owner.rootLogger. ! if (!requiresDefaultLoggers || logger == null ! || logger != Logger.global && logger != manager.rootLogger) { // the case where we have a non null logger which is neither // Logger.global nor manager.rootLogger indicates a serious // issue - as ensureDefaultLogger should never be called // with any other loggers than one of these two (or null - if --- 661,672 ---- // to a LoggerContext. // This check is simple sanity: we do not want that this // method be called for anything else than Logger.global // or owner.rootLogger. ! if (!requiresDefaultLoggers() || logger == null ! || logger != Logger.global && logger != LogManager.this.rootLogger) { // the case where we have a non null logger which is neither // Logger.global nor manager.rootLogger indicates a serious // issue - as ensureDefaultLogger should never be called // with any other loggers than one of these two (or null - if
*** 623,633 **** } } boolean addLocalLogger(Logger logger) { // no need to add default loggers if it's not required ! return addLocalLogger(logger, requiresDefaultLoggers); } // Add a logger to this context. This method will only set its level // and process parent loggers. It doesn't set its handlers. synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) { --- 688,698 ---- } } boolean addLocalLogger(Logger logger) { // no need to add default loggers if it's not required ! return addLocalLogger(logger, requiresDefaultLoggers()); } // Add a logger to this context. This method will only set its level // and process parent loggers. It doesn't set its handlers. synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) {
*** 661,675 **** } } // We're adding a new logger. // Note that we are creating a weak reference here. ! ref = manager.new LoggerWeakRef(logger); namedLoggers.put(name, ref); // Apply any initial level defined for the new logger. ! Level level = manager.getLevelProperty(name + ".level", null); if (level != null) { doSetLevel(logger, level); } // instantiation of the handler is done in the LogManager.addLogger --- 726,742 ---- } } // We're adding a new logger. // Note that we are creating a weak reference here. ! final LogManager owner = getOwner(); ! logger.setLogManager(owner); ! ref = owner.new LoggerWeakRef(logger); namedLoggers.put(name, ref); // Apply any initial level defined for the new logger. ! Level level = owner.getLevelProperty(name + ".level", null); if (level != null) { doSetLevel(logger, level); } // instantiation of the handler is done in the LogManager.addLogger
*** 717,730 **** } // If logger.getUseParentHandlers() returns 'true' and any of the logger's // parents have levels or handlers defined, make sure they are instantiated. private void processParentHandlers(final Logger logger, final String name) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { ! if (logger != manager.rootLogger) { ! boolean useParent = manager.getBooleanProperty(name + ".useParentHandlers", true); if (!useParent) { logger.setUseParentHandlers(false); } } return null; --- 784,799 ---- } // If logger.getUseParentHandlers() returns 'true' and any of the logger's // parents have levels or handlers defined, make sure they are instantiated. private void processParentHandlers(final Logger logger, final String name) { + final LogManager owner = getOwner(); AccessController.doPrivileged(new PrivilegedAction<Void>() { + @Override public Void run() { ! if (logger != owner.rootLogger) { ! boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true); if (!useParent) { logger.setUseParentHandlers(false); } } return null;
*** 736,747 **** int ix2 = name.indexOf(".", ix); if (ix2 < 0) { break; } String pname = name.substring(0, ix2); ! if (manager.getProperty(pname + ".level") != null || ! manager.getProperty(pname + ".handlers") != null) { // This pname has a level/handlers definition. // Make sure it exists. demandLogger(pname, null); } ix = ix2+1; --- 805,816 ---- int ix2 = name.indexOf(".", ix); if (ix2 < 0) { break; } String pname = name.substring(0, ix2); ! if (owner.getProperty(pname + ".level") != null || ! owner.getProperty(pname + ".handlers") != null) { // This pname has a level/handlers definition. // Make sure it exists. demandLogger(pname, null); } ix = ix2+1;
*** 777,796 **** } return node; } } ! static class SystemLoggerContext extends LoggerContext { // Add a system logger in the system context's namespace as well as // in the LogManager's namespace if not exist so that there is only // one single logger of the given name. System loggers are visible // to applications unless a logger of the same name has been added. Logger demandLogger(String name, String resourceBundleName) { Logger result = findLogger(name); if (result == null) { // only allocate the new system logger once ! Logger newLogger = new Logger(name, resourceBundleName); do { if (addLocalLogger(newLogger)) { // We successfully added the new Logger that we // created above so return it without refetching. result = newLogger; --- 846,866 ---- } return node; } } ! final class SystemLoggerContext extends LoggerContext { // Add a system logger in the system context's namespace as well as // in the LogManager's namespace if not exist so that there is only // one single logger of the given name. System loggers are visible // to applications unless a logger of the same name has been added. + @Override Logger demandLogger(String name, String resourceBundleName) { Logger result = findLogger(name); if (result == null) { // only allocate the new system logger once ! Logger newLogger = new Logger(name, resourceBundleName, null, getOwner()); do { if (addLocalLogger(newLogger)) { // We successfully added the new Logger that we // created above so return it without refetching. result = newLogger;
*** 820,829 **** --- 890,900 ---- // only be modified by trusted code. private void loadLoggerHandlers(final Logger logger, final String name, final String handlersPropertyName) { AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override public Object run() { String names[] = parseClassNames(handlersPropertyName); for (int i = 0; i < names.length; i++) { String word = names[i]; try {
*** 1012,1021 **** --- 1083,1093 ---- return; } // There is a security manager. Raise privilege before // calling setLevel. AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override public Object run() { logger.setLevel(level); return null; }}); }
*** 1030,1039 **** --- 1102,1112 ---- return; } // There is a security manager. Raise privilege before // calling setParent. AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override public Object run() { logger.setParent(parent); return null; }}); }
*** 1127,1146 **** } File f = new File(fname, "lib"); f = new File(f, "logging.properties"); fname = f.getCanonicalPath(); } ! InputStream in = new FileInputStream(fname); ! BufferedInputStream bin = new BufferedInputStream(in); try { readConfiguration(bin); } finally { - if (in != null) { in.close(); } } - } /** * Reset the logging configuration. * <p> * For all named loggers, the reset operation removes and closes --- 1200,1217 ---- } File f = new File(fname, "lib"); f = new File(f, "logging.properties"); fname = f.getCanonicalPath(); } ! final InputStream in = new FileInputStream(fname); ! final BufferedInputStream bin = new BufferedInputStream(in); try { readConfiguration(bin); } finally { in.close(); } } /** * Reset the logging configuration. * <p> * For all named loggers, the reset operation removes and closes
*** 1199,1209 **** if (hands == null) { return new String[0]; } hands = hands.trim(); int ix = 0; ! Vector<String> result = new Vector<>(); while (ix < hands.length()) { int end = ix; while (end < hands.length()) { if (Character.isWhitespace(hands.charAt(end))) { break; --- 1270,1280 ---- if (hands == null) { return new String[0]; } hands = hands.trim(); int ix = 0; ! final List<String> result = new ArrayList<>(); while (ix < hands.length()) { int end = ix; while (end < hands.length()) { if (Character.isWhitespace(hands.charAt(end))) { break;
*** 1469,1500 **** } // We use a subclass of Logger for the root logger, so // that we only instantiate the global handlers when they // are first needed. ! private class RootLogger extends Logger { private RootLogger() { ! super("", null); setLevel(defaultLevel); } public void log(LogRecord record) { // Make sure that the global handlers have been instantiated. initializeGlobalHandlers(); super.log(record); } public void addHandler(Handler h) { initializeGlobalHandlers(); super.addHandler(h); } public void removeHandler(Handler h) { initializeGlobalHandlers(); super.removeHandler(h); } public Handler[] getHandlers() { initializeGlobalHandlers(); return super.getHandlers(); } } --- 1540,1578 ---- } // We use a subclass of Logger for the root logger, so // that we only instantiate the global handlers when they // are first needed. ! private final class RootLogger extends Logger { private RootLogger() { ! // We do not the protected Logger two args constructor here, ! // to avoid calling LOgManager.getLogManager() from within the ! // RootLogger constructor. ! super("", null, null, LogManager.this); setLevel(defaultLevel); } + @Override public void log(LogRecord record) { // Make sure that the global handlers have been instantiated. initializeGlobalHandlers(); super.log(record); } + @Override public void addHandler(Handler h) { initializeGlobalHandlers(); super.addHandler(h); } + @Override public void removeHandler(Handler h) { initializeGlobalHandlers(); super.removeHandler(h); } + @Override public Handler[] getHandlers() { initializeGlobalHandlers(); return super.getHandlers(); } }