365302: made map of loggers concurrent and shared in abstract

This commit is contained in:
Greg Wilkins 2012-01-12 20:39:24 +11:00
parent 08f4b79a66
commit 564cf7329c
16 changed files with 185 additions and 120 deletions

View File

@ -5,6 +5,6 @@ contexts:MMBean: Deployed Contexts
appProviders:MMBean: Application Providers appProviders:MMBean: Application Providers
getApps(java.lang.String):MBean:ACTION: List apps that are located at specified App LifeCycle node getApps(java.lang.String):MBean:ACTION: List apps that are located at specified App LifeCycle node
getApps(java.lang.String)[0]:nodeName: Name of the App LifeCycle node getApps(java.lang.String)[0]:nodeName: Name of the App LifeCycle node
requestAppGoal(java.lang.String,java.lang.String) ACTION: Request the app to be moved to the specified App LifeCycle node requestAppGoal(java.lang.String,java.lang.String):ACTION: Request the app to be moved to the specified App LifeCycle node
requestAppGoal(java.lang.String,java.lang.String)[0]:appId:App identifier requestAppGoal(java.lang.String,java.lang.String)[0]:appId:App identifier
requestAppGoal(java.lang.String,java.lang.String)[1]:nodeName:Name of the App LifeCycle node requestAppGoal(java.lang.String,java.lang.String)[1]:nodeName:Name of the App LifeCycle node

View File

@ -48,11 +48,10 @@
</Call> </Call>
<!-- Add the static log --> <!-- Add the static log -->
<Get id="Logger" class="org.eclipse.jetty.util.log.Log" name="log" />
<Ref id="MBeanContainer"> <Ref id="MBeanContainer">
<Call name="addBean"> <Call name="addBean">
<Arg> <Arg>
<Ref id="Logger" /> <New class="org.eclipse.jetty.util.log.Log"/>
</Arg> </Arg>
</Call> </Call>
</Ref> </Ref>

View File

@ -0,0 +1,48 @@
// ========================================================================
// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.util.log.jmx;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.jmx.ObjectMBean;
import org.eclipse.jetty.util.log.Log;
/* ------------------------------------------------------------ */
/**
*/
public class LogMBean extends ObjectMBean
{
public LogMBean(Object managedObject)
{
super(managedObject);
}
public List<String> getLoggers()
{
List<String> keySet = new ArrayList<String>(Log.getLoggers().keySet());
return keySet;
}
public boolean isDebugEnabled(String logger)
{
return Log.getLogger(logger).isDebugEnabled();
}
public void setDebugEnabled(String logger, Boolean enabled)
{
Log.getLogger(logger).setDebugEnabled(enabled);
}
}

View File

@ -0,0 +1,8 @@
Log: Jetty Logging implementaton
loggers:MBean: List of all instantiated loggers
debugEnabled:RW: True if debug enabled for root logger Log.LOG
isDebugEnabled(java.lang.String):MBean:INFO: True if debug is enabled for the given logger
isDebugEnabled(java.lang.String)[0]:loggerName: Name of the logger to return isDebugEnabled for
setDebugEnabled(java.lang.String,java.lang.Boolean):MBean:ACTION: Set debug enabled for the given logger
setDebugEnabled(java.lang.String,java.lang.Boolean)[0]:loggerName: Name of the logger to set debug enabled
setDebugEnabled(java.lang.String,java.lang.Boolean)[1]:enabled: true to enable debug, false otherwise

View File

@ -1,3 +0,0 @@
Logger: Jetty Logging implementaton
debugEnabled: True if debug enabled
name: Logger name

View File

@ -1,2 +1 @@
ThreadMonitor: Detect and report spinning and deadlocked threads ThreadMonitor: Detect and report spinning and deadlocked threads

View File

@ -3,4 +3,3 @@ name: RO:Name
displayName: RO:Display Name displayName: RO:Display Name
className: RO:Class Name className: RO:Class Name
initParameters: RO:Initial parameters initParameters: RO:Initial parameters

View File

@ -0,0 +1,59 @@
package org.eclipse.jetty.util.log;
/* ------------------------------------------------------------ */
/** Abstract Logger.
* Manages the atomic registration of the logger by name.
*/
public abstract class AbstractLogger implements Logger
{
public final Logger getLogger(String name)
{
if (isBlank(name))
return this;
final String basename = getName();
final String fullname = (isBlank(basename) || Log.getRootLogger()==this)?name:(basename + "." + name);
Logger logger = Log.getLoggers().get(fullname);
if (logger == null)
{
Logger newlog = newLogger(fullname);
logger = Log.getMutableLoggers().putIfAbsent(fullname,newlog);
if (logger == null)
logger=newlog;
}
return logger;
}
protected abstract Logger newLogger(String fullname);
/**
* A more robust form of name blank test. Will return true for null names, and names that have only whitespace
*
* @param name
* the name to test
* @return true for null or blank name, false if any non-whitespace character is found.
*/
private static boolean isBlank(String name)
{
if (name == null)
{
return true;
}
int size = name.length();
char c;
for (int i = 0; i < size; i++)
{
c = name.charAt(i);
if (!Character.isWhitespace(c))
{
return false;
}
}
return true;
}
}

