Adding support for Formatter and MDC.

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@964 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Joakim Erdfelt 2009-10-02 20:52:12 +00:00
parent c41639a848
commit 6dcadfa3ea
12 changed files with 538 additions and 60 deletions

View File

@ -16,6 +16,7 @@
package org.eclipse.jetty.logging.impl;
import java.io.IOException;
import java.util.Date;
/**
* Appender for log content.
@ -26,7 +27,7 @@ public interface Appender
String getId();
void append(String date, Severity severity, String name, String message, Throwable t) throws IOException;
void append(Date date, Severity severity, String name, String message, Throwable t) throws IOException;
void setProperty(String key, String value) throws Exception;

View File

@ -16,7 +16,6 @@
package org.eclipse.jetty.logging.impl;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.slf4j.helpers.MarkerIgnoringBase;
@ -28,7 +27,6 @@ import org.slf4j.helpers.MessageFormatter;
public class CentralLogger extends MarkerIgnoringBase
{
private static final long serialVersionUID = 385001265755850685L;
private static final String dateFormat = "yyyy-MM-dd HH:mm:ss.SSS";
private Severity level = Severity.INFO;
private String name;
private Appender appenders[];
@ -48,7 +46,7 @@ public class CentralLogger extends MarkerIgnoringBase
return;
}
String now = new SimpleDateFormat(dateFormat).format(new Date());
Date now = new Date();
for (Appender appender : appenders)
{

View File

@ -0,0 +1,201 @@
// ========================================================================
// Copyright (c) Webtide LLC
// ------------------------------------------------------------------------
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.logging.impl;
import java.util.HashMap;
import java.util.Map;
public class CentralMDC
{
private final static CentralMDC mdc = new CentralMDC();
private ThreadLocalMap local;
private CentralMDC()
{
local = new ThreadLocalMap();
}
public static void put(String key, String value)
{
if (mdc == null)
{
return;
}
mdc.internalPut(key,value);
}
private void internalPut(String key, String value)
{
if (local == null)
{
return;
}
HashMap<String, String> map = local.get();
if (map == null)
{
map = new HashMap<String, String>();
local.set(map);
}
map.put(key,value);
}
public static String get(String key)
{
if (mdc == null)
{
return null;
}
return mdc.internalGet(key);
}
private String internalGet(String key)
{
if (local == null)
{
return null;
}
if (key == null)
{
return null;
}
HashMap<String, String> map = local.get();
if (map == null)
{
return null;
}
return map.get(key);
}
public static void remove(String key)
{
if (mdc == null)
{
return;
}
mdc.internalRemove(key);
}
private void internalRemove(String key)
{
if (local == null)
{
return;
}
if (key == null)
{
return;
}
HashMap<String, String> map = local.get();
if (map == null)
{
return;
}
map.remove(key);
}
public static void clear()
{
if (mdc == null)
{
return;
}
mdc.internalClear();
}
private void internalClear()
{
if (local == null)
{
return;
}
HashMap<String, String> map = local.get();
if (map == null)
{
return;
}
map.clear();
}
public static Map<String, String> getContextMap()
{
if (mdc == null)
{
return null;
}
return mdc.internalGetContextMap();
}
private Map<String, String> internalGetContextMap()
{
if (local == null)
{
return null;
}
HashMap<String, String> map = local.get();
if (map == null)
{
return null;
}
Map<String, String> copy = new HashMap<String, String>();
copy.putAll(map);
return copy;
}
public static void setContextMap(Map<String, String> contextMap)
{
if (mdc == null)
{
return;
}
mdc.internalSetContextMap(contextMap);
}
private void internalSetContextMap(Map<String, String> contextMap)
{
if (local == null)
{
return;
}
HashMap<String, String> map = local.get();
if (map == null)
{
map = new HashMap<String, String>();
local.set(map);
}
else
{
map.clear();
}
map.putAll(contextMap);
}
}

View File

@ -0,0 +1,56 @@
// ========================================================================
// Copyright (c) Webtide LLC
// ------------------------------------------------------------------------
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.logging.impl;
import java.util.Map;
import org.slf4j.spi.MDCAdapter;
public class CentralMDCAdapter implements MDCAdapter
{
public void clear()
{
CentralMDC.clear();
}
public String get(String key)
{
return CentralMDC.get(key);
}
@SuppressWarnings("unchecked")
public Map getCopyOfContextMap()
{
return CentralMDC.getContextMap();
}
public void put(String key, String value)
{
CentralMDC.put(key,value);
}
public void remove(String key)
{
CentralMDC.remove(key);
}
@SuppressWarnings("unchecked")
public void setContextMap(Map contextMap)
{
CentralMDC.setContextMap(contextMap);
}
}

View File

@ -16,33 +16,19 @@
package org.eclipse.jetty.logging.impl;
import java.io.IOException;
import java.util.Date;
/**
* Standard Appender to the STDOUT Console
*/
public class ConsoleAppender implements Appender
{
private Formatter formatter;
private String id;
public String getId()
public void append(Date date, Severity severity, String name, String message, Throwable t)
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public void append(String date, Severity severity, String name, String message, Throwable t)
{
StringBuffer buf = new StringBuffer();
buf.append(date);
buf.append(':').append(severity.name()).append(':');
buf.append(name);
buf.append(':').append(message);
System.out.println(buf.toString());
System.out.println(getFormatter().format(date,severity,name,message));
if (t != null)
{
t.printStackTrace(System.out);
@ -50,17 +36,41 @@ public class ConsoleAppender implements Appender
System.out.flush();
}
public void setProperty(String key, String value) throws Exception
public void close() throws IOException
{
/* nothing to do here */
}
public Formatter getFormatter()
{
if (formatter == null)
{
formatter = new DefaultFormatter();
}
return formatter;
}
public String getId()
{
return id;
}
public void open() throws IOException
{
/* nothing to do here */
}
public void close() throws IOException
public void setFormatter(Formatter formatter)
{
this.formatter = formatter;
}
public void setId(String id)
{
this.id = id;
}
public void setProperty(String key, String value) throws Exception
{
/* nothing to do here */
}

View File

@ -0,0 +1,47 @@
// ========================================================================
// Copyright (c) Webtide LLC
// ------------------------------------------------------------------------
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.logging.impl;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Default log output formatter.
*/
public class DefaultFormatter implements Formatter
{
private String dateFormat = "yyyy-MM-dd HH:mm:ss.SSS";
public String format(Date date, Severity severity, String name, String message)
{
StringBuffer buf = new StringBuffer();
buf.append(new SimpleDateFormat(dateFormat).format(date));
buf.append(':').append(severity.name()).append(':');
buf.append(name);
buf.append(':').append(message);
return buf.toString();
}
public String getDateFormat()
{
return dateFormat;
}
public void setDateFormat(String dateFormat)
{
this.dateFormat = dateFormat;
}
}

View File

@ -0,0 +1,8 @@
package org.eclipse.jetty.logging.impl;
import java.util.Date;
public interface Formatter
{
String format(Date date, Severity severity, String name, String message);
}

View File

@ -19,6 +19,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Date;
import java.util.TimeZone;
import org.eclipse.jetty.logging.impl.io.RolloverFileOutputStream;
@ -28,8 +29,8 @@ import org.eclipse.jetty.logging.impl.io.RolloverFileOutputStream;
*/
public class RollingFileAppender implements Appender
{
private static final byte[] LN = System.getProperty("line.separator","\n").getBytes();
private RolloverFileOutputStream out;
private RolloverFileOutputStream fileout;
private PrintStream out;
private String filename;
private File file;
private boolean append = true;
@ -38,37 +39,21 @@ public class RollingFileAppender implements Appender
private String dateFormat = "yyyy_MM_dd";
private String backupFormat = "HHmmssSSS";
private String id;
private Formatter formatter;
public String getId()
public void append(Date date, Severity severity, String name, String message, Throwable t) throws IOException
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public void append(String date, Severity severity, String name, String message, Throwable t) throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append(date);
buf.append(':').append(severity.name()).append(':');
buf.append(name);
buf.append(':').append(message);
out.write(buf.toString().getBytes());
out.write(LN);
out.println(getFormatter().format(date,severity,name,message));
if (t != null)
{
t.printStackTrace(new PrintStream(out));
out.write(LN);
t.printStackTrace(out);
}
out.flush();
}
public void close() throws IOException
{
fileout.close();
out.close();
}
@ -82,11 +67,30 @@ public class RollingFileAppender implements Appender
return dateFormat;
}
public File getFile()
{
return file;
}
public String getFilename()
{
return filename;
}
public Formatter getFormatter()
{
if (formatter == null)
{
formatter = new DefaultFormatter();
}
return formatter;
}
public String getId()
{
return id;
}
public int getRetainDays()
{
return retainDays;
@ -102,11 +106,6 @@ public class RollingFileAppender implements Appender
return append;
}
public File getFile()
{
return file;
}
public void open() throws IOException
{
file = new File(PropertyExpansion.expand(filename));
@ -122,7 +121,8 @@ public class RollingFileAppender implements Appender
throw new FileNotFoundException("Logging path exist, but is not a directory: " + logDir);
}
out = new RolloverFileOutputStream(file.getAbsolutePath(),append,retainDays,zone,dateFormat,backupFormat);
fileout = new RolloverFileOutputStream(file.getAbsolutePath(),append,retainDays,zone,dateFormat,backupFormat);
out = new PrintStream(fileout);
}
public void setAppend(boolean append)
@ -145,6 +145,16 @@ public class RollingFileAppender implements Appender
this.filename = filename;
}
public void setFormatter(Formatter formatter)
{
this.formatter = formatter;
}
public void setId(String id)
{
this.id = id;
}
public void setProperty(String key, String value) throws Exception
{
if ("filename".equals(key))

View File

@ -0,0 +1,35 @@
// ========================================================================
// Copyright (c) Webtide LLC
// ------------------------------------------------------------------------
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.logging.impl;
import java.util.HashMap;
final public class ThreadLocalMap extends InheritableThreadLocal<HashMap<String, String>>
{
@Override
@SuppressWarnings("unchecked")
protected HashMap<String, String> childValue(HashMap<String, String> parentValue)
{
if (parentValue != null)
{
return (HashMap<String, String>)parentValue.clone();
}
else
{
return null;
}
}
}

View File

@ -15,7 +15,7 @@
// ========================================================================
package org.slf4j.impl;
import org.slf4j.helpers.NOPMakerAdapter;
import org.eclipse.jetty.logging.impl.CentralMDCAdapter;
import org.slf4j.spi.MDCAdapter;
/**
@ -32,11 +32,11 @@ public class StaticMDCBinder
public MDCAdapter getMDCA()
{
return new NOPMakerAdapter();
return new CentralMDCAdapter();
}
public String getMDCAdapterClassStr()
{
return NOPMakerAdapter.class.getName();
return CentralMDCAdapter.class.getName();
}
}

View File

@ -0,0 +1,87 @@
package org.eclipse.jetty.logging.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.log4j.MDC;
import org.eclipse.jetty.logging.impl.TestAppender.LogEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.StaticLoggerBinder;
import junit.framework.TestCase;
public class CentralMDCAdapterTest extends TestCase
{
public void testMDCInfo() throws Exception
{
// Setup Logger Config
Properties props = new Properties();
props.setProperty("root.level","DEBUG");
props.setProperty("root.appenders","test");
props.setProperty("appender.test.class",TestAppender.class.getName());
CentralLoggerConfig root = CentralLoggerConfig.load(props);
StaticLoggerBinder.getSingleton().setRoot(root);
// Generate a few logging events.
Logger logroot = LoggerFactory.getLogger("test.root");
logroot.info("The Phoenix and the Turtle");
logroot.info("Let the bird of loudest lay");
MDC.put("mood","sad");
MDC.put("animal","bird");
Logger logtree = LoggerFactory.getLogger("test.root.tree");
logtree.info("On the sole Arabian tree,");
logtree.info("Herald sad and trumpet be,");
MDC.put("mood","soaring");
Logger logwings = LoggerFactory.getLogger("test.root.wings");
logwings.info("To whose sound chaste wings obey.");
logwings.info("But thou shrieking harbinger,");
logwings.info("Foul precurrer of the fiend,");
MDC.remove("animal");
Logger logend = LoggerFactory.getLogger("test.root.end");
logend.info("Augur of the fever's end,");
MDC.clear();
logend.info("To this troop come thou not near.");
// Assert Events
TestAppender testappender = (TestAppender)root.findAppender(TestAppender.class);
List<LogEvent> captured = testappender.getEvents();
List<String> expectedMessages = new ArrayList<String>();
expectedMessages.add("The Phoenix and the Turtle");
expectedMessages.add("Let the bird of loudest lay");
expectedMessages.add("On the sole Arabian tree,");
expectedMessages.add("Herald sad and trumpet be,");
expectedMessages.add("To whose sound chaste wings obey.");
expectedMessages.add("But thou shrieking harbinger,");
expectedMessages.add("Foul precurrer of the fiend,");
expectedMessages.add("Augur of the fever's end,");
expectedMessages.add("To this troop come thou not near.");
assertEquals("Captured Messages size",expectedMessages.size(),captured.size());
List<String> expectedMdc = new ArrayList<String>();
expectedMdc.add("");
expectedMdc.add("");
expectedMdc.add("animal=bird, mood=sad");
expectedMdc.add("animal=bird, mood=sad");
expectedMdc.add("animal=bird, mood=soaring");
expectedMdc.add("animal=bird, mood=soaring");
expectedMdc.add("animal=bird, mood=soaring");
expectedMdc.add("mood=soaring");
expectedMdc.add("");
assertEquals("Captured MDC events size",expectedMdc.size(),captured.size());
for(int i=0, n=expectedMessages.size(); i<n; i++) {
assertEquals("Message[" + i + "]", expectedMessages.get(i), captured.get(i).message);
assertEquals("MDC[" + i + "]", expectedMdc.get(i), captured.get(i).mdc);
}
}
}

View File

@ -17,10 +17,15 @@ package org.eclipse.jetty.logging.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.eclipse.jetty.logging.impl.Appender;
import org.eclipse.jetty.logging.impl.Severity;
import org.slf4j.MDC;
/**
* Test Appender, records the logging events.
@ -29,13 +34,15 @@ public class TestAppender implements Appender
{
public static class LogEvent
{
String date;
Date date;
Severity severity;
String name;
String message;
Throwable t;
String mdc;
public LogEvent(String date, Severity severity, String name, String message, Throwable t)
@SuppressWarnings("unchecked")
public LogEvent(Date date, Severity severity, String name, String message, Throwable t)
{
super();
this.date = date;
@ -43,6 +50,24 @@ public class TestAppender implements Appender
this.name = name;
this.message = message;
this.t = t;
this.mdc = "";
Map<String, String> mdcMap = MDC.getCopyOfContextMap();
if (mdcMap != null)
{
Set<String> keys = new TreeSet<String>();
keys.addAll(mdcMap.keySet());
boolean delim = false;
for (String key : keys)
{
if (delim)
{
mdc += ", ";
}
mdc += key + "=" + mdcMap.get(key);
delim = true;
}
}
}
public LogEvent(Severity severity, String name, String message)
@ -74,13 +99,13 @@ public class TestAppender implements Appender
this.id = id;
}
public void append(String date, Severity severity, String name, String message, Throwable t)
public void append(Date date, Severity severity, String name, String message, Throwable t)
{
if (name.equals("org.eclipse.jetty.util.log")) // standard jetty logger
{
if (t != null)
{
// Still interested in seeing throwables (HACK)
// Still interested in seeing throwables
t.printStackTrace(System.err);
}
return; // skip storing it.