The message attribute in the JSON log has backslash, new line and special charecters
See original GitHub issueHi Team,
I have applied the logstash-logback-encoder and the logs generate in JSON format but some portion of the logs as below for message attritbute still has backslash, new line and special charecters in it.
{"@timestamp":"2018-01-31T19:21:27.624+04:00","@version":1,"message":"{\"type\":\"API_REQUEST\",\"uid\":\"35f53fe5-7c63-4936-a617-14601073a5f7\",\"sessionId\":\"9E998B68C5A6D66C30D215DE0B4B5EF3\",\"remoteAddress\":\"0:0:0:0:0:0:0:1\",\"methodType\":\"POST\",\"headers\":\"{content-length=76, accept-language=en-US,en;q=0.9, cookie=JSESSIONID=50D17B32E96A6A8850F2A5FD52A4C07D, postman-token=a5be9806-a0a6-3905-e45d-2bea9036f3ed, origin=chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop, accept=*/*, host=localhost:3080, connection=keep-alive, content-type=application/json, cache-control=no-cache, accept-encoding=gzip, deflate, br, user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36}\",\"uri\":\"/user/login\",\"query\":null,\"contentType\":\"application/json\",\"requestTime\":\"2018-01-31 19:21:26.024\",\"responseTime\":\"2018-01-31 19:21:27.604\",\"executionTimeMillisecond\":1580,\"requestPayload\":\"{\\n \\\"\\": \\\"+971\\\",\\n \\\"phone\\\": \\\"545901009\\\",\\n \\\"employeeType\\\": \\\"PHONE\\\"\\n }\",\"responsePayload\":\"{\\\"status\\\":\\\"FAIL\\\",\\\"statusCode\\\":1000,\\\"message\\\":\\\"Internal Server Error\\\",\\\"desc\\\":\\\"FAIL\\\",\\\"debug\\\":\\\"org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalArgumentException: non null key required\\\\n\\\\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)\\\\n\\\\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)\\\\n\\\\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:648)\\\\n\\\\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)\\\\n\\\\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:729)\\\\n\\\\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)\\\\n\\\\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)\\\\n\\\\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)\\\\n\\\\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)\\\\n\\\\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)\\\\n\\\\tat
Issue Analytics
- State:
- Created 6 years ago
- Comments:34
Top GitHub Comments
You are encountering the main problem with trying to serialize every argument as JSON. Jackson is not able to serialize every object due to things like infinite recursion in object graphs, like you are encountering.
My recommendation is to not try to serialize every argument as JSON. Again, because there is no guarantee that jackson will be able to serialize every type of object passed as an argument as JSON. You are extremely likely to encounter objects that are not JSON serializable by jackson, unless custom class-specific hints (such as JsonSerializers or mixin) are registered for the class.
Instead, I would recommend utilizing StructuredArguments. When StructuredArguments are used, it forces the developer to follow the contract of a StructuredArgument… in that the argument must be JSON serializable. This forces developers to select which arguments it makes sense to try to JSON-serialize, and ensure those classes JSON-serializable.
However, if you would like to continue trying to serialize every argument, then you are going to have to come up with your own strategy. Most likely that strategy is not going to be able to magically make every object JSON-serializable. Therefore, you’re going to have to make compromises.
For example, a simple strategy might be to whitelist classes that are known to be serializable, and not attempt to serialize classes that are not in the whitelist in your
JsonProvider
.For classes that jackson cannot serialize by default, you can register mixins and custom serializers in a
JsonFactoryDecorator
. After including the appropriate mixin or custom serializer, you can add them to your whitelist.You could also take the opposite approach, by having a blacklist… i.e. classes that are known to NOT be serializable. And only serialize classes that are not in that list. This would be more error prone than a whitelist approach, since new classes (that might not be serializable) are invented every day.
Another strategy would be to catch the exceptions from jackson in your
JsonProvider
, and dynamically add the classes that cannot be serialized by jackson to a list of blacklisted classes at runtime. (Therefore preventing them from being attempted to be serialized again).There are probably other strategies that you can think of that will work for you.
The choice is yours to make. You will need to pick a compromise with which you are willing to live.
The logstash-logback-encoder library gives you the tools needed to implement your strategy. You can configure the
JsonFactory
,ObjectMapper
, andJsonGenerator
exactly how you want it with decorators. And you can create your ownJsonProvider
with full control over what to write to theJsonGenerator
. You can experiment with Jackson, and find what options work best for you.LoggingEventCompositeJsonEncoder
encodes LoggingEvents as JSON by using JsonProviders. By default,LoggingEventCompositeJsonEncoder
has no providers. It’s up to you to add the providers that you want to get the output you want.Each provider contributes something to the JSON output by the encoder. For example, the
timestamp
provider will add the LoggingEvent’s timestamp to the JSON output. logstash-logback-encoder comes with many providers, but you can also add your own if those provided by logstash-logback-encoder do not handle your use case.LogstashEncoder
is a subclass ofLoggingEventCompositeJsonEncoder
with a set of providers pre-configured as sensible defaults.Both
LogstashEncoder
andLoggingEventCompositeJsonEncoder
use providers to contribute to the output. It’s just thatLogstashEncoder
starts with a set of default providers to handle common use cases, andLoggingEventCompositeJsonEncoder
starts with no providers.For simple use cases, users can just use
LogstashEncoder
.For complex use cases, it might be easier to start with
LoggingEventCompositeJsonEncoder
, and add the exact providers what you want, rather than starting withLogstashEncoder
, and trying to remove/add/override functionality. For example, if you want to customize the ordering of fields in the JSON output, you can configureLoggingEventCompositeJsonEncoder
with providers in the order you want. Or if you want to override some of the providers used byLogstashEncoder
(like your desire to not output the formatted message field), it might be easier to useLoggingEventCompositeJsonEncoder
In summary, for your use case, I would recommend
LoggingEventCompositeJsonEncoder
, but you could probably still useLogstashEncoder
if you wanted.Here’s what your configuration could potentially look like using the
LoggingEventCompositeJsonEncoder
. You can also add any other provider you want, depending on what you want included in the JSON output.(Notice that the
rawMessage
provider is used here. This can be used instead of yourUnformattedMessageJsonProvider
. I didn’t realize that logstash-logback-encoder already had a provider that outputs the unformatted message.)Regarding the clubbed messages, there is probably an exception occurring while generating the JSON output. I would recommend registering a logback status listener so you can see error messages and exceptions from logback. You can use
<configuration debug="true">
or<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />