使用 JSON 格式的 log4j 记录 json 字符串消息,而不用引号破坏格式

Posted

技术标签:

【中文标题】使用 JSON 格式的 log4j 记录 json 字符串消息,而不用引号破坏格式【英文标题】:log json string message using log4j in JSON format without breaking the format with quotes 【发布时间】:2022-01-24 04:40:18 【问题描述】:

我正在尝试以 json 格式格式化日志并使用模式布局来执行此操作。但是生成的输出不是正确的 json 格式,因为 msg 中的额外引号正在被记录。

下面是 log4j.properties 文件 =======================log4j.properties==================

appender.file.layout.pattern="level":"%p","time":"%dISO8601","thread":"%t","file":"%F", "line":"%L","message":"%m"%n
loggers=file
logger.file.name=com.ibm
logger.file.level = error
logger.file.level = debug
logger.file.appenderRefs = file
logger.file.appenderRef.file.ref = LOGFILE
rootLogger.level = error
rootLogger.level = debug
rootLogger.appenderRefs = stdout
rootLogger.appenderRef.stdout.ref = STDOUT

下面是编码格式

String msg = "!@#$%^&*()_+=~[]|<>?;'Text with special character /\"\'\b\f\t\r\n";
// to escape especial character, serializing msg with jackson library method
Serialize serializeMsg = objectMapper.writeValueAsString(msg);
String jsonString = "" + serializeMsg + "\", \"crn\":\"" + crn + "\", \"otherProperty\":\"" + crn + "\"";
log.debug(serializeMsg );

Json 日志生成

"level":"DEBUG","time":"2021-12-20T20:05:14,465","thread":"main","file":"App.java", "line":"81","message":""!@#$%^&*()_+=~[]|<>?;'Text with special character /\"'\b\f\t\r\n"", "crn":"5741af48-808a-4e55-8f37-681f025b1ce3", "otherProperty":"5741af48-808a-4e55-8f37-681f025b1ce3""

如何从邮件中删除多余的引号?谢谢!!

【问题讨论】:

【参考方案1】:

直接回答你的问题:objectMapper.writeValueAsString(msg) 输出一个有效的 JSON,因此它是一个用双引号括起来的字符串。您在代码中构造的消息是:

"!@#$%^&*()_+=~[]|<>?;'Text with special character /\"'\b\f\t\r\n"", "crn":"5741af48-808a-4e55-8f37-681f025b1ce3", "otherProperty":"5741af48-808a-4e55-8f37-681f025b1ce3"

您的PatternLayout 将其括在另一对双引号中("%m")。您可以轻松地从代码中删除一些双引号,使其成为有效的 JSON 消息。

但是,您为解决主要问题(将日志消息格式化为 JSON)而采取的整个方法是不稳定的(这是一个大问题):您需要应用程序中的所有日志消息都具有类似于 JSON 的格式。如果您忘记正确格式化消息会发生什么?那些肯定不符合您的格式的图书馆消息怎么办?如果您的应用程序的用户想要更改日志记录布局会发生什么?如果您不小心记录的内容,您的方法也可能容易受到log injection attacks 的攻击。

一种标准方法是让 Log4j 将您的消息格式化为 JSON。有一个JSON Template Layout。你只需要:

    log4j-layout-template-json 添加到您的依赖项中,

    在您的应用程序类路径中创建一个模板(我们称之为logTemplate.json):

    
        "level": 
            "$resolver": "level",
            "field": "name"
        ,
        "time": 
            "$resolver": "timestamp"
        ,
        "thread": 
            "$resolver": "thread",
            "field": "name"
        ,
        "file": 
            "$resolver": "source",
            "field": "fileName"
        ,
        "line": 
            "$resolver": "source",
            "field": "lineNumber"
        ,
        "message": 
            "$resolver": "message",
            "stringified": true
        
    
    

    更新您的 log4j2.properties 文件以使用 JSON 模板布局:

    appender.file.layout.type=JsonTemplateLayout
    appender.file.layout.eventTemplateUri=classpath:logTemplate.json
    appender.file.layout.locationInfoEnabled=true
    

    只需调用即可记录消息:

    log.debug("!@#$%^&*()_+=~[]|<>?;'Text with special character /\"\'\b\f\t\r\n");
    

【讨论】:

感谢您回答问题并提出解决问题的更好方法。实际上,客户端现在可能不允许我们添加任何进一步的依赖项,所以不幸的是,我可能不得不采用从代码本身中删除引号的解决方案,现在我得到了有效 json 格式的输出。再次感谢您的建议。 由于您之前描述的所有安全问题,肯定会更新为 json 模板布局。接受您的评论作为答案。

以上是关于使用 JSON 格式的 log4j 记录 json 字符串消息,而不用引号破坏格式的主要内容,如果未能解决你的问题,请参考以下文章

使用cookie记录点击/浏览历史并以json格式存入

log4j

如何使用 Serilog 以有效的 json 格式记录复杂对象?

如何在 Jackson 中记录 JSON 反序列化

请使用 JSON 格式记录日志,好吗?

Django 以 JSON 格式返回单个记录