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
{
void setId(String id);
String getId();
void append(String date, int ms, Severity severity, String name, String message, Throwable t) throws IOException;
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.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@ -48,6 +49,8 @@ public class CentralLoggerConfig
private static void configureAppender(Properties props, String id, Appender appender)
{
appender.setId(id);
// Collect configuration fields for appender id
Pattern appenderIdRegex = Pattern.compile("^appender\\." + id + "\\.([^\\.]*)$");
Matcher match;
@ -88,7 +91,9 @@ public class CentralLoggerConfig
out.printf("%sAppenders: ",prefix);
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())
{
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);
if (value == null)
{
return null;
return ids;
}
String ids[] = value.split(",");
List<Appender> appenders = new ArrayList<Appender>();
// ensure ids exist as declared as well.
for (int i = 0, n = ids.length; i < n; i++)
String parts[] = value.split(",");
for (int i = 0, n = parts.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
{
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);
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)
root.appenders.add(new ConsoleAppender());
}
@ -265,10 +281,29 @@ public class CentralLoggerConfig
// Set loggers & levels of OTHER nodes
for (String id : ids)
{
System.out.println("Processing child id: " + id);
CentralLoggerConfig childlog = root.getConfiguredLogger(id);
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;
@ -293,7 +328,7 @@ public class CentralLoggerConfig
this.appenders.addAll(copyLogger.appenders);
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)
@ -301,14 +336,22 @@ public class CentralLoggerConfig
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)

View File

@ -22,6 +22,18 @@ import java.io.IOException;
*/
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)
{
StringBuffer buf = new StringBuffer();
@ -65,4 +77,10 @@ public class ConsoleAppender implements Appender
{
/* 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
{
private static final byte[] LN = System.getProperty("line.separator","\n").getBytes();
private RolloverFileOutputStream out;
private String filename;
private File file;
@ -37,6 +38,17 @@ public class RollingFileAppender implements Appender
private TimeZone zone = TimeZone.getDefault();
private String dateFormat = "yyyy_MM_dd";
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
{
@ -60,9 +72,11 @@ public class RollingFileAppender implements Appender
buf.append(':').append(message);
out.write(buf.toString().getBytes());
out.write(LN);
if (t != null)
{
t.printStackTrace(new PrintStream(out));
out.write(LN);
}
out.flush();
}
@ -195,4 +209,10 @@ public class RollingFileAppender implements Appender
{
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
{
private static final String LOGGING_SERVLET_ID = "org.eclipse.jetty.tests.webapp.LoggingServlet";
private XmlConfiguredJetty jetty;
private void assertContainsLogEvents(TestAppender capturedEvents, LogEvent[] expectedLogs)
@ -74,14 +75,14 @@ public class CentralizedLoggingTest extends TestCase
SimpleRequest.get(jetty,"/dummy-webapp-logging-java/logging");
TestAppender.LogEvent expectedLogs[] =
{ new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(log4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(log4j) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(slf4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(slf4j) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(commons-logging) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(commons-logging) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(java) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(java) GET requested",null) };
{ new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(log4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(log4j) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(slf4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(slf4j) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(commons-logging) initialized",null),
new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(commons-logging) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(java) initialized",null),
new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(java) GET requested",null) };
assertContainsLogEvents(testAppender,expectedLogs);
}

View File

@ -38,6 +38,7 @@ import org.eclipse.jetty.webapp.WebAppContext;
*/
public class EmbeddedCentralizedLoggingTest extends TestCase
{
private static final String LOGGING_SERVLET_ID = "org.eclipse.jetty.tests.webapp.LoggingServlet";
private TestAppender testAppender;
private void assertContainsLogEvents(TestAppender capturedEvents, LogEvent[] expectedLogs)
@ -146,14 +147,14 @@ public class EmbeddedCentralizedLoggingTest extends TestCase
server.stop();
TestAppender.LogEvent expectedLogs[] =
{ new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(log4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(log4j) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(slf4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(slf4j) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(commons-logging) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(commons-logging) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(java) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(java) GET requested",null) };
{ new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(log4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(log4j) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(slf4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(slf4j) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(commons-logging) initialized",null),
new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(commons-logging) GET requested",null),
new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(java) initialized",null),
new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(java) GET requested",null) };
assertContainsLogEvents(testAppender,expectedLogs);
}
@ -169,8 +170,8 @@ public class EmbeddedCentralizedLoggingTest extends TestCase
server.stop();
TestAppender.LogEvent expectedLogs[] =
{ new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(commons-logging) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(commons-logging) GET requested",null) };
{ new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(commons-logging) initialized",null),
new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(commons-logging) GET requested",null) };
assertContainsLogEvents(testAppender,expectedLogs);
}
@ -186,8 +187,8 @@ public class EmbeddedCentralizedLoggingTest extends TestCase
server.stop();
TestAppender.LogEvent expectedLogs[] =
{ new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(java) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(java) GET requested",null) };
{ new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(java) initialized",null),
new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(java) GET requested",null) };
assertContainsLogEvents(testAppender,expectedLogs);
}
@ -203,8 +204,8 @@ public class EmbeddedCentralizedLoggingTest extends TestCase
server.stop();
TestAppender.LogEvent expectedLogs[] =
{ new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(log4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(log4j) GET requested",null) };
{ new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(log4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(log4j) GET requested",null) };
assertContainsLogEvents(testAppender,expectedLogs);
}
@ -220,8 +221,8 @@ public class EmbeddedCentralizedLoggingTest extends TestCase
server.stop();
TestAppender.LogEvent expectedLogs[] =
{ new LogEvent(null,-1,Severity.DEBUG,"LoggingServlet","LoggingServlet(slf4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,"LoggingServlet","LoggingServlet(slf4j) GET requested",null) };
{ new LogEvent(null,-1,Severity.DEBUG,LOGGING_SERVLET_ID,"LoggingServlet(slf4j) initialized",null),
new LogEvent(null,-1,Severity.INFO,LOGGING_SERVLET_ID,"LoggingServlet(slf4j) GET requested",null) };
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)
{
assertEquals("Severity",severity,logger.getLevel());
@ -184,4 +241,42 @@ public class ConfiguredLoggerTest extends TestCase
assertSeverityLevel(implLogger,Severity.WARN);
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 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)
{
if (name.equals("log")) // standard jetty logger
if (name.equals("org.eclipse.jetty.util.log")) // standard jetty logger
{
if (t != null)
{
// Still interested in seeing throwables (HACK)
t.printStackTrace(System.err);
}
return; // skip storing it.