8005615: Java Logger fails to load tomcat logger implementation (JULI)
Reviewed-by: alanb, ahgross
This commit is contained in:
parent
be64e9b087
commit
3243aaf47a
@ -158,7 +158,7 @@ public class LogManager {
|
||||
|
||||
// LoggerContext for system loggers and user loggers
|
||||
private final LoggerContext systemContext = new SystemLoggerContext();
|
||||
private final LoggerContext userContext = new UserLoggerContext();
|
||||
private final LoggerContext userContext = new LoggerContext();
|
||||
private Logger rootLogger;
|
||||
|
||||
// Have we done the primordial reading of the configuration file?
|
||||
@ -196,13 +196,13 @@ public class LogManager {
|
||||
|
||||
// Create and retain Logger for the root of the namespace.
|
||||
manager.rootLogger = manager.new RootLogger();
|
||||
manager.systemContext.addLogger(manager.rootLogger);
|
||||
manager.userContext.addLogger(manager.rootLogger);
|
||||
manager.addLogger(manager.rootLogger);
|
||||
manager.systemContext.addLocalLogger(manager.rootLogger);
|
||||
|
||||
// Adding the global Logger. Doing so in the Logger.<clinit>
|
||||
// would deadlock with the LogManager.<clinit>.
|
||||
Logger.getGlobal().setLogManager(manager);
|
||||
manager.systemContext.addLogger(Logger.getGlobal());
|
||||
Logger.global.setLogManager(manager);
|
||||
manager.addLogger(Logger.global);
|
||||
|
||||
// We don't call readConfiguration() here, as we may be running
|
||||
// very early in the JVM startup sequence. Instead readConfiguration
|
||||
@ -373,7 +373,7 @@ public class LogManager {
|
||||
|
||||
// Returns the LoggerContext for the user code (i.e. application or AppContext).
|
||||
// Loggers are isolated from each AppContext.
|
||||
LoggerContext getUserContext() {
|
||||
private LoggerContext getUserContext() {
|
||||
LoggerContext context = null;
|
||||
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
@ -394,8 +394,8 @@ public class LogManager {
|
||||
if (javaAwtAccess.isMainAppContext()) {
|
||||
context = userContext;
|
||||
} else {
|
||||
context = new UserLoggerContext();
|
||||
context.addLogger(manager.rootLogger);
|
||||
context = new LoggerContext();
|
||||
context.addLocalLogger(manager.rootLogger);
|
||||
}
|
||||
javaAwtAccess.put(ecx, LoggerContext.class, context);
|
||||
}
|
||||
@ -406,10 +406,6 @@ public class LogManager {
|
||||
return context;
|
||||
}
|
||||
|
||||
LoggerContext getSystemContext() {
|
||||
return systemContext;
|
||||
}
|
||||
|
||||
private List<LoggerContext> contexts() {
|
||||
List<LoggerContext> cxs = new ArrayList<>();
|
||||
cxs.add(systemContext);
|
||||
@ -417,6 +413,58 @@ public class LogManager {
|
||||
return cxs;
|
||||
}
|
||||
|
||||
// Find or create a specified logger instance. If a logger has
|
||||
// already been created with the given name it is returned.
|
||||
// Otherwise a new logger instance is created and registered
|
||||
// in the LogManager global namespace.
|
||||
// This method will always return a non-null Logger object.
|
||||
// Synchronization is not required here. All synchronization for
|
||||
// adding a new Logger object is handled by addLogger().
|
||||
//
|
||||
// This method must delegate to the LogManager implementation to
|
||||
// add a new Logger or return the one that has been added previously
|
||||
// as a LogManager subclass may override the addLogger, getLogger,
|
||||
// readConfiguration, and other methods.
|
||||
Logger demandLogger(String name, String resourceBundleName) {
|
||||
Logger result = getLogger(name);
|
||||
if (result == null) {
|
||||
// only allocate the new logger once
|
||||
Logger newLogger = new Logger(name, resourceBundleName);
|
||||
do {
|
||||
if (addLogger(newLogger)) {
|
||||
// We successfully added the new Logger that we
|
||||
// created above so return it without refetching.
|
||||
return newLogger;
|
||||
}
|
||||
|
||||
// We didn't add the new Logger that we created above
|
||||
// because another thread added a Logger with the same
|
||||
// name after our null check above and before our call
|
||||
// to addLogger(). We have to refetch the Logger because
|
||||
// addLogger() returns a boolean instead of the Logger
|
||||
// reference itself. However, if the thread that created
|
||||
// the other Logger is not holding a strong reference to
|
||||
// the other Logger, then it is possible for the other
|
||||
// Logger to be GC'ed after we saw it in addLogger() and
|
||||
// before we can refetch it. If it has been GC'ed then
|
||||
// we'll just loop around and try again.
|
||||
result = getLogger(name);
|
||||
} while (result == null);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Logger demandSystemLogger(String name, String resourceBundleName) {
|
||||
return systemContext.demandLogger(name, resourceBundleName);
|
||||
}
|
||||
|
||||
// LoggerContext maintains the logger namespace per context.
|
||||
// The default LogManager implementation has one system context and user
|
||||
// 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<>();
|
||||
@ -427,6 +475,12 @@ public class LogManager {
|
||||
this.root = new LogNode(null, this);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
synchronized Logger findLogger(String name) {
|
||||
LoggerWeakRef ref = namedLoggers.get(name);
|
||||
if (ref == null) {
|
||||
@ -441,7 +495,9 @@ public class LogManager {
|
||||
return logger;
|
||||
}
|
||||
|
||||
synchronized boolean addLogger(Logger logger) {
|
||||
// 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) {
|
||||
final String name = logger.getName();
|
||||
if (name == null) {
|
||||
throw new NullPointerException();
|
||||
@ -474,9 +530,9 @@ public class LogManager {
|
||||
doSetLevel(logger, level);
|
||||
}
|
||||
|
||||
// Do we have a per logger handler too?
|
||||
// Note: this will add a 200ms penalty
|
||||
manager.loadLoggerHandlers(logger, name, name + ".handlers");
|
||||
// instantiation of the handler is done in the LogManager.addLogger
|
||||
// implementation as a handler class may be only visible to LogManager
|
||||
// subclass for the custom log manager case
|
||||
processParentHandlers(logger, name);
|
||||
|
||||
// Find the new node and its parent.
|
||||
@ -513,50 +569,21 @@ public class LogManager {
|
||||
return namedLoggers.keys();
|
||||
}
|
||||
|
||||
Logger demandLogger(String name) {
|
||||
return demandLogger(name, null);
|
||||
}
|
||||
|
||||
// Find or create a specified logger instance. If a logger has
|
||||
// already been created with the given name it is returned.
|
||||
// Otherwise a new logger instance is created and registered
|
||||
// in the LogManager global namespace.
|
||||
|
||||
// This method will always return a non-null Logger object.
|
||||
// Synchronization is not required here. All synchronization for
|
||||
// adding a new Logger object is handled by addLogger().
|
||||
Logger demandLogger(String name, String resourceBundleName) {
|
||||
Logger result = findLogger(name);
|
||||
if (result == null) {
|
||||
// only allocate the new logger once
|
||||
Logger newLogger = new Logger(name, resourceBundleName);
|
||||
do {
|
||||
if (addLogger(newLogger)) {
|
||||
// We successfully added the new Logger that we
|
||||
// created above so return it without refetching.
|
||||
return newLogger;
|
||||
}
|
||||
|
||||
// We didn't add the new Logger that we created above
|
||||
// because another thread added a Logger with the same
|
||||
// name after our null check above and before our call
|
||||
// to addLogger(). We have to refetch the Logger because
|
||||
// addLogger() returns a boolean instead of the Logger
|
||||
// reference itself. However, if the thread that created
|
||||
// the other Logger is not holding a strong reference to
|
||||
// the other Logger, then it is possible for the other
|
||||
// Logger to be GC'ed after we saw it in addLogger() and
|
||||
// before we can refetch it. If it has been GC'ed then
|
||||
// we'll just loop around and try again.
|
||||
result = findLogger(name);
|
||||
} while (result == null);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// 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(Logger logger, String name) {
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
int ix = 1;
|
||||
for (;;) {
|
||||
int ix2 = name.indexOf(".", ix);
|
||||
@ -564,12 +591,11 @@ public class LogManager {
|
||||
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);
|
||||
demandLogger(pname, null);
|
||||
}
|
||||
ix = ix2+1;
|
||||
}
|
||||
@ -607,53 +633,51 @@ public class LogManager {
|
||||
}
|
||||
|
||||
static class SystemLoggerContext extends LoggerContext {
|
||||
// Default resource bundle for all system loggers
|
||||
Logger demandLogger(String name) {
|
||||
// default to use the system logger's resource bundle
|
||||
return super.demandLogger(name, Logger.SYSTEM_LOGGER_RB_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
static class UserLoggerContext extends LoggerContext {
|
||||
/**
|
||||
* Returns a Logger of the given name if there is one registered
|
||||
* in this context. Otherwise, it will return the one registered
|
||||
* in the system context if there is one. The returned Logger
|
||||
* instance may be initialized with a different resourceBundleName.
|
||||
* If no such logger exists, a new Logger instance will be created
|
||||
* and registered in this context.
|
||||
*/
|
||||
// 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) {
|
||||
// use the system logger if exists; or allocate a new logger.
|
||||
// The system logger is added to the app logger context so that
|
||||
// any child logger created in the app logger context can have
|
||||
// a system logger as its parent if already exist.
|
||||
Logger logger = manager.systemContext.findLogger(name);
|
||||
Logger newLogger =
|
||||
logger != null ? logger : new Logger(name, resourceBundleName);
|
||||
// only allocate the new system logger once
|
||||
Logger newLogger = new Logger(name, resourceBundleName);
|
||||
do {
|
||||
if (addLogger(newLogger)) {
|
||||
if (addLocalLogger(newLogger)) {
|
||||
// We successfully added the new Logger that we
|
||||
// created above so return it without refetching.
|
||||
return newLogger;
|
||||
result = newLogger;
|
||||
} else {
|
||||
// We didn't add the new Logger that we created above
|
||||
// because another thread added a Logger with the same
|
||||
// name after our null check above and before our call
|
||||
// to addLogger(). We have to refetch the Logger because
|
||||
// addLogger() returns a boolean instead of the Logger
|
||||
// reference itself. However, if the thread that created
|
||||
// the other Logger is not holding a strong reference to
|
||||
// the other Logger, then it is possible for the other
|
||||
// Logger to be GC'ed after we saw it in addLogger() and
|
||||
// before we can refetch it. If it has been GC'ed then
|
||||
// we'll just loop around and try again.
|
||||
result = findLogger(name);
|
||||
}
|
||||
|
||||
// We didn't add the new Logger that we created above
|
||||
// because another thread added a Logger with the same
|
||||
// name after our null check above and before our call
|
||||
// to addLogger(). We have to refetch the Logger because
|
||||
// addLogger() returns a boolean instead of the Logger
|
||||
// reference itself. However, if the thread that created
|
||||
// the other Logger is not holding a strong reference to
|
||||
// the other Logger, then it is possible for the other
|
||||
// Logger to be GC'ed after we saw it in addLogger() and
|
||||
// before we can refetch it. If it has been GC'ed then
|
||||
// we'll just loop around and try again.
|
||||
result = findLogger(name);
|
||||
} while (result == null);
|
||||
}
|
||||
// Add the system logger to the LogManager's namespace if not exists
|
||||
// The LogManager will set its handlers via the LogManager.addLogger method.
|
||||
if (!manager.addLogger(result) && result.getHandlers().length == 0) {
|
||||
// if logger already exists but handlers not set
|
||||
final Logger l = manager.getLogger(name);
|
||||
final Logger logger = result;
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
for (Handler hdl : l.getHandlers()) {
|
||||
logger.addHandler(hdl);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -663,22 +687,16 @@ public class LogManager {
|
||||
// be made based on the logging configuration, which can
|
||||
// only be modified by trusted code.
|
||||
private void loadLoggerHandlers(final Logger logger, final String name,
|
||||
final String handlersPropertyName) {
|
||||
final String handlersPropertyName)
|
||||
{
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
public Object run() {
|
||||
if (logger != rootLogger) {
|
||||
boolean useParent = getBooleanProperty(name + ".useParentHandlers", true);
|
||||
if (!useParent) {
|
||||
logger.setUseParentHandlers(false);
|
||||
}
|
||||
}
|
||||
|
||||
String names[] = parseClassNames(handlersPropertyName);
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
String word = names[i];
|
||||
try {
|
||||
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
|
||||
Handler hdl = (Handler) clz.newInstance();
|
||||
Handler hdl = (Handler) clz.newInstance();
|
||||
// Check if there is a property defining the
|
||||
// this handler's level.
|
||||
String levs = getProperty(word + ".level");
|
||||
@ -700,7 +718,8 @@ public class LogManager {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -839,13 +858,17 @@ public class LogManager {
|
||||
if (name == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (systemContext.findLogger(name) != null) {
|
||||
LoggerContext cx = getUserContext();
|
||||
if (cx.addLocalLogger(logger)) {
|
||||
// Do we have a per logger handler too?
|
||||
// Note: this will add a 200ms penalty
|
||||
loadLoggerHandlers(logger, name, name + ".handlers");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return getUserContext().addLogger(logger);
|
||||
}
|
||||
|
||||
|
||||
// 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) {
|
||||
@ -864,8 +887,6 @@ public class LogManager {
|
||||
}});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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) {
|
||||
@ -900,15 +921,7 @@ public class LogManager {
|
||||
* @return matching logger or null if none is found
|
||||
*/
|
||||
public Logger getLogger(String name) {
|
||||
// return the first logger added
|
||||
//
|
||||
// once a system logger is added in the system context, no one can
|
||||
// adds a logger with the same name in the global context
|
||||
// (see LogManager.addLogger). So if there is a logger in the global
|
||||
// context with the same name as one in the system context, it must be
|
||||
// added before the system logger was created.
|
||||
Logger logger = getUserContext().findLogger(name);
|
||||
return logger != null ? logger : systemContext.findLogger(name);
|
||||
return getUserContext().findLogger(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -928,10 +941,7 @@ public class LogManager {
|
||||
* @return enumeration of logger name strings
|
||||
*/
|
||||
public Enumeration<String> getLoggerNames() {
|
||||
// only return unique names
|
||||
Set<String> names = new HashSet<>(Collections.list(systemContext.getLoggerNames()));
|
||||
names.addAll(Collections.list(getUserContext().getLoggerNames()));
|
||||
return Collections.enumeration(names);
|
||||
return getUserContext().getLoggerNames();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1329,7 +1339,6 @@ public class LogManager {
|
||||
// that we only instantiate the global handlers when they
|
||||
// are first needed.
|
||||
private class RootLogger extends Logger {
|
||||
|
||||
private RootLogger() {
|
||||
super("", null);
|
||||
setLevel(defaultLevel);
|
||||
|
@ -31,7 +31,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.security.*;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.LogManager.LoggerContext;
|
||||
|
||||
/**
|
||||
* A Logger object is used to log messages for a specific
|
||||
@ -321,18 +320,32 @@ public class Logger {
|
||||
//
|
||||
// As an interim solution, if the immediate caller whose caller loader is
|
||||
// null, we assume it's a system logger and add it to the system context.
|
||||
private static LoggerContext getLoggerContext() {
|
||||
// These system loggers only set the resource bundle to the given
|
||||
// resource bundle name (rather than the default system resource bundle).
|
||||
private static class SystemLoggerHelper {
|
||||
static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck");
|
||||
private static boolean getBooleanProperty(final String key) {
|
||||
String s = AccessController.doPrivileged(new PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
return System.getProperty(key);
|
||||
}
|
||||
});
|
||||
return Boolean.valueOf(s);
|
||||
}
|
||||
}
|
||||
|
||||
private static Logger demandLogger(String name, String resourceBundleName) {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
// 0: Reflection 1: Logger.getLoggerContext 2: Logger.getLogger 3: caller
|
||||
if (sm != null && !SystemLoggerHelper.disableCallerCheck) {
|
||||
// 0: Reflection 1: Logger.demandLogger 2: Logger.getLogger 3: caller
|
||||
final int SKIP_FRAMES = 3;
|
||||
Class<?> caller = sun.reflect.Reflection.getCallerClass(SKIP_FRAMES);
|
||||
if (caller.getClassLoader() == null) {
|
||||
return manager.getSystemContext();
|
||||
return manager.demandSystemLogger(name, resourceBundleName);
|
||||
}
|
||||
}
|
||||
return manager.getUserContext();
|
||||
return manager.demandLogger(name, resourceBundleName);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -376,8 +389,7 @@ public class Logger {
|
||||
// would throw an IllegalArgumentException in the second call
|
||||
// because the wrapper would result in an attempt to replace
|
||||
// the existing "resourceBundleForFoo" with null.
|
||||
LoggerContext context = getLoggerContext();
|
||||
return context.demandLogger(name);
|
||||
return demandLogger(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -424,8 +436,7 @@ public class Logger {
|
||||
// Synchronization is not required here. All synchronization for
|
||||
// adding a new Logger object is handled by LogManager.addLogger().
|
||||
public static Logger getLogger(String name, String resourceBundleName) {
|
||||
LoggerContext context = getLoggerContext();
|
||||
Logger result = context.demandLogger(name, resourceBundleName);
|
||||
Logger result = demandLogger(name, resourceBundleName);
|
||||
|
||||
// MissingResourceException or IllegalArgumentException can be
|
||||
// thrown by setupResourceInfo().
|
||||
@ -438,11 +449,10 @@ public class Logger {
|
||||
// i.e. caller of sun.util.logging.PlatformLogger.getLogger
|
||||
static Logger getPlatformLogger(String name) {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
LoggerContext context = manager.getSystemContext();
|
||||
|
||||
// all loggers in the system context will default to
|
||||
// the system logger's resource bundle
|
||||
Logger result = context.demandLogger(name);
|
||||
Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1588,7 +1598,8 @@ public class Logger {
|
||||
public ResourceBundle run() {
|
||||
try {
|
||||
return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME,
|
||||
locale);
|
||||
locale,
|
||||
ClassLoader.getSystemClassLoader());
|
||||
} catch (MissingResourceException e) {
|
||||
throw new InternalError(e.toString());
|
||||
}
|
||||
|
177
jdk/test/java/util/logging/CustomLogManager.java
Normal file
177
jdk/test/java/util/logging/CustomLogManager.java
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.logging.*;
|
||||
|
||||
/*
|
||||
* Custom LogManager implementation to verify that the implementation delegates
|
||||
* to the LogManager subclass to register both system logger and user logger.
|
||||
*
|
||||
* The LogManager implementation is the one configuring the logger's property
|
||||
* such as level, handler, etc.
|
||||
*/
|
||||
public class CustomLogManager extends LogManager {
|
||||
static LogManager INSTANCE;
|
||||
Map<String,Logger> namedLoggers = new HashMap<>();
|
||||
Properties props = initConfig();
|
||||
public CustomLogManager() {
|
||||
if (INSTANCE != null) {
|
||||
throw new RuntimeException("CustomLogManager already created");
|
||||
}
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
public synchronized boolean addLogger(Logger logger) {
|
||||
String name = logger.getName();
|
||||
if (namedLoggers.containsKey(name)) {
|
||||
return false;
|
||||
}
|
||||
namedLoggers.put(name, logger);
|
||||
// set level
|
||||
if (props.get(name + ".level") != null) {
|
||||
logger.setLevel(Level.parse(props.getProperty(name + ".level")));
|
||||
}
|
||||
// add handlers
|
||||
if (props.get(name + ".handlers") != null && logger.getHandlers().length == 0) {
|
||||
logger.addHandler(new CustomHandler());
|
||||
}
|
||||
// add parent loggers
|
||||
int ix = 1;
|
||||
for (;;) {
|
||||
int ix2 = name.indexOf(".", ix);
|
||||
if (ix2 < 0) {
|
||||
break;
|
||||
}
|
||||
String pname = name.substring(0, ix2);
|
||||
if (props.get(pname + ".level") != null ||
|
||||
props.get(pname + ".handlers") != null) {
|
||||
// This pname has a level/handlers definition.
|
||||
// Make sure it exists.
|
||||
//
|
||||
// The test doesn't set the parent for simplicity.
|
||||
if (!namedLoggers.containsKey(pname)) {
|
||||
Logger.getLogger(pname);
|
||||
}
|
||||
}
|
||||
ix = ix2 + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized Logger getLogger(String name) {
|
||||
return namedLoggers.get(name);
|
||||
}
|
||||
|
||||
public synchronized Enumeration<String> getLoggerNames() {
|
||||
return Collections.enumeration(namedLoggers.keySet());
|
||||
}
|
||||
|
||||
public String getProperty(String name) {
|
||||
return props.getProperty(name);
|
||||
}
|
||||
|
||||
public void readConfiguration() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public void readConfiguration(InputStream ins) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
private Properties initConfig() {
|
||||
Properties props = new Properties();
|
||||
props.put(".level", "CONFIG");
|
||||
props.put("CustomLogManagerTest.level", "WARNING");
|
||||
props.put("CustomLogManagerTest.handlers", "CustomLogManager$CustomHandler");
|
||||
props.put("SimpleLogManager.level", "INFO");
|
||||
props.put("SimpleLogManager.handlers", "CustomLogManager$CustomHandler");
|
||||
props.put("CustomLogManager$CustomHandler.level", "WARNING");
|
||||
props.put(".handlers", "CustomLogManager$CustomHandler");
|
||||
props.put("org.foo.bar.level", "SEVERE");
|
||||
props.put("org.foo.handlers", "CustomLogManager$CustomHandler");
|
||||
props.put("org.openjdk.level", "SEVERE");
|
||||
props.put("org.openjdk.handlers", "CustomLogManager$CustomHandler");
|
||||
props.put("org.openjdk.core.level", "INFO");
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
public static void checkLogger(String name) {
|
||||
checkLogger(name, null);
|
||||
}
|
||||
|
||||
public static void checkLogger(String name, String resourceBundleName) {
|
||||
Logger logger = INSTANCE.getLogger(name);
|
||||
if (logger == null) {
|
||||
throw new RuntimeException("Logger \"" + name + "\" not exist");
|
||||
}
|
||||
System.out.format("Logger \"%s\" level=%s handlers=%s resourcebundle=%s%n",
|
||||
name, logger.getLevel(),
|
||||
Arrays.toString(logger.getHandlers()),
|
||||
logger.getResourceBundleName());
|
||||
String rb = logger.getResourceBundleName();
|
||||
if (rb != resourceBundleName && (rb == null || rb.equals(resourceBundleName))) {
|
||||
throw new RuntimeException("Logger \"" + name +
|
||||
"\" unexpected resource bundle: " + rb);
|
||||
}
|
||||
|
||||
String value = INSTANCE.getProperty(name + ".level");
|
||||
String level = logger.getLevel() != null ? logger.getLevel().getName() : null;
|
||||
if (level != value && (level == null || level.equals(value))) {
|
||||
throw new RuntimeException("Logger \"" + name + "\" unexpected level: " + level);
|
||||
}
|
||||
|
||||
Handler[] handlers = logger.getHandlers();
|
||||
String hdl = INSTANCE.getProperty(name + ".handlers");
|
||||
if ((hdl == null && handlers.length != 0) ||
|
||||
(hdl != null && handlers.length != 1)) {
|
||||
throw new RuntimeException("Logger \"" + name + "\" unexpected handler: " +
|
||||
Arrays.toString(handlers));
|
||||
}
|
||||
checkParents(name);
|
||||
}
|
||||
|
||||
private static void checkParents(String name) {
|
||||
int ix = 1;
|
||||
for (;;) {
|
||||
int ix2 = name.indexOf(".", ix);
|
||||
if (ix2 < 0) {
|
||||
break;
|
||||
}
|
||||
String pname = name.substring(0, ix2);
|
||||
if (INSTANCE.getProperty(pname + ".level") != null ||
|
||||
INSTANCE.getProperty(pname + ".handlers") != null) {
|
||||
// This pname has a level/handlers definition.
|
||||
// Make sure it exists.
|
||||
checkLogger(pname);
|
||||
}
|
||||
ix = ix2 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// only CustomLogManager can create an instance of CustomHandler
|
||||
private class CustomHandler extends StreamHandler {
|
||||
}
|
||||
}
|
63
jdk/test/java/util/logging/CustomLogManagerTest.java
Normal file
63
jdk/test/java/util/logging/CustomLogManagerTest.java
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import java.util.logging.*;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8005615
|
||||
* @summary Add loggers to custom log manager
|
||||
*
|
||||
* @compile -XDignore.symbol.file CustomLogManagerTest.java CustomLogManager.java
|
||||
* @run main/othervm -Djava.util.logging.manager=CustomLogManager CustomLogManagerTest
|
||||
*/
|
||||
public class CustomLogManagerTest {
|
||||
private static final String RESOURCE_BUNDLE = "sun.util.logging.resources.logging";
|
||||
public static void main(String[] args) {
|
||||
String mgr = System.getProperty("java.util.logging.manager");
|
||||
if (!mgr.equals("CustomLogManager")) {
|
||||
throw new RuntimeException("java.util.logging.manager not set");
|
||||
}
|
||||
|
||||
Logger.getLogger(CustomLogManagerTest.class.getName());
|
||||
Logger.getLogger("org.foo.Foo");
|
||||
Logger.getLogger("org.foo.bar.Foo", RESOURCE_BUNDLE);
|
||||
// platform logger will be set with the default system resource bundle
|
||||
PlatformLogger.getLogger("org.openjdk.core.logger");
|
||||
|
||||
if (LogManager.getLogManager() != CustomLogManager.INSTANCE) {
|
||||
throw new RuntimeException(LogManager.getLogManager() + " not CustomLogManager");
|
||||
}
|
||||
|
||||
CustomLogManager.checkLogger(CustomLogManagerTest.class.getName());
|
||||
CustomLogManager.checkLogger("org.foo.Foo");
|
||||
CustomLogManager.checkLogger("org.foo.bar.Foo", RESOURCE_BUNDLE);
|
||||
CustomLogManager.checkLogger(Logger.GLOBAL_LOGGER_NAME);
|
||||
CustomLogManager.checkLogger("");
|
||||
CustomLogManager.checkLogger("org.openjdk.core.logger", RESOURCE_BUNDLE);
|
||||
}
|
||||
}
|
113
jdk/test/java/util/logging/SimpleLogManager.java
Normal file
113
jdk/test/java/util/logging/SimpleLogManager.java
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.util.logging.*;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8005615
|
||||
* @summary A LogManager subclass overrides its own implementation of named
|
||||
* logger (see the subclassing information in the Logger class specification)
|
||||
*
|
||||
* @compile -XDignore.symbol.file CustomLogManager.java SimpleLogManager.java
|
||||
* @run main/othervm -Djava.util.logging.manager=SimpleLogManager SimpleLogManager
|
||||
*/
|
||||
public class SimpleLogManager extends CustomLogManager {
|
||||
public static void main(String[] args) {
|
||||
String classname = System.getProperty("java.util.logging.manager");
|
||||
if (!classname.equals("SimpleLogManager")) {
|
||||
throw new RuntimeException("java.util.logging.manager not set");
|
||||
}
|
||||
|
||||
Logger logger = Logger.getLogger(SimpleLogManager.class.getName());
|
||||
Logger.getLogger("org.foo.bar.Foo");
|
||||
|
||||
// a platform logger used by the system code is just a Logger instance.
|
||||
PlatformLogger.getLogger("org.openjdk.core.logger");
|
||||
|
||||
LogManager mgr = LogManager.getLogManager();
|
||||
if (mgr != CustomLogManager.INSTANCE || !(mgr instanceof SimpleLogManager)) {
|
||||
throw new RuntimeException(LogManager.getLogManager() + " not SimpleLogManager");
|
||||
}
|
||||
|
||||
checkCustomLogger(SimpleLogManager.class.getName(), null);
|
||||
checkCustomLogger("org.foo.bar.Foo", null);
|
||||
checkCustomLogger("org.openjdk.core.logger", "sun.util.logging.resources.logging");
|
||||
|
||||
// ## The LogManager.demandLogger method does not handle custom log manager
|
||||
// ## that overrides the getLogger method to return a custom logger
|
||||
// ## (see the test case in 8005640). Logger.getLogger may return
|
||||
// ## a Logger instance but LogManager overrides it with a custom Logger
|
||||
// ## instance like this case.
|
||||
//
|
||||
// However, the specification of LogManager and Logger subclassing is
|
||||
// not clear whether this is supported or not. The following check
|
||||
// just captures the current behavior.
|
||||
if (logger instanceof CustomLogger) {
|
||||
throw new RuntimeException(logger + " not CustomLogger");
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkCustomLogger(String name, String resourceBundleName) {
|
||||
CustomLogManager.checkLogger(name, resourceBundleName);
|
||||
Logger logger1 = Logger.getLogger(name);
|
||||
Logger logger2 = LogManager.getLogManager().getLogger(name);
|
||||
if (logger1 != logger2) {
|
||||
throw new RuntimeException(logger1 + " != " + logger2);
|
||||
}
|
||||
if (!(logger1 instanceof CustomLogger)) {
|
||||
throw new RuntimeException(logger1 + " not CustomLogger");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This SimpleLogManager overrides the addLogger method to replace
|
||||
* the given logger with a custom logger.
|
||||
*
|
||||
* It's unclear what the recommended way to use custom logger is.
|
||||
* A LogManager subclass might override the getLogger method to return
|
||||
* a custom Logger and create a new custom logger if not exist so that
|
||||
* Logger.getLogger() can return a custom Logger instance but that violates
|
||||
* the LogManager.getLogger() spec which should return null if not found.
|
||||
*/
|
||||
public synchronized boolean addLogger(Logger logger) {
|
||||
String name = logger.getName();
|
||||
if (namedLoggers.containsKey(name)) {
|
||||
return false;
|
||||
}
|
||||
CustomLogger newLogger = new CustomLogger(logger);
|
||||
super.addLogger(newLogger);
|
||||
return true;
|
||||
}
|
||||
|
||||
public class CustomLogger extends Logger {
|
||||
CustomLogger(Logger logger) {
|
||||
super(logger.getName(), logger.getResourceBundleName());
|
||||
}
|
||||
CustomLogger(String name) {
|
||||
super(name, null);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user