4

I'm working on a logging framework for an enterprise system and have been looking at both logback and log4j as logging backends but trying to use slf4j to keep the backend implementation out of it.

We want to log messages out in JSON format and I've found a Layout class for log4j and an Encoder for logback that does that. However, we would like to have the ability to add arbitrary key/value pairs to the JSON output.

I was hoping that the Layout/Encoder would be able to detect what type of object was being logged and in the case of a Map it would add the key/value pairs to the JSON but for anything else it would just toString() it.

This doesn't seem to be possible however since the slf4j interface seems to be restricted to logging String objects.

I've read up on Markers, MDC and NDC but none of those seem to fit my needs well enough.

To clarify, here is a code snippet that would be optimal:

Map m = new HashMap();
m.put("foo", "bar");
m.put("baz", "fluffbunny");
log.info(m);

This would output something like:

{ "timestamp": "2013-03-04T13:33:40", "foo": "bar", "baz": "fluffbunny" }

or

{ "timestamp": "2013-03-04T13:33:40", "message": { "foo": "bar", "baz": "fluffbunny" } }

There would be some workarounds such as rendering JSON strings as the message or using the MDC around the log statements (my layout/encoder classes correctly render the MDC and NDC) but this would in both cases clutter the log lines.

So my question is whether there is some convenient way to do this. Sticking to SLF4J is a definite plus but perhaps not necessary if the benefits of using a particular backend outweigh the benefits of being backend agnostic.

StFS
  • 1,639
  • 2
  • 15
  • 31

1 Answers1

4

I would just have a LoggableMap that outputs JSON as its toString, using SLF4J

Map m = new Loggable();
m.put("foo", "bar");
m.put("baz", "fluffbunny");
// Note the use of {} to log an arbitrary object rather than a String
log.info("{}", m);
artbristol
  • 32,010
  • 5
  • 70
  • 103