Logging bug fixes + new functionality

* Fixed names that were associated with CentralLogger to be fully
  qualified (to match behaviour present in slf4j + log4j +
  commons-logging + java.util.logging)
* Allowed for configuration keys "logger.*.appenders" to contain
  negative logger ids to remove an appender from that heirarchy in the
  configuration.

  Example:
  root.level=INFO
  root.appenders=rollLog

  logger.AUDIT.level=INFO
  logger.AUDIT.appenders=-rollLog,auditLog

  appender.rollLog.class=org.eclipse.jetty.logging.impl.RollingFileAppender
  appender.rollLog.filename=${jetty.home}/logs/central.log

  appender.auditLog.class=org.eclipse.jetty.logging.impl.RollingFileAppender
  appender.auditLog.filename=${jetty.home}/logs/audit.log

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@867 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Joakim Erdfelt 2009-09-10 23:05:57 +00:00
parent e87dfd072b
commit 828f08fe8d
8 changed files with 239 additions and 45 deletions

View File

@ -22,6 +22,10 @@ import java.io.IOException;
*/ */
public interface Appender public interface Appender
{ {
void setId(String id);
String getId();
void append(String date, int ms, Severity severity, String name, String message, Throwable t) throws IOException; void append(String date, int ms, Severity severity, String name, String message, Throwable t) throws IOException;
void setProperty(String key, String value) throws Exception; void setProperty(String key, String value) throws Exception;

View File

@ -23,6 +23,7 @@ import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
@ -48,6 +49,8 @@ public class CentralLoggerConfig
private static void configureAppender(Properties props, String id, Appender appender) private static void configureAppender(Properties props, String id, Appender appender)
{ {
appender.setId(id);
// Collect configuration fields for appender id // Collect configuration fields for appender id
Pattern appenderIdRegex = Pattern.compile("^appender\\." + id + "\\.([^\\.]*)$"); Pattern appenderIdRegex = Pattern.compile("^appender\\." + id + "\\.([^\\.]*)$");
Matcher match; Matcher match;
@ -88,7 +91,9 @@ public class CentralLoggerConfig
out.printf("%sAppenders: ",prefix); out.printf("%sAppenders: ",prefix);
for (Iterator<Appender> it = cl.getAppenders().iterator(); it.hasNext();) for (Iterator<Appender> it = cl.getAppenders().iterator(); it.hasNext();)
{ {
out.print(it.next().getClass().getSimpleName()); Appender ap = it.next();
// out.printf("(%s) %s",ap.getClass().getSimpleName(),ap);
out.print(ap);
if (it.hasNext()) if (it.hasNext())
{ {
out.print(", "); out.print(", ");
@ -111,26 +116,38 @@ public class CentralLoggerConfig
} }
} }
private static List<Appender> getAppenders(Properties props, String key, Map<String, Appender> declaredAppenders) private static Set<String> getAppenderIds(Properties props, String key)
{ {
Set<String> ids = new TreeSet<String>();
String value = props.getProperty(key); String value = props.getProperty(key);
if (value == null) if (value == null)
{ {
return null; return ids;
} }
String ids[] = value.split(","); String parts[] = value.split(",");
List<Appender> appenders = new ArrayList<Appender>(); for (int i = 0, n = parts.length; i < n; i++)
// ensure ids exist as declared as well.
for (int i = 0, n = ids.length; i < n; i++)
{ {
if (declaredAppenders.containsKey(ids[i])) ids.add(parts[i].trim());
}
return ids;
}
private static List<Appender> getAppenders(Properties props, String key, Map<String, Appender> declaredAppenders)
{
Set<String> ids = getAppenderIds(props,key);
List<Appender> appenders = new ArrayList<Appender>();
for (String id : ids)
{
if (declaredAppenders.containsKey(id))
{ {
appenders.add(declaredAppenders.get(ids[i])); appenders.add(declaredAppenders.get(id));
} }
else else
{ {
System.err.println("No such Appender: " + ids[i]); System.err.println("No such Appender: " + id);
} }
} }
@ -230,9 +247,8 @@ public class CentralLoggerConfig
Map<String, Appender> declaredAppenders = getDeclaredAppenders(props); Map<String, Appender> declaredAppenders = getDeclaredAppenders(props);
root.appenders = getAppenders(props,"root.appenders",declaredAppenders); root.appenders = getAppenders(props,"root.appenders",declaredAppenders);
if (root.appenders == null) if (root.appenders.isEmpty())
{ {
root.appenders = new ArrayList<Appender>();
// Default (if not specified for root) // Default (if not specified for root)
root.appenders.add(new ConsoleAppender()); root.appenders.add(new ConsoleAppender());
} }
@ -265,10 +281,29 @@ public class CentralLoggerConfig
// Set loggers & levels of OTHER nodes // Set loggers & levels of OTHER nodes
for (String id : ids) for (String id : ids)
{ {
System.out.println("Processing child id: " + id);
CentralLoggerConfig childlog = root.getConfiguredLogger(id); CentralLoggerConfig childlog = root.getConfiguredLogger(id);
childlog.level = Severity.valueOf(props.getProperty("logger." + id + ".level","INFO")); childlog.level = Severity.valueOf(props.getProperty("logger." + id + ".level","INFO"));
childlog.addAppenders(getAppenders(props,"logger." + id + ".appenders",declaredAppenders)); Set<String> appenderIds = getAppenderIds(props,"logger." + id + ".appenders");
for (String appenderId : appenderIds)
{
if (appenderId.startsWith("-"))
{
// Remove an appender
childlog.removeAppenderById(appenderId.substring(1));
}
else
{
// Add an appender
if (declaredAppenders.containsKey(appenderId))
{
childlog.addAppender(declaredAppenders.get(appenderId));
}
else
{
System.err.println("No such Appender: " + appenderId);
}
}
}
} }
return root; return root;
@ -293,7 +328,7 @@ public class CentralLoggerConfig
this.appenders.addAll(copyLogger.appenders); this.appenders.addAll(copyLogger.appenders);
this.level = copyLogger.level; this.level = copyLogger.level;
this.logger = new CentralLogger(name,appenders.toArray(new Appender[] {}),level); this.logger = new CentralLogger(this.name,appenders.toArray(new Appender[] {}),level);
} }
private CentralLoggerConfig(String name) private CentralLoggerConfig(String name)
@ -301,14 +336,22 @@ public class CentralLoggerConfig
this.name = name; this.name = name;
} }
private void addAppenders(List<Appender> moreAppenders) private void addAppender(Appender appender)
{ {
if (moreAppenders == null) getAppenders().add(appender);
}
private void removeAppenderById(String id)
{
ListIterator<Appender> it = appenders.listIterator();
while (it.hasNext())
{ {
return; Appender appender = it.next();
if (id.equals(appender.getId()))
{
it.remove();
}
} }
getAppenders().addAll(moreAppenders);
this.logger = new CentralLogger(name,appenders.toArray(new Appender[] {}),level);
} }
public void dumpTree(PrintStream out) public void dumpTree(PrintStream out)

View File

@ -22,6 +22,18 @@ import java.io.IOException;
*/ */
public class ConsoleAppender implements Appender public class ConsoleAppender implements Appender
{ {
private String id;
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public void append(String date, int ms, Severity severity, String name, String message, Throwable t) public void append(String date, int ms, Severity severity, String name, String message, Throwable t)
{ {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
@ -65,4 +77,10 @@ public class ConsoleAppender implements Appender
{ {
/* nothing to do here */ /* nothing to do here */
} }
@Override
public String toString()
{
return "ConsoleAppender[" + id + "]";
}
} }

View File

@ -29,6 +29,7 @@ import org.eclipse.jetty.util.RolloverFileOutputStream;
*/ */
public class RollingFileAppender implements Appender public class RollingFileAppender implements Appender
{ {
private static final byte[] LN = System.getProperty("line.separator","\n").getBytes();
private RolloverFileOutputStream out; private RolloverFileOutputStream out;
private String filename; private String filename;
private File file; private File file;
@ -37,6 +38,17 @@ public class RollingFileAppender implements Appender
private TimeZone zone = TimeZone.getDefault(); private TimeZone zone = TimeZone.getDefault();
private String dateFormat = "yyyy_MM_dd"; private String dateFormat = "yyyy_MM_dd";
private String backupFormat = "HHmmssSSS"; private String backupFormat = "HHmmssSSS";
private String id;
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public void append(String date, int ms, Severity severity, String name, String message, Throwable t) throws IOException public void append(String date, int ms, Severity severity, String name, String message, Throwable t) throws IOException
{ {
@ -60,9 +72,11 @@ public class RollingFileAppender implements Appender
buf.append(':').append(message); buf.append(':').append(message);
out.write(buf.toString().getBytes()); out.write(buf.toString().getBytes());
out.write(LN);
if (t != null) if (t != null)
{ {
t.printStackTrace(new PrintStream(out)); t.printStackTrace(new PrintStream(out));
out.write(LN);
} }
out.flush(); out.flush();
} }
@ -195,4 +209,10 @@ public class RollingFileAppender implements Appender
{ {
this.zone = zone; this.zone = zone;
} }
@Override
public String toString()
{
return "RollingFileAppender[" + id + "|" + filename + "]";
}
} }

View File

@ -26,6 +26,7 @@ import org.eclipse.jetty.logging.impl.TestAppender.LogEvent;
public class CentralizedLoggingTest extends TestCase public class CentralizedLoggingTest extends TestCase
{ {
private static final String LOGGING_SERVLET_ID = "org.eclipse.jetty.tests.webapp.LoggingServlet";
private XmlConfiguredJetty jetty; private XmlConfiguredJetty jetty;
private void assertContainsLogEvents(TestAppender capturedEvents, LogEvent[] expectedLogs) private void assertContainsLogEvents(TestAppender capturedEvents, LogEvent[] expectedLogs)
@ -74,14 +75,14 @@ public class CentralizedLoggingTest extends TestCase
SimpleRequest.get(jetty,"/dummy-webapp-logging-java/logging"); SimpleRequest.get(jetty,"/dummy-webapp-logging-java/logging");
TestAppender.LogEvent expectedLogs[] = TestAppender.LogEvent expectedLogs[] =
{ new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(log4j) initialized",null), { new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(log4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(log4j) GET requested",null), new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(log4j) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(slf4j) initialized",null), new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(slf4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(slf4j) GET requested",null), new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(slf4j) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(commons-logging) initialized",null), new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(commons-logging) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(commons-logging) GET requested",null), new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(commons-logging) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(java) initialized",null), new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(java) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(java) GET requested",null) }; new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(java) GET requested",null) };
assertContainsLogEvents(testAppender,expectedLogs); assertContainsLogEvents(testAppender,expectedLogs);
} }

