logstash/logstash-logback-encoder — pull request #39 by philsttr (2014-07-10 06:11:06+00:00)
Title: Use Jackson Streaming API, and add an extensible way to add event-specific fields to json output

Oh boy, I had some fun!

First, to improve performance, I switched the formatters to use the Jackson Streaming api (instead of building up JsonNodes, and then writing them out). The measurements that I've done indicate a 10-15% speed increase when logging events. Woo hoo!

Next, I saw that 1) adding custom json fields using `enableContextMap=true` and adding a Map as the last argument to the log line AND 2) adding json using the `JSON` marker causing a `json_message` field to be added left much to be desired. Both of these approaches felt very "hacky" to me. (Hopefully I won't offend the original implementors.)

I implemented a much cleaner and flexible solution using custom Markers. Take a look at the new README.md file for all the details. But just to hit the highlights:
* Both of the previous use cases are easily handled with the new implementation in a similar fashion
* I have deprecated the previous use cases (in code, and in the README.md)
** Perhaps these can be removed for 3.0
* Custom Markers now can be used to add fields into the logstash json event
* The markers are instantiated in a fluent/method-chaining way using the `Markers` class
* No more "magic" parameters when calling the logger (e.g. the last argument being a map, even if it's not used in the log message).
* The intent is very clear when reading code that calls the loggers

Here are some examples (copied from README.md):

```java
import static net.logstash.logback.marker.Markers.*

/*
* Add "name":"value" to the json event.
*/
logger.info(append("name", "value"), "log message");

/*
* Add "name1":"value1","name2":"value2" to the json event by using multiple markers.
*/
logger.info(append("name1", "value1").with(append("name2", "value2")), "log message");

/*
* Add "name1":"value1","name2":"value2" to the json event by using a map.
*
* Note the values can be any object that can be serialized by Jackson's ObjectMapper
* (e.g. other Maps, JsonNodes, numbers, arrays, etc)
*/
Map myMap = new HashMap();
myMap.put("name1", "value1");
myMap.put("name2", "value2");
logger.info(embed(myMap), "log message");

/*
* Add "array":[1,2,3] to the json event
*/
logger.info(appendArray("array", 1, 2, 3), "log message");

/*
* Add "array":[1,2,3] to the json event by using raw json.
* This allows you to use your own json seralization routine to construct the json output
*/
logger.info(appendRaw("array", "[1,2,3]"), "log message");

/*
* Add any object that can be serialized by Jackson's ObjectMapper
* (e.g. Maps, JsonNodes, numbers, arrays, etc)
*/
logger.info(append("object", myobject), "log message");

```

Finally, I updated the README.md file to
* document all of the fields that can appear in the event
* document all the new awesomeness of the custom matchers
* deprecate the old "json_message" and enableContextMap things

Let me know what you think. I really like the way this turned out. It makes the encoder very powerful.