我试图了解是否有任何最佳实践/实用程序/开箱即用的功能来记录很长的消息(通常是json文件响应/ xmls / CSV等)。
在作为我的应用程序的一部分进行日志记录时,我会执行类似
的操作log.info("Incompatible order found {}", order.asJson())
问题是asJson()表示可能很长。在日志文件中,实际的json仅与1%的时间相关。因此,重要的是保留但足够大,以便在我浏览日志时让我失去焦点。
无论如何,我可以做一些像
这样的事情log.info("Incompatible order found, file dumped at {}", SomeUtility.dumpString(order.asJson()));
实用程序将文件转储到与其他日志文件一致的位置,然后在我的日志文件中,我可以看到以下内容
Incompatible order found, file dumped at /abc/your/log/location/tmpfiles/xy23nmg
需要注意的关键事项
答案 0 :(得分:1)
(建议是基于logback而不是log4j2。但我相信log4j2中存在类似的设施)
在Logback中,有一个名为SiftingAppender的工具,它允许根据某些鉴别器(例如在MDC中)创建单独的appender(例如文件追加器)。
因此,通过配置一个appender(例如orderDetailAppender),它根据一个鉴别器分离文件(例如通过在MDC中放置订单ID),并利用一个单独的记录器连接到appender,这应该给你结果你想:
伪代码:
logback config:
<appender name="ORDER_DETAIL_APPENDER" class="ch.qos.logback.classic.sift.SiftingAppender">
<!-- use MDC disciminator by default, you may choose/develop other appropriate discrimator -->
<sift>
<appender name="ORDER-DETAIL-${ORDER_ID}" class="ch.qos.logback.core.FileAppender">
....
</appender>
</sift>
</appender>
<logger name="ORDER_DETAIL_LOGGER">
<appender-ref name="ORDER_DETAIL_APPENDER"/>
</logger>
您的代码如下:
Logger logger = LoggerFactory.getLogger(YourClass.class); // logger you use normally
Logger orderDetailLogger = LoggerFactory.getLogger("ORDER_DETAIL_LOGGER");
.....
MDC.put("ORDER_ID", order.getId());
logger.warn("something wrong in order {}. Find the file in separate file", order.getId());
orderDetailLogger.warn("Order detail:\n{}", order.getJson());
// consider making order.getJson() an lambda, or wrap the line with logger
// level checking, to avoid json construction even not required to log
MDC.remove("ORDER_ID");
答案 1 :(得分:0)
最简单的方法是为JSON转储使用单独的记录器,并配置该记录器将其输出放在不同的文件中。
举个例子:
private static final Logger log = LogManager.getLogger();
private static final Logger jsonLog = LogManager.getLogger("jsondump");
...
log.info("Incompatible order found, id = {}", order.getId());
jsonLog.info("Incompatible order found, id = {}, JSON = {}",
order.getId(), order.asJson());
然后,将名为jsondump
的记录器配置为单独的文件,可能还有单独的轮换计划。确保将additivity
设置为false
以获取JSON记录器,以便发送到该记录器的消息也不会被发送到根记录器。见Additivity
在Log4J文档中了解详细信息。
示例(XML配置,Log4J 2):
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<!-- By setting only filePattern, not fileName, all log files
will use the pattern for naming. Files will be rotated once
an hour, since that's the most specific unit in the
pattern. -->
<RollingFile name="LogFile" filePattern="app-%d{yyyy-MM-dd HH}00.log">
<PatternLayout pattern="%d %p %c [%t] %m %ex%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
<!-- See comment for appender named "LogFile" above. -->
<RollingFile name="JsonFile" filePattern="json-%d{yyyy-MM-dd HH}00.log">
<!-- Omitting logger name for this appender, as it's only used by
one logger. -->
<PatternLayout pattern="%d %p [%t] %m %ex%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<!-- Note that additivity="false" to prevent JSON dumps from being
sent to the root logger as well. -->
<Logger name="jsondump" level="debug" additivity="false">
<appender-ref ref="JsonFile"/>
</Logger>
<Root level="debug">
<appender-ref ref="LogFile"/>
</Root>
</Loggers>
</Configuration>