View File

@ -38,6 +38,7 @@ import org.eclipse.jetty.webapp.WebAppContext;
*/ */
public class EmbeddedCentralizedLoggingTest extends TestCase public class EmbeddedCentralizedLoggingTest extends TestCase
{ {
private static final String LOGGING_SERVLET_ID = "org.eclipse.jetty.tests.webapp.LoggingServlet";
private TestAppender testAppender; private TestAppender testAppender;
private void assertContainsLogEvents(TestAppender capturedEvents, LogEvent[] expectedLogs) private void assertContainsLogEvents(TestAppender capturedEvents, LogEvent[] expectedLogs)
@ -146,14 +147,14 @@ public class EmbeddedCentralizedLoggingTest extends TestCase
server.stop(); server.stop();
TestAppender.LogEvent expectedLogs[] = TestAppender.LogEvent expectedLogs[] =
{ new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(log4j) initialized",null), { new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(log4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(log4j) GET requested",null), new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(log4j) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(slf4j) initialized",null), new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(slf4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(slf4j) GET requested",null), new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(slf4j) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(commons-logging) initialized",null), new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(commons-logging) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(commons-logging) GET requested",null), new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(commons-logging) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(java) initialized",null), new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(java) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(java) GET requested",null) }; new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(java) GET requested",null) };
assertContainsLogEvents(testAppender,expectedLogs); assertContainsLogEvents(testAppender,expectedLogs);
} }
@ -169,8 +170,8 @@ public class EmbeddedCentralizedLoggingTest extends TestCase
server.stop(); server.stop();
TestAppender.LogEvent expectedLogs[] = TestAppender.LogEvent expectedLogs[] =
{ new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(commons-logging) initialized",null), { new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(commons-logging) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(commons-logging) GET requested",null) }; new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(commons-logging) GET requested",null) };
assertContainsLogEvents(testAppender,expectedLogs); assertContainsLogEvents(testAppender,expectedLogs);
} }
@ -186,8 +187,8 @@ public class EmbeddedCentralizedLoggingTest extends TestCase
server.stop(); server.stop();
TestAppender.LogEvent expectedLogs[] = TestAppender.LogEvent expectedLogs[] =
{ new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(java) initialized",null), { new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(java) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(java) GET requested",null) }; new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(java) GET requested",null) };
assertContainsLogEvents(testAppender,expectedLogs); assertContainsLogEvents(testAppender,expectedLogs);
} }
@ -203,8 +204,8 @@ public class EmbeddedCentralizedLoggingTest extends TestCase
server.stop(); server.stop();
TestAppender.LogEvent expectedLogs[] = TestAppender.LogEvent expectedLogs[] =
{ new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(log4j) initialized",null), { new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(log4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(log4j) GET requested",null) }; new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(log4j) GET requested",null) };
assertContainsLogEvents(testAppender,expectedLogs); assertContainsLogEvents(testAppender,expectedLogs);
} }
@ -220,8 +221,8 @@ public class EmbeddedCentralizedLoggingTest extends TestCase
server.stop(); server.stop();
TestAppender.LogEvent expectedLogs[] = TestAppender.LogEvent expectedLogs[] =
{ new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(slf4j) initialized",null), { new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(slf4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(slf4j) GET requested",null) }; new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(slf4j) GET requested",null) };
assertContainsLogEvents(testAppender,expectedLogs); assertContainsLogEvents(testAppender,expectedLogs);
} }

