Yes, logback does this well in fact.
I can show you and example of a logback encoder that encodes to a JSON
format. You can extend the concept to encode XML just the same. Possibly
you could use very similar code to mine and abstract your message
formatting into a builder pattern.
For my money though, I'd stick with JSON. I'd also steer you toward
Logstash and Kibana as a killer combo for dealing with logs--both of these
tools are free and open source.
I attached some (incomplete WRT to dependencies) code that should get the
main point across.
Good Luck.
Troy
/* Copyright (C) 2013 Partnet, Inc. Confidential and Proprietary. */
package com.foo;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
/**
* @author thart
*
*/
public class GsonLoggingEventBuilder
{
@SerializedName("message")
private String message;
@SerializedName("source_host")
private String sourceHost;
@SerializedName("fields")
private Map<String, Object> fields = new HashMap<String, Object>();
public void setMessage(String message)
{
this.message = message;
}
public void setSourceHost(String sourceHost)
{
this.sourceHost = sourceHost;
}
/**
* @param fieldName
* @param fieldValue
*/
public void addField(String fieldName, Object fieldValue)
{
if (fieldName == null) {
throw new IllegalArgumentException("fieldName is null");
}
fields.put(fieldName, fieldValue);
}
public String toJson()
{
return new Gson().toJson(this);
//return new GsonBuilder().setPrettyPrinting().create().toJson(this);
}
}
package com.foo;
// just showing logback imports for brevity
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.ThrowableProxyUtil;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.encoder.EncoderBase;\
public class JsonEncoder
extends EncoderBase<ILoggingEvent>
{
/**
* The charset to use when converting a String into bytes.
* <p/>
* By default this property has the value
* <code>null</null> which corresponds to
* the system's default charset.
*/
private Charset charset;
private boolean immediateFlush = true;
/**
* <p>Sets the immediateFlush option. The default value for immediateFlush is
* 'true'. If set to true, the doEncode() method will immediately flush the
* underlying OutputStream. Although immediate flushing is safer, it also
* significantly degrades logging throughput.</p>
*/
public void setImmediateFlush(boolean immediateFlush)
{
this.immediateFlush = immediateFlush;
}
public boolean isImmediateFlush()
{
return immediateFlush;
}
public Charset getCharset()
{
return charset;
}
/**
* <p>Set the charset to use when converting the string returned by the layout
* into bytes.</p>
*
* <p>By default this property has the value <code>null</null> which
* corresponds to the system's default charset.</p>
*
* @param charset
*/
public void setCharset(Charset charset)
{
this.charset = charset;
}
@Override
public void close()
throws IOException
{
outputStream.write(convertToBytes(CoreConstants.LINE_SEPARATOR, getCharset()));
}
@Override
public void doEncode(ILoggingEvent event)
throws IOException
{
GsonLoggingEventBuilder builder = new GsonLoggingEventBuilder();
builder.setMessage(event.getFormattedMessage());
builder.addField("level", event.getLevel().toString());
builder.addField("logger", event.getLoggerName());
builder.addField("thread", event.getThreadName());
builder.addField("context.name", event.getLoggerContextVO().getName());
addTimestamp(builder, event);
addMDC(builder, event);
addContext(builder, event);
addThrowableInformation(builder, event);
Charset charset = getCharset();
outputStream.write(convertToBytes(builder.toJson(), charset));
outputStream.write(convertToBytes(CoreConstants.LINE_SEPARATOR, charset));
if (immediateFlush) {
outputStream.flush();
}
}
private void addTimestamp(JsonLoggingEventBuilder builder, ILoggingEvent event)
{
builder.addField("timestamp", formatTimestamp(event));
}
private void addThrowableInformation(JsonLoggingEventBuilder builder, ILoggingEvent event)
{
final IThrowableProxy tp = event.getThrowableProxy();
if (tp != null) {
builder.addField("stacktrace", ThrowableProxyUtil.asString(tp));
//...what else should be included?
}
}
private void addMDC(JsonLoggingEventBuilder builder, ILoggingEvent event)
{
Map<String, String> mdc = event.getMDCPropertyMap();
if (!mdc.isEmpty()) {
builder.addField("mdc", mdc);
}
}
private void addContext(JsonLoggingEventBuilder builder, ILoggingEvent event)
{
Context ctx = getContext();
if (ctx != null) {
builder.addField("context", ctx.getCopyOfPropertyMap());
}
}
}
_______________________________________________
Logback-user mailing list
[email protected]
http://mailman.qos.ch/mailman/listinfo/logback-user