< prev index next >

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

Print this page

        

*** 257,273 **** new LoggerBundle(null, null); private static final RuntimePermission GET_CLASS_LOADER_PERMISSION = new RuntimePermission("getClassLoader"); private volatile LogManager manager; private String name; - private final CopyOnWriteArrayList<Handler> handlers = - new CopyOnWriteArrayList<>(); private volatile LoggerBundle loggerBundle = NO_RESOURCE_BUNDLE; - private volatile boolean useParentHandlers = true; - private volatile Filter filter; private boolean anonymous; // Cache to speed up behavior of findResourceBundle: private ResourceBundle catalog; // Cached resource bundle private String catalogName; // name associated with catalog --- 257,447 ---- new LoggerBundle(null, null); private static final RuntimePermission GET_CLASS_LOADER_PERMISSION = new RuntimePermission("getClassLoader"); + // A value class that holds the logger configuration data. + // This configuration can be shared between an application logger + // and a system logger of the same name. + private static final class ConfigurationData { + + // The delegate field is used to avoid races while + // merging configuration. This will ensure that any pending + // configuration action on an application logger will either + // be finished before the merge happens, or will be forwarded + // to the system logger configuration after the merge is completed. + // By default delegate=this. + private volatile ConfigurationData delegate; + + volatile boolean useParentHandlers; + volatile Filter filter; + volatile Level levelObject; + volatile int levelValue; // current effective level value + final CopyOnWriteArrayList<Handler> handlers = + new CopyOnWriteArrayList<>(); + + ConfigurationData() { + delegate = this; + useParentHandlers = true; + levelValue = Level.INFO.intValue(); + } + + void setUseParentHandlers(boolean flag) { + useParentHandlers = flag; + if (delegate != this) { + // merge in progress - propagate value to system peer. + final ConfigurationData system = delegate; + synchronized (system) { + system.useParentHandlers = useParentHandlers; + } + } + } + + void setFilter(Filter f) { + filter = f; + if (delegate != this) { + // merge in progress - propagate value to system peer. + final ConfigurationData system = delegate; + synchronized (system) { + system.filter = filter; + } + } + } + + void setLevelObject(Level l) { + levelObject = l; + if (delegate != this) { + // merge in progress - propagate value to system peer. + final ConfigurationData system = delegate; + synchronized (system) { + system.levelObject = levelObject; + } + } + } + + void setLevelValue(int v) { + levelValue = v; + if (delegate != this) { + // merge in progress - propagate value to system peer. + final ConfigurationData system = delegate; + synchronized (system) { + system.levelValue = levelValue; + } + } + } + + void addHandler(Handler h) { + if (handlers.add(h)) { + if (delegate != this) { + // merge in progress - propagate value to system peer. + final ConfigurationData system = delegate; + synchronized (system) { + system.handlers.addIfAbsent(h); + } + } + } + } + + void removeHandler(Handler h) { + if (handlers.remove(h)) { + if (delegate != this) { + // merge in progress - propagate value to system peer. + final ConfigurationData system = delegate; + synchronized (system) { + system.handlers.remove(h); + } + } + } + } + + ConfigurationData merge(Logger systemPeer) { + if (!systemPeer.isSystemLogger) { + // should never come here + throw new InternalError("not a system logger"); + } + + ConfigurationData system = systemPeer.config; + + if (system == this) { + // nothing to do + return system; + } + + systemPeer.checkPermission(); + + synchronized (system) { + // synchronize before checking on delegate to counter + // race conditions where two threads might attempt to + // merge concurrently + if (delegate == system) { + // merge already performed; + return system; + } + + // publish system as the temporary delegate configuration. + // This should take care of potential race conditions where + // an other thread might attempt to call e.g. setlevel on + // the application logger while merge is in progress. + // (see implementation of ConfigurationData::setLevel) + delegate = system; + + // merge this config object data into the system config + system.useParentHandlers = useParentHandlers; + system.filter = filter; + system.levelObject = levelObject; + system.levelValue = levelValue; + + // Prevent race condition in case two threads attempt to merge + // configuration and add handlers at the same time. We don't want + // to add the same handlers twice. + // + // Handlers are created and loaded by LogManager.addLogger. If we + // reach here, then it means that the application logger has + // been created first and added with LogManager.addLogger, and the + // system logger was created after - and no handler has been added + // to it by LogManager.addLogger. Therefore, system.handlers + // should be empty. + // + // A non empty cfg.handlers list indicates a race condition + // where two threads might attempt to merge the configuration + // or add handlers concurrently. Though of no consequence for + // the other data (level etc...) this would be an issue if we + // added the same handlers twice. + // + for (Handler h : handlers) { + if (!system.handlers.contains(h)) { + systemPeer.addHandler(h); + } + } + system.handlers.retainAll(handlers); + system.handlers.addAllAbsent(handlers); + } + + // sanity: update effective level after merging + synchronized(treeLock) { + systemPeer.updateEffectiveLevel(); + } + + return system; + } + + } + + // The logger configuration data. Ideally, this should be final + // for system loggers, and replace-once for application loggers. + // When an application requests a logger by name, we do not know a-priori + // whether that corresponds to a system logger name or not. + // So if no system logger by that name already exists, we simply return an + // application logger. + // If a system class later requests a system logger of the same name, then + // the application logger and system logger configurations will be merged + // in a single instance of ConfigurationData that both loggers will share. + private volatile ConfigurationData config; + private volatile LogManager manager; private String name; private volatile LoggerBundle loggerBundle = NO_RESOURCE_BUNDLE; private boolean anonymous; // Cache to speed up behavior of findResourceBundle: private ResourceBundle catalog; // Cached resource bundle private String catalogName; // name associated with catalog
*** 278,289 **** private static final Object treeLock = new Object(); // We keep weak references from parents to children, but strong // references from children to parents. private volatile Logger parent; // our nearest parent. private ArrayList<LogManager.LoggerWeakRef> kids; // WeakReferences to loggers that have us as parent - private volatile Level levelObject; - private volatile int levelValue; // current effective level value private WeakReference<Module> callerModuleRef; private final boolean isSystemLogger; /** * GLOBAL_LOGGER_NAME is a name for the global logger. --- 452,461 ----
*** 382,394 **** Logger(String name, String resourceBundleName, Module caller, LogManager manager, boolean isSystemLogger) { this.manager = manager; this.isSystemLogger = isSystemLogger; ! setupResourceInfo(resourceBundleName, caller); this.name = name; ! levelValue = Level.INFO.intValue(); } private void setCallerModuleRef(Module callerModule) { if (callerModule != null) { this.callerModuleRef = new WeakReference<>(callerModule); --- 554,586 ---- Logger(String name, String resourceBundleName, Module caller, LogManager manager, boolean isSystemLogger) { this.manager = manager; this.isSystemLogger = isSystemLogger; ! this.config = new ConfigurationData(); this.name = name; ! setupResourceInfo(resourceBundleName, caller); ! } ! ! // Called by LogManager when a system logger is created ! // after a user logger of the same name. ! // Ensure that both loggers will share the same ! // configuration. ! final void mergeWithSystemLogger(Logger system) { ! // sanity checks ! if (!system.isSystemLogger ! || anonymous ! || name == null ! || !name.equals(system.name)) { ! // should never come here ! throw new InternalError("invalid logger merge"); ! } ! checkPermission(); ! final ConfigurationData cfg = config; ! if (cfg != system.config) { ! config = cfg.merge(system); ! } } private void setCallerModuleRef(Module callerModule) { if (callerModule != null) { this.callerModuleRef = new WeakReference<>(callerModule);
*** 406,416 **** // and Logger static initializers causing deadlocks. private Logger(String name) { // The manager field is not initialized here. this.name = name; this.isSystemLogger = true; ! levelValue = Level.INFO.intValue(); } // It is called from LoggerContext.addLocalLogger() when the logger // is actually added to a LogManager. void setLogManager(LogManager manager) { --- 598,608 ---- // and Logger static initializers causing deadlocks. private Logger(String name) { // The manager field is not initialized here. this.name = name; this.isSystemLogger = true; ! config = new ConfigurationData(); } // It is called from LoggerContext.addLocalLogger() when the logger // is actually added to a LogManager. void setLogManager(LogManager manager) {
*** 449,459 **** } private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) { LogManager manager = LogManager.getLogManager(); if (!SystemLoggerHelper.disableCallerCheck) { ! if (caller.getClassLoader() == null) { return manager.demandSystemLogger(name, resourceBundleName, caller); } } return manager.demandLogger(name, resourceBundleName, caller); // ends up calling new Logger(name, resourceBundleName, caller) --- 641,651 ---- } private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) { LogManager manager = LogManager.getLogManager(); if (!SystemLoggerHelper.disableCallerCheck) { ! if (isSystem(caller.getModule())) { return manager.demandSystemLogger(name, resourceBundleName, caller); } } return manager.demandLogger(name, resourceBundleName, caller); // ends up calling new Logger(name, resourceBundleName, caller)
*** 738,757 **** * this logger is not anonymous, and the caller * does not have LoggingPermission("control"). */ public void setFilter(Filter newFilter) throws SecurityException { checkPermission(); ! filter = newFilter; } /** * Get the current filter for this Logger. * * @return a filter object (may be null) */ public Filter getFilter() { ! return filter; } /** * Log a LogRecord. * <p> --- 930,949 ---- * this logger is not anonymous, and the caller * does not have LoggingPermission("control"). */ public void setFilter(Filter newFilter) throws SecurityException { checkPermission(); ! config.setFilter(newFilter); } /** * Get the current filter for this Logger. * * @return a filter object (may be null) */ public Filter getFilter() { ! return config.filter; } /** * Log a LogRecord. * <p>
*** 763,773 **** */ public void log(LogRecord record) { if (!isLoggable(record.getLevel())) { return; } ! Filter theFilter = filter; if (theFilter != null && !theFilter.isLoggable(record)) { return; } // Post the LogRecord to all our Handlers, and then to --- 955,965 ---- */ public void log(LogRecord record) { if (!isLoggable(record.getLevel())) { return; } ! Filter theFilter = config.filter; if (theFilter != null && !theFilter.isLoggable(record)) { return; } // Post the LogRecord to all our Handlers, and then to
*** 782,792 **** for (Handler handler : loggerHandlers) { handler.publish(record); } final boolean useParentHdls = isSystemLogger ! ? logger.useParentHandlers : logger.getUseParentHandlers(); if (!useParentHdls) { break; } --- 974,984 ---- for (Handler handler : loggerHandlers) { handler.publish(record); } final boolean useParentHdls = isSystemLogger ! ? logger.config.useParentHandlers : logger.getUseParentHandlers(); if (!useParentHdls) { break; }
*** 1802,1829 **** * does not have LoggingPermission("control"). */ public void setLevel(Level newLevel) throws SecurityException { checkPermission(); synchronized (treeLock) { ! levelObject = newLevel; updateEffectiveLevel(); } } final boolean isLevelInitialized() { ! return levelObject != null; } /** * Get the log Level that has been specified for this Logger. * The result may be null, which means that this logger's * effective level will be inherited from its parent. * * @return this Logger's level */ public Level getLevel() { ! return levelObject; } /** * Check if a message of the given level would actually be logged * by this logger. This check is based on the Loggers effective level, --- 1994,2021 ---- * does not have LoggingPermission("control"). */ public void setLevel(Level newLevel) throws SecurityException { checkPermission(); synchronized (treeLock) { ! config.setLevelObject(newLevel); updateEffectiveLevel(); } } final boolean isLevelInitialized() { ! return config.levelObject != null; } /** * Get the log Level that has been specified for this Logger. * The result may be null, which means that this logger's * effective level will be inherited from its parent. * * @return this Logger's level */ public Level getLevel() { ! return config.levelObject; } /** * Check if a message of the given level would actually be logged * by this logger. This check is based on the Loggers effective level,
*** 1831,1840 **** --- 2023,2033 ---- * * @param level a message logging level * @return true if the given message level is currently being logged. */ public boolean isLoggable(Level level) { + int levelValue = config.levelValue; if (level.intValue() < levelValue || levelValue == offValue) { return false; } return true; }
*** 1860,1870 **** * does not have LoggingPermission("control"). */ public void addHandler(Handler handler) throws SecurityException { Objects.requireNonNull(handler); checkPermission(); ! handlers.add(handler); } /** * Remove a log Handler. * <P> --- 2053,2063 ---- * does not have LoggingPermission("control"). */ public void addHandler(Handler handler) throws SecurityException { Objects.requireNonNull(handler); checkPermission(); ! config.addHandler(handler); } /** * Remove a log Handler. * <P>
*** 1878,1888 **** public void removeHandler(Handler handler) throws SecurityException { checkPermission(); if (handler == null) { return; } ! handlers.remove(handler); } /** * Get the Handlers associated with this logger. * --- 2071,2081 ---- public void removeHandler(Handler handler) throws SecurityException { checkPermission(); if (handler == null) { return; } ! config.removeHandler(handler); } /** * Get the Handlers associated with this logger. *
*** 1893,1903 **** } // This method should ideally be marked final - but unfortunately // it needs to be overridden by LogManager.RootLogger Handler[] accessCheckedHandlers() { ! return handlers.toArray(emptyHandlers); } /** * Specify whether or not this logger should send its output * to its parent Logger. This means that any LogRecords will --- 2086,2096 ---- } // This method should ideally be marked final - but unfortunately // it needs to be overridden by LogManager.RootLogger Handler[] accessCheckedHandlers() { ! return config.handlers.toArray(emptyHandlers); } /** * Specify whether or not this logger should send its output * to its parent Logger. This means that any LogRecords will
*** 1910,1930 **** * this logger is not anonymous, and the caller * does not have LoggingPermission("control"). */ public void setUseParentHandlers(boolean useParentHandlers) { checkPermission(); ! this.useParentHandlers = useParentHandlers; } /** * Discover whether or not this logger is sending its output * to its parent logger. * * @return true if output is to be sent to the logger's parent */ public boolean getUseParentHandlers() { ! return useParentHandlers; } /** * Private utility method to map a resource bundle name to an * actual resource bundle, using a simple one-entry cache. --- 2103,2123 ---- * this logger is not anonymous, and the caller * does not have LoggingPermission("control"). */ public void setUseParentHandlers(boolean useParentHandlers) { checkPermission(); ! config.setUseParentHandlers(useParentHandlers); } /** * Discover whether or not this logger is sending its output * to its parent logger. * * @return true if output is to be sent to the logger's parent */ public boolean getUseParentHandlers() { ! return config.useParentHandlers; } /** * Private utility method to map a resource bundle name to an * actual resource bundle, using a simple one-entry cache.
*** 2254,2280 **** private void updateEffectiveLevel() { // assert Thread.holdsLock(treeLock); // Figure out our current effective level. int newLevelValue; if (levelObject != null) { newLevelValue = levelObject.intValue(); } else { if (parent != null) { ! newLevelValue = parent.levelValue; } else { // This may happen during initialization. newLevelValue = Level.INFO.intValue(); } } // If our effective value hasn't changed, we're done. ! if (levelValue == newLevelValue) { return; } ! levelValue = newLevelValue; // System.err.println("effective level: \"" + getName() + "\" := " + level); // Recursively update the level on each of our kids. if (kids != null) { --- 2447,2475 ---- private void updateEffectiveLevel() { // assert Thread.holdsLock(treeLock); // Figure out our current effective level. int newLevelValue; + final ConfigurationData cfg = config; + final Level levelObject = cfg.levelObject; if (levelObject != null) { newLevelValue = levelObject.intValue(); } else { if (parent != null) { ! newLevelValue = parent.config.levelValue; } else { // This may happen during initialization. newLevelValue = Level.INFO.intValue(); } } // If our effective value hasn't changed, we're done. ! if (cfg.levelValue == newLevelValue) { return; } ! cfg.setLevelValue(newLevelValue); // System.err.println("effective level: \"" + getName() + "\" := " + level); // Recursively update the level on each of our kids. if (kids != null) {
< prev index next >