View File

@ -59,6 +59,63 @@ public class ConfiguredLoggerTest extends TestCase
} }
} }
private void assertAppendersById(CentralLoggerConfig logger, String... ids)
{
assertNotNull("Appenders should not be null",logger.getAppenders());
assertTrue("Should have appenders",logger.getAppenders().size() >= 1);
List<String> expectedAppenders = new ArrayList<String>();
List<String> actualAppenders = new ArrayList<String>();
for (String id : ids)
{
expectedAppenders.add(id);
}
for (Appender appender : logger.getAppenders())
{
actualAppenders.add(appender.getId());
}
// Sort
Collections.sort(expectedAppenders);
Collections.sort(actualAppenders);
boolean same = true;
// Same Size?
if (expectedAppenders.size() != actualAppenders.size())
{
same = false;
}
// Same Content?
for (int i = 0, n = expectedAppenders.size(); i < n; i++)
{
if (!expectedAppenders.get(i).equals(actualAppenders.get(i)))
{
same = false;
break;
}
}
if (!same)
{
System.out.println("/* Actual */");
for (String id : actualAppenders)
{
System.out.println(id);
}
System.out.println("/* Expected */");
for (String id : expectedAppenders)
{
System.out.println(id);
}
fail("Not the same appender id list.");
}
}
private void assertSeverityLevel(CentralLoggerConfig logger, Severity severity) private void assertSeverityLevel(CentralLoggerConfig logger, Severity severity)
{ {
assertEquals("Severity",severity,logger.getLevel()); assertEquals("Severity",severity,logger.getLevel());
@ -184,4 +241,42 @@ public class ConfiguredLoggerTest extends TestCase
assertSeverityLevel(implLogger,Severity.WARN); assertSeverityLevel(implLogger,Severity.WARN);
assertAppenders(implLogger,ConsoleAppender.class,TestAppender.class); assertAppenders(implLogger,ConsoleAppender.class,TestAppender.class);
} }
public void testGetConfiguredLoggerNegativeAppender() throws IOException
{
File testLoggingDir = new File(MavenTestingUtils.getTargetTestingDir(this),"logs");
testLoggingDir.mkdirs();
System.setProperty("test.dir",testLoggingDir.getAbsolutePath());
Properties props = new Properties();
props.setProperty("root.level","DEBUG");
props.setProperty("root.appenders","console,rollLog");
props.setProperty("logger.AUDIT.level","INFO");
props.setProperty("logger.AUDIT.appenders","-rollLog,auditLog");
props.setProperty("appender.console.class",ConsoleAppender.class.getName());
props.setProperty("appender.rollLog.class",RollingFileAppender.class.getName());
props.setProperty("appender.rollLog.filename","${test.dir}/rolling.log");
props.setProperty("appender.auditLog.class",RollingFileAppender.class.getName());
props.setProperty("appender.auditLog.filename","${test.dir}/audit.log");
CentralLoggerConfig root = CentralLoggerConfig.load(props);
assertNotNull("Root Logger should not be null",root);
assertEquals("Root Logger.name",Logger.ROOT_LOGGER_NAME,root.getName());
assertSeverityLevel(root,Severity.DEBUG);
assertAppendersById(root,"console","rollLog");
CentralLoggerConfig jettyLogger = root.getConfiguredLogger("AUDIT");
assertNotNull("Jetty Logger should not be null",jettyLogger);
assertEquals("Jetty Logger.name","AUDIT",jettyLogger.getName());
assertSeverityLevel(jettyLogger,Severity.INFO);
assertAppendersById(jettyLogger,"console","auditLog");
CentralLoggerConfig implLogger = root.getConfiguredLogger("AUDIT.some.thing.else");
assertNotNull("Jetty Logging Impl Logger should not be null",implLogger);
assertEquals("Jetty Logging Impl Logger.name","AUDIT.some.thing.else",implLogger.getName());
assertSeverityLevel(implLogger,Severity.INFO);
assertAppendersById(implLogger,"console","auditLog");
}
} }

View File

@ -56,13 +56,25 @@ public class TestAppender implements Appender
} }
private List<LogEvent> events = new ArrayList<LogEvent>(); private List<LogEvent> events = new ArrayList<LogEvent>();
private String id;
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public void append(String date, int ms, Severity severity, String name, String message, Throwable t) public void append(String date, int ms, Severity severity, String name, String message, Throwable t)
{ {
if (name.equals("log")) // standard jetty logger if (name.equals("org.eclipse.jetty.util.log")) // standard jetty logger
{ {
if (t != null) if (t != null)
{ {
// Still interested in seeing throwables (HACK)
t.printStackTrace(System.err); t.printStackTrace(System.err);
} }
return; // skip storing it. return; // skip storing it.