[ 
https://issues.apache.org/jira/browse/LOG4J2-3298?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17470837#comment-17470837
 ] 

Matt Pavlovich commented on LOG4J2-3298:
----------------------------------------

The intent here is not to add a "hack", but be able to generate fully-formed 
JSON log lines for hierarchical objects passed into the logger using the 
framework as intended for auditing and diagnostics.

What is the best way to achieve that? Perhaps I am just missing a config or 
context setup.. is there a unit test or example along these lines?

My understanding is that MapMessage is a two-dimensional map, and would not be 
suitable for complex objects. Also, in my testing of output when passing in a 
MapMessage, the output generated is escaped and not well-formed JSON.

{noformat}
StringMapMessage mapMessage = new StringMapMessage()
mapMessage.put("id", Long.toValue(obj.getId()));
mapMessage.put("name", obj.getName());
logger.info(mapMessage);
{noformat}

Event Template Layout:
{noformat}
"message": {
    "$resolver": "message",
    "fallbackKey": "formattedMessage"
  },
{noformat}

or 

{noformat}
"message": {
    "$resolver": "message",
    "stringified": true
  },
{noformat}


Output:
{noformat}
{"@timestamp":"2022-01-07T19:14:01.057Z","log.level":"ERROR","message":"START 
adding 
MAPMessage","process.thread.name":"main","log.logger":"io.hyte.dev.log.ProcessService","muid":"3e5ecf","tags":["{
 \"Task\" { \"id\": \"4664\", \"orderId\": \"2221\", \"taskStatus\": \"null\", 
\"startDateTime\": \"2022-01-07T07:52:01.052884-06:00\", \"endDateTime\": 
\"2022-01-07T20:42:01.055447-06:00\"} }","{ \"Order\" { \"id\": \"3977\", 
\"customerName\": \"Customer-8625\", \"createdDate\": 
\"2022-01-07T09:51:01.056580-06:00\"} }"]}
{"@timestamp":"2022-01-07T19:14:01.058Z","log.level":"INFO","message":"{\"customerName\":\"Customer-8625\",\"id\":\"3977\"}","process.thread.name":"main","log.logger":"io.hyte.dev.log.ProcessService","muid":"3e5ecf","tags":["{
 \"Task\" { \"id\": \"4664\", \"orderId\": \"2221\", \"taskStatus\": \"null\", 
\"startDateTime\": \"2022-01-07T07:52:01.052884-06:00\", \"endDateTime\": 
\"2022-01-07T20:42:01.055447-06:00\"} }","{ \"Order\" { \"id\": \"3977\", 
\"customerName\": \"Customer-8625\", \"createdDate\": 
\"2022-01-07T09:51:01.056580-06:00\"} }"]}
{"@timestamp":"2022-01-07T19:14:01.058Z","log.level":"ERROR","message":"END 
adding 
MAPMessage","process.thread.name":"main","log.logger":"io.hyte.dev.log.ProcessService","muid":"3e5ecf","tags":["{
 \"Task\" { \"id\": \"4664\", \"orderId\": \"2221\", \"taskStatus\": \"null\", 
\"startDateTime\": \"2022-01-07T07:52:01.052884-06:00\", \"endDateTime\": 
\"2022-01-07T20:42:01.055447-06:00\"} }","{ \"Order\" { \"id\": \"3977\", 
\"customerName\": \"Customer-8625\", \"createdDate\": 
\"2022-01-07T09:51:01.056580-06:00\"} }"]}
{"@timestamp":"2022-01-07T19:14:01.059Z","log.level":"ERROR","message":"START 
adding 
ObjectMessage","process.thread.name":"main","log.logger":"io.hyte.dev.log.ProcessService","muid":"3e5ecf","tags":["{
 \"Task\" { \"id\": \"4664\", \"orderId\": \"2221\", \"taskStatus\": \"null\", 
\"startDateTime\": \"2022-01-07T07:52:01.052884-06:00\", \"endDateTime\": 
\"2022-01-07T20:42:01.055447-06:00\"} }","{ \"Order\" { \"id\": \"3977\", 
\"customerName\": \"Customer-8625\", \"createdDate\": 
\"2022-01-07T09:51:01.056580-06:00\"} }"]}
{"@timestamp":"2022-01-07T19:14:01.060Z","log.level":"INFO","message":"{ 
\"Order\" { \"id\": \"3977\", \"customerName\": \"Customer-8625\", 
\"createdDate\": \"2022-01-07T09:51:01.056580-06:00\"} 
}","process.thread.name":"main","log.logger":"io.hyte.dev.log.ProcessService","muid":"3e5ecf","tags":["{
 \"Task\" { \"id\": \"4664\", \"orderId\": \"2221\", \"taskStatus\": \"null\", 
\"startDateTime\": \"2022-01-07T07:52:01.052884-06:00\", \"endDateTime\": 
\"2022-01-07T20:42:01.055447-06:00\"} }","{ \"Order\" { \"id\": \"3977\", 
\"customerName\": \"Customer-8625\", \"createdDate\": 
\"2022-01-07T09:51:01.056580-06:00\"} }"]}
{"@timestamp":"2022-01-07T19:14:01.060Z","log.level":"ERROR","message":"END 
adding 
ObjectMessage","process.thread.name":"main","log.logger":"io.hyte.dev.log.ProcessService","muid":"3e5ecf","tags":["{
 \"Task\" { \"id\": \"4664\", \"orderId\": \"2221\", \"taskStatus\": \"null\", 
\"startDateTime\": \"2022-01-07T07:52:01.052884-06:00\", \"endDateTime\": 
\"2022-01-07T20:42:01.055447-06:00\"} }","{ \"Order\" { \"id\": \"3977\", 
\"customerName\": \"Customer-8625\", \"createdDate\": 
\"2022-01-07T09:51:01.056580-06:00\"} }"]}
{noformat}



> Update JSONTemplateFormat to support not escaping certain payloads
> ------------------------------------------------------------------
>
>                 Key: LOG4J2-3298
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-3298
>             Project: Log4j 2
>          Issue Type: Improvement
>          Components: JsonTemplateLayout
>            Reporter: Matt Pavlovich
>            Assignee: Volkan Yazici
>            Priority: Minor
>
> Currently, if a JSON string is pushed to ThreadContext, it will be escaped. 
> It would be great if there was a way to config the JsonTemplateLayout to _not 
> escape_ certain payloads. This allows the json to be fully formed and contain 
> model object data that can be parsed out later without any un-formatting. 
> Example log entry:
> {noformat}
> {
>   "instant": {
>     "epochSecond": 1640632561,
>     "nanoOfSecond": 287515000
>   },
>   "thread": "main",
>   "level": "INFO",
>   "loggerName": "io.hyte.dev.c.ServiceC",
>   "message": "Doing way other thing with order: 3235",
>   "contextStack": ["{ \"Task\" {\
>       "id\":\"3623\", \"orderId\": "1345\", \"taskStatus\":null, 
> \"startDateTime\": \"2021-12-27T06:07:01.363232-06:00\", \"endDateTime\": 
> \"2021-12-27T17:10:01.365430-06:00\"} }",
>       "{ \"Order\" { \"id\": \"3235\", \"customerName\": \"Customer-8780\", 
> \"createdDate\" :\"2021-12-27T08:55:01.366162-06:00\"} }"], 
>       
>   "endOfBatch": false, 
>   "loggerFqcn": "org.apache.logging.log4j.spi.AbstractLogger", 
>   "threadId": 1, 
>   "threadPriority": 5
> }
> {noformat}
> Desired output:
> {noformat}
> {
>   "instant": {
>     "epochSecond": 1640632561,
>     "nanoOfSecond": 287515000
>   },
>   "thread": "main",
>   "level": "INFO",
>   "loggerName": "io.hyte.dev.c.ServiceC",
>   "message": "Doing way other thing with order: 3235",
>   "contextStack": [{ "Task" { "id": "3623", "orderId": "1345", 
> "taskStatus":null, "startDateTime": "2021-12-27T06:07:01.363232-06:00", 
> "endDateTime": "2021-12-27T17:10:01.365430-06:00"} }",
>                    { "Order" { "id": "3235", "customerName": "Customer-8780", 
> "createdDate": "2021-12-27T08:55:01.366162-06:00"} }],
>   "endOfBatch": false,
>   "loggerFqcn": "org.apache.logging.log4j.spi.AbstractLogger",
>   "threadId": 1,
>   "threadPriority": 5
> }
> {noformat}
> Proposed requirements:
> 1. Users would have to pre-escape their JSON string in order to not break 
> overall log json format
> Implementation approach options:
> 1. Prefix {noformat}{noesc}{noformat} or other marker macro to instruct 
> JSONWriter skip escaping for that string
> {noformat}
> ThreadContext.push("{noesc}" + JSONString(myModelObject));
> {noformat}
> _or_
> 2. Alternatively, the JSONWriter could invoke a JSONReader on the marked 
> payload and then ensure that fields are properly escaped, but not escape the 
> whole payload. This would involve add'l cycles, but remove the pre-req and 
> potential hazard of user calling with malformed JSON
> Developer codes:
> {noformat}
> ThreadContext.push("{json}" + JSONString(myModelObject));
> ...
> JSONWriter detects prefix {json}.. then invokes JSONReader on the payload
> {noformat}



--
This message was sent by Atlassian Jira
(v8.20.1#820001)

Reply via email to