View File

@ -28,7 +28,7 @@ import java.util.logging.Level;
* standard java.util.logging configuration</a>. * standard java.util.logging configuration</a>.
* </p> * </p>
*/ */
public class JavaUtilLog implements Logger public class JavaUtilLog extends AbstractLogger
{ {
private Level configuredLevel; private Level configuredLevel;
private java.util.logging.Logger _logger; private java.util.logging.Logger _logger;
@ -116,9 +116,12 @@ public class JavaUtilLog implements Logger
_logger.log(Level.FINE, msg, thrown); _logger.log(Level.FINE, msg, thrown);
} }
public Logger getLogger(String name) /**
* Create a Child Logger of this Logger.
*/
protected Logger newLogger(String fullname)
{ {
return new JavaUtilLog(name); return new JavaUtilLog(fullname);
} }
public void ignore(Throwable ignored) public void ignore(Throwable ignored)

View File

@ -19,10 +19,14 @@ import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.Loader;
@ -61,7 +65,11 @@ public class Log
*/ */
public static boolean __ignored; public static boolean __ignored;
public static Map<String, Logger> __loggers = new HashMap<String, Logger>(); /**
* Hold loggers only.
*/
private final static ConcurrentMap<String, Logger> __loggers = new ConcurrentHashMap<String, Logger>();
static static
{ {
@ -427,14 +435,16 @@ public class Log
Logger logger = __loggers.get(name); Logger logger = __loggers.get(name);
if(logger==null) if(logger==null)
{
logger = LOG.getLogger(name); logger = LOG.getLogger(name);
__loggers.put(name,logger);
}
return logger; return logger;
} }
static ConcurrentMap<String, Logger> getMutableLoggers()
{
return __loggers;
}
/** /**
* Get a map of all configured {@link Logger} instances. * Get a map of all configured {@link Logger} instances.
* *
@ -442,6 +452,6 @@ public class Log
*/ */
public static Map<String, Logger> getLoggers() public static Map<String, Logger> getLoggers()
{ {
return __loggers; return Collections.unmodifiableMap(__loggers);
} }
} }

View File

@ -18,7 +18,7 @@ import java.lang.reflect.Method;
/** /**
* *
*/ */
public class LoggerLog implements Logger public class LoggerLog extends AbstractLogger
{ {
private final Object _logger; private final Object _logger;
private final Method _debugMT; private final Method _debugMT;
@ -189,11 +189,14 @@ public class LoggerLog implements Logger
} }
} }
public Logger getLogger(String name) /**
* Create a Child Logger of this Logger.
*/
protected Logger newLogger(String fullname)
{ {
try try
{ {
Object logger=_getLoggerN.invoke(_logger, name); Object logger=_getLoggerN.invoke(_logger, fullname);
return new LoggerLog(logger); return new LoggerLog(logger);
} }
catch (Exception e) catch (Exception e)

View File

@ -18,7 +18,7 @@ package org.eclipse.jetty.util.log;
/** /**
* Slf4jLog Logger * Slf4jLog Logger
*/ */
public class Slf4jLog implements Logger public class Slf4jLog extends AbstractLogger
{ {
private final org.slf4j.Logger _logger; private final org.slf4j.Logger _logger;
@ -114,9 +114,12 @@ public class Slf4jLog implements Logger
warn("setDebugEnabled not implemented",null,null); warn("setDebugEnabled not implemented",null,null);
} }
public Logger getLogger(String name) /**
* Create a Child Logger of this Logger.
*/
protected Logger newLogger(String fullname)
{ {
return new Slf4jLog(name); return new Slf4jLog(fullname);
} }
public void ignore(Throwable ignored) public void ignore(Throwable ignored)

View File

@ -35,7 +35,7 @@ import org.eclipse.jetty.util.DateCache;
* used for logging. For named debuggers, the system property name+".LONG" is checked. If it is not not set, then * used for logging. For named debuggers, the system property name+".LONG" is checked. If it is not not set, then
* "org.eclipse.jetty.util.log.LONG" is used as the default. * "org.eclipse.jetty.util.log.LONG" is used as the default.
*/ */
public class StdErrLog implements Logger public class StdErrLog extends AbstractLogger
{ {
private static final String EOL = System.getProperty("line.separator"); private static final String EOL = System.getProperty("line.separator");
private static DateCache _dateCache; private static DateCache _dateCache;
@ -45,11 +45,6 @@ public class StdErrLog implements Logger
Log.__props.getProperty("org.eclipse.jetty.util.log.stderr.SOURCE","false"))); Log.__props.getProperty("org.eclipse.jetty.util.log.stderr.SOURCE","false")));
private final static boolean __long = Boolean.parseBoolean(Log.__props.getProperty("org.eclipse.jetty.util.log.stderr.LONG","false")); private final static boolean __long = Boolean.parseBoolean(Log.__props.getProperty("org.eclipse.jetty.util.log.stderr.LONG","false"));
/**
* Tracking for child loggers only.
*/
private final static ConcurrentMap<String, StdErrLog> __loggers = new ConcurrentHashMap<String, StdErrLog>();
static static
{ {
String deprecatedProperties[] = String deprecatedProperties[] =
@ -332,28 +327,22 @@ public class StdErrLog implements Logger
{ {
if (enabled) if (enabled)
{ {
synchronized (__loggers) this._level = LEVEL_DEBUG;
{
this._level = LEVEL_DEBUG;
// Boot stomp all cached log levels to DEBUG for (Logger log : Log.getLoggers().values())
for(StdErrLog log: __loggers.values()) {
{ if (log instanceof StdErrLog)
log._level = LEVEL_DEBUG; ((StdErrLog)log).setLevel(LEVEL_DEBUG);
}
} }
} }
else else
{ {
synchronized (__loggers) this._level = this._configuredLevel;
for (Logger log : Log.getLoggers().values())
{ {
this._level = this._configuredLevel; if (log instanceof StdErrLog)
((StdErrLog)log).setLevel(((StdErrLog)log)._configuredLevel);
// restore all cached log configured levels
for(StdErrLog log: __loggers.values())
{
log._level = log._configuredLevel;
}
} }
} }
} }
@ -570,67 +559,18 @@ public class StdErrLog implements Logger
} }
} }
/**
* A more robust form of name blank test. Will return true for null names, and names that have only whitespace
*
* @param name
* the name to test
* @return true for null or blank name, false if any non-whitespace character is found.
*/
private static boolean isBlank(String name)
{
if (name == null)
{
return true;
}
int size = name.length();
char c;
for (int i = 0; i < size; i++)
{
c = name.charAt(i);
if (!Character.isWhitespace(c))
{
return false;
}
}
return true;
}
/** /**
* Get a Child Logger relative to this Logger. * Create a Child Logger of this Logger.
*
* @param name
* the child name
* @return the appropriate child logger (if name specified results in a new unique child)
*/ */
public Logger getLogger(String name) protected Logger newLogger(String fullname)
{ {
if (isBlank(name)) StdErrLog logger = new StdErrLog(fullname);
{ // Preserve configuration for new loggers configuration
return this; logger.setPrintLongNames(_printLongNames);
} // Let Level come from configured Properties instead - sel.setLevel(_level);
logger.setSource(_source);
String fullname = name; logger._stderr = this._stderr;
if (!isBlank(_name))
{
fullname = _name + "." + name;
}
StdErrLog logger = __loggers.get(fullname);
if (logger == null)
{
StdErrLog sel = new StdErrLog(fullname);
// Preserve configuration for new loggers configuration
sel.setPrintLongNames(_printLongNames);
// Let Level come from configured Properties instead - sel.setLevel(_level);
sel.setSource(_source);
sel._stderr = this._stderr;
logger = __loggers.putIfAbsent(fullname,sel);
if (logger == null)
{
logger = sel;
}
}
return logger; return logger;
} }

View File

@ -15,6 +15,9 @@ package org.eclipse.jetty.util.log;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import java.util.HashMap;
import java.util.Map;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@ -23,18 +26,23 @@ import org.junit.Test;
public class LogTest public class LogTest
{ {
private static Logger originalLogger; private static Logger originalLogger;
private static Map<String,Logger> originalLoggers;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@BeforeClass @BeforeClass
public static void rememberOriginalLogger() public static void rememberOriginalLogger()
{ {
originalLogger = Log.getLog(); originalLogger = Log.getLog();
originalLoggers = new HashMap<String, Logger>(Log.getLoggers());
Log.getMutableLoggers().clear();
} }
@AfterClass @AfterClass
public static void restoreOriginalLogger() public static void restoreOriginalLogger()
{ {
Log.setLog(originalLogger); Log.setLog(originalLogger);
Log.getMutableLoggers().clear();
Log.getMutableLoggers().putAll(originalLoggers);
} }
@Test @Test

View File

@ -1,26 +1,9 @@
package org.eclipse.jetty.util.log; package org.eclipse.jetty.util.log;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
public class NamedLogTest public class NamedLogTest
{ {
private static Logger originalLogger;
@SuppressWarnings("deprecation")
@BeforeClass
public static void rememberOriginalLogger()
{
originalLogger = Log.getLog();
}
@AfterClass
public static void restoreOriginalLogger()
{
Log.setLog(originalLogger);
}
@Test @Test
public void testNamedLogging() public void testNamedLogging()
{ {
@ -37,7 +20,7 @@ public class NamedLogTest
red.generateLogs(); red.generateLogs();
green.generateLogs(); green.generateLogs();
blue.generateLogs(); blue.generateLogs();
output.assertContains(Red.class.getName()); output.assertContains(Red.class.getName());
output.assertContains(Green.class.getName()); output.assertContains(Green.class.getName());
output.assertContains(Blue.class.getName()); output.assertContains(Blue.class.getName());

View File

@ -43,4 +43,10 @@ public class StdErrCapture
String output = new String(test.toByteArray()); String output = new String(test.toByteArray());
Assert.assertThat(output,not(containsString(unexpectedString))); Assert.assertThat(output,not(containsString(unexpectedString)));
} }
public String toString()
{
err.flush();
return new String(test.toByteArray());
}
} }