title: Java: How to log raw JSON as JSON and avoid escaping during logging with logback / slf4j
body: <p>I'm using SLF4J with Logback in a JAX-RS application... I want to log to JSON in such a way that my message is not encoded again but printed raw into the logfile: </p>
  
  <p>At the moment it looks like this:</p>
  
  <pre><code>{"@timestamp":1363834123012,"@message":"{\"text\":\"From MLK to Barack 
  Ob...\n\"}"
  </code></pre>
  
  <p>But I want to have this:  </p>
  
  <pre><code>  {"@timestamp":1363834123012,"@message": { "text ": "From MLK to Barack 
  Ob...\n\}
  </code></pre>
  
  <p>The reason is I want to parse the JSON again and want to avoid the unescaping of the data. </p>
  
  <p>I've written a custom logback encoder but I found no way to avoid the escaping. Can I pass a object to logback and change the settings based on the type of the object? </p>
  
  <p>Edit: I've found a way - not exactly elegant - as requested a SSCE: </p>
  
  <p>In my Application</p>
  
  <pre><code>// SLF4J Logger
  private static Logger logger = LoggerFactory.getLogger(MyClass.class);
  // A logback? Marker
  private Marker foo = MarkerFactory.getMarker("foo");
  // Jackson ObjectMapper()
  ObjectMapper mapper = new ObjectMapper();
  
  // Log something... 
  logger.info(foo, mapper.writeValueAsString(json));
  </code></pre>
  
  <p>I've used a variation of the Logstash-Encoder found here: <a href="https://github.com/logstash/logstash-logback-encoder">https://github.com/logstash/logstash-logback-encoder</a></p>
  
  <pre><code>package my.package;
  
  import static org.apache.commons.io.IOUtils.*;
  
  import java.io.IOException;
  import java.util.Map;
  import java.util.Map.Entry;
  
  import org.codehaus.jackson.JsonGenerator.Feature;
  import org.codehaus.jackson.JsonNode;
  import org.codehaus.jackson.map.ObjectMapper;
  import org.codehaus.jackson.node.ObjectNode;
  import org.slf4j.Marker;
  
  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.CoreConstants;
  import ch.qos.logback.core.encoder.EncoderBase;
  
  public class JsonEncoder extends EncoderBase&lt;ILoggingEvent&gt; {
  
      private static final ObjectMapper MAPPER = new ObjectMapper().configure(
          Feature.ESCAPE_NON_ASCII, true);
      private static Marker M;
  
      private boolean immediateFlush = true;
  
  @Override
  public void doEncode(ILoggingEvent event) throws IOException {
  
      M = event.getMarker();
  
      ObjectNode eventNode = MAPPER.createObjectNode();
  
      eventNode.put("@timestamp", event.getTimeStamp());
      //
      if (M != null) {
          if (M.getName().equals("foo")) {
              JsonNode j = MAPPER.readTree(event.getFormattedMessage());
              eventNode.put("@foo", j);
          }
      } else {
          eventNode.put("@message", event.getFormattedMessage());
      }
      eventNode.put("@fields", createFields(event));
  
      write(MAPPER.writeValueAsBytes(eventNode), outputStream);
      write(CoreConstants.LINE_SEPARATOR, outputStream);
  
      if (immediateFlush) {
          outputStream.flush();
      }
  
  }
  
  private ObjectNode createFields(ILoggingEvent event) {
           // not important here
      return fieldsNode;
  
  }
  
  @Override
  public void close() throws IOException {
      write(LINE_SEPARATOR, outputStream);
  }
  
  public boolean isImmediateFlush() {
      return immediateFlush;
  }
  
  public void setImmediateFlush(boolean immediateFlush) {
      this.immediateFlush = immediateFlush;
  }
  }
  </code></pre>
  
  <p>It's works now! Yeah! But I guess it's not the best way to do it (serialize, deserialize the JSON...) </p>