参考这篇文章 log4j2 的 JsonLayout 测试
我们已经知道 Log4j2 能够输出 json 格式的日志,但还是没有很好的支持 ELK 的需求,打印出来的每一条日志是多行显示的,那么该如何配置具体的格式呢?请往下看。
参照 Log4j 官网的说明:
https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/layout/JsonLayout.html
@Deprecated
public static JsonLayout createLayout(Configuration config,
boolean locationInfo,
boolean properties,
boolean propertiesAsList,
boolean complete,
boolean compact,
boolean eventEol,
String headerPattern,
String footerPattern,
Charset charset,
boolean includeStacktrace)
Deprecated. Use newBuilder() instead
Creates a JSON Layout.
Parameters:
config - The plugin configuration.
locationInfo - If “true”, includes the location information in the generated JSON.
properties - If “true”, includes the thread context map in the generated JSON.
propertiesAsList - If true, the thread context map is included as a list of map entry objects, where each entry has a “key” attribute (whose value is the key) and a “value” attribute (whose value is the value). Defaults to false, in which case the thread context map is included as a simple map of key-value pairs.
complete - If “true”, includes the JSON header and footer, and comma between records.
compact - If “true”, does not use end-of-lines and indentation, defaults to “false”.
eventEol - If “true”, forces an EOL after each log event (even if compact is “true”), defaults to “false”. This allows one even per line, even in compact mode.
headerPattern - The header pattern, defaults to “[” if null.
footerPattern - The header pattern, defaults to “]” if null.
charset - The character set to use, if null, uses “UTF-8”.
includeStacktrace - If “true”, includes the stacktrace of any Throwable in the generated JSON, defaults to “true”.
Returns:
A JSON Layout.
参数说明部分翻译过来是:
config - 插件配置。
locationInfo - 如果为“true”,则在生成的 JSON 中包含位置信息。
properties - 如果为“true”,则在生成的 JSON 中包含线程上下文映射。
propertiesAsList - 如果为 true,则将线程上下文映射包括为映射条目对象的列表,其中每个条目具有“key”属性(其值为键)和“value”属性(其值为值)。默认为 false,在这种情况下,线程上下文映射包含为键值对的简单映射。
complete - 如果为“true”,则包括 JSON 页眉和页脚,以及记录之间的逗号。
compact - 如果为“true”,则不使用行尾和缩进,默认为“false”。
eventEol - 如果为“true”,则在每个日志事件后强制执行 EOL(即使compact为“true”),默认为“false”。即使在紧凑模式下,这也允许一行甚至每一行。
headerPattern- 标题模式,默认为"[“如果是 null。
footerPattern- 标题模式,默认为”]"如果是 null。
charset- 要使用的字符集if null,使用“UTF-8”。
includeStacktrace - 如果为“true”,则包括生成的 JSON 中任何Throwable的堆栈跟踪,默认为“true”。
好了,可以知道,满足每条日志输出为一行 json 的需求我们该这样设置:
<JsonLayout compact="true" locationInfo="true" complete="false" eventEol="true"/>
完整的 log4j2.xml 配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<!-- 日志文件目录和压缩文件目录配置 -->
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout
pattern="%highlight{%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %M() @%L - %msg%n}{FATAL=Bright Red, ERROR=Bright Magenta, WARN=Bright Yellow, INFO=Bright Green, DEBUG=Bright Cyan, TRACE=Bright White}"/>
</Console>
<!--这个会打印出所有的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingInfoFile" fileName="log/app.log"
filePattern="logs/info/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<JsonLayout compact="true" locationInfo="true" complete="false" eventEol="true" />
<SizeBasedTriggeringPolicy size="20MB"/>
</RollingFile>
<!-- error 日志 -->
<RollingFile name="RollingErrorFile" fileName="log/error.log"
filePattern="logs/error/$${date:yyyy-MM}/error-%d{MM-dd-yyyy}-%i.log.gz">
<JsonLayout compact="true" locationInfo="true" complete="false" eventEol="true"/>
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<SizeBasedTriggeringPolicy size="20MB"/>
</RollingFile>
</Appenders>
<!-- 全局配置,默认所有的Logger都继承此配置 -->
<Loggers>
<Root level="INFO">
<AppenderRef ref="RollingInfoFile"/>
<AppenderRef ref="RollingErrorFile"/>
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
输出的日志内容为:
{"thread":"main","level":"INFO","loggerName":"com.hoperun.bigdata.es.api.BigdataEsApiApplication","message":"Starting BigdataEsApiApplication on DESKTOP-1HMKQ6H with PID 12316 (started by HopeRunner in E:\\SVN\\Hoperun_BigData\\实验\\bigdata-es-api)","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.LogAdapter$Log4jLog","instant":{"epochSecond":1555386053,"nanoOfSecond":854000000},"threadId":1,"threadPriority":5,"source":{"class":"org.springframework.boot.StartupInfoLogger","method":"logStarting","file":"StartupInfoLogger.java","line":50}}
{"thread":"main","level":"INFO","loggerName":"com.hoperun.bigdata.es.api.BigdataEsApiApplication","message":"No active profile set, falling back to default profiles: default","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.LogAdapter$Log4jLog","instant":{"epochSecond":1555386053,"nanoOfSecond":925000000},"threadId":1,"threadPriority":5,"source":{"class":"org.springframework.boot.SpringApplication","method":"logStartupProfileInfo","file":"SpringApplication.java","line":675}}
{"thread":"main","level":"INFO","loggerName":"org.springframework.data.repository.config.RepositoryConfigurationDelegate","message":"Bootstrapping Spring Data repositories in DEFAULT mode.","endOfBatch":false,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","instant":{"epochSecond":1555386054,"nanoOfSecond":298000000},"threadId":1,"threadPriority":5,"source":{"class":"org.springframework.data.repository.config.RepositoryConfigurationDelegate","method":"registerRepositoriesIn","file":"RepositoryConfigurationDelegate.java","line":126}}
{"thread":"main","level":"INFO","loggerName":"org.springframework.data.repository.config.RepositoryConfigurationDelegate","message":"Finished Spring Data repository scanning in 49ms. Found 3 repository interfaces.","endOfBatch":false,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","instant":{"epochSecond":1555386054,"nanoOfSecond":350000000},"threadId":1,"threadPriority":5,"source":{"class":"org.springframework.data.repository.config.RepositoryConfigurationDelegate","method":"registerRepositoriesIn","file":"RepositoryConfigurationDelegate.java","line":182}}
{"thread":"main","level":"INFO","loggerName":"org.springframework.boot.web.embedded.tomcat.TomcatWebServer","message":"Tomcat initialized with port(s): 19999 (http)","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.LogAdapter$Log4jLog","instant":{"epochSecond":1555386054,"nanoOfSecond":715000000},"threadId":1,"threadPriority":5,"source":{"class":"org.springframework.boot.web.embedded.tomcat.TomcatWebServer","method":"initialize","file":"TomcatWebServer.java","line":90}}
{"thread":"main","level":"INFO","loggerName":"org.apache.coyote.http11.Http11NioProtocol","message":"Initializing ProtocolHandler [\"http-nio-19999\"]","endOfBatch":false,"loggerFqcn":"java.util.logging.Logger","instant":{"epochSecond":1555386054,"nanoOfSecond":730000000},"threadId":1,"threadPriority":5,"source":{"class":"org.apache.juli.logging.DirectJDKLog","method":"log","file":"DirectJDKLog.java","line":173}}
{"thread":"main","level":"INFO","loggerName":"org.apache.catalina.core.StandardService","message":"Starting service [Tomcat]","endOfBatch":false,"loggerFqcn":"java.util.logging.Logger","instant":{"epochSecond":1555386054,"nanoOfSecond":737000000},"threadId":1,"threadPriority":5,"source":{"class":"org.apache.juli.logging.DirectJDKLog","method":"log","file":"DirectJDKLog.java","line":173}}
{"thread":"main","level":"INFO","loggerName":"org.apache.catalina.core.StandardEngine","message":"Starting Servlet engine: [Apache Tomcat/9.0.17]","endOfBatch":false,"loggerFqcn":"java.util.logging.Logger","instant":{"epochSecond":1555386054,"nanoOfSecond":738000000},"threadId":1,"threadPriority":5,"source":{"class":"org.apache.juli.logging.DirectJDKLog","method":"log","file":"DirectJDKLog.java","line":173}}
{"thread":"main","level":"INFO","loggerName":"org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/]","message":"Initializing Spring embedded WebApplicationContext","endOfBatch":false,"loggerFqcn":"java.util.logging.Logger","instant":{"epochSecond":1555386054,"nanoOfSecond":927000000},"threadId":1,"threadPriority":5,"source":{"class":"org.apache.juli.logging.DirectJDKLog","method":"log","file":"DirectJDKLog.java","line":173}}
{"thread":"main","level":"INFO","loggerName":"org.springframework.web.context.ContextLoader","message":"Root WebApplicationContext: initialization completed in 974 ms","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.LogAdapter$Log4jLog","instant":{"epochSecond":1555386054,"nanoOfSecond":928000000},"threadId":1,"threadPriority":5,"source":{"class":"org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext","method":"prepareWebApplicationContext","file":"ServletWebServerApplicationContext.java","line":296}}
{"thread":"main","level":"INFO","loggerName":"org.elasticsearch.plugins.PluginsService","marker":{"name":"[_client_] "},"message":"no modules loaded","endOfBatch":false,"loggerFqcn":"org.apache.logging.log4j.spi.AbstractLogger","instant":{"epochSecond":1555386055,"nanoOfSecond":182000000},"threadId":1,"threadPriority":5,"source":{"class":"org.elasticsearch.plugins.PluginsService","method":"logPluginInfo","file":"PluginsService.java","line":181}}
{"thread":"main","level":"INFO","loggerName":"org.elasticsearch.plugins.PluginsService","marker":{"name":"[_client_] "},"message":"loaded plugin [org.elasticsearch.index.reindex.ReindexPlugin]","endOfBatch":false,"loggerFqcn":"org.apache.logging.log4j.spi.AbstractLogger","instant":{"epochSecond":1555386055,"nanoOfSecond":188000000},"threadId":1,"threadPriority":5,"source":{"class":"org.elasticsearch.plugins.PluginsService","method":"logPluginInfo","file":"PluginsService.java","line":184}}
{"thread":"main","level":"INFO","loggerName":"org.elasticsearch.plugins.PluginsService","marker":{"name":"[_client_] "},"message":"loaded plugin [org.elasticsearch.join.ParentJoinPlugin]","endOfBatch":false,"loggerFqcn":"org.apache.logging.log4j.spi.AbstractLogger","instant":{"epochSecond":1555386055,"nanoOfSecond":189000000},"threadId":1,"threadPriority":5,"source":{"class":"org.elasticsearch.plugins.PluginsService","method":"logPluginInfo","file":"PluginsService.java","line":184}}
{"thread":"main","level":"INFO","loggerName":"org.elasticsearch.plugins.PluginsService","marker":{"name":"[_client_] "},"message":"loaded plugin [org.elasticsearch.percolator.PercolatorPlugin]","endOfBatch":false,"loggerFqcn":"org.apache.logging.log4j.spi.AbstractLogger","instant":{"epochSecond":1555386055,"nanoOfSecond":189000000},"threadId":1,"threadPriority":5,"source":{"class":"org.elasticsearch.plugins.PluginsService","method":"logPluginInfo","file":"PluginsService.java","line":184}}
{"thread":"main","level":"INFO","loggerName":"org.elasticsearch.plugins.PluginsService","marker":{"name":"[_client_] "},"message":"loaded plugin [org.elasticsearch.script.mustache.MustachePlugin]","endOfBatch":false,"loggerFqcn":"org.apache.logging.log4j.spi.AbstractLogger","instant":{"epochSecond":1555386055,"nanoOfSecond":189000000},"threadId":1,"threadPriority":5,"source":{"class":"org.elasticsearch.plugins.PluginsService","method":"logPluginInfo","file":"PluginsService.java","line":184}}
{"thread":"main","level":"INFO","loggerName":"org.elasticsearch.plugins.PluginsService","marker":{"name":"[_client_] "},"message":"loaded plugin [org.elasticsearch.transport.Netty4Plugin]","endOfBatch":false,"loggerFqcn":"org.apache.logging.log4j.spi.AbstractLogger","instant":{"epochSecond":1555386055,"nanoOfSecond":190000000},"threadId":1,"threadPriority":5,"source":{"class":"org.elasticsearch.plugins.PluginsService","method":"logPluginInfo","file":"PluginsService.java","line":184}}
{"thread":"main","level":"INFO","loggerName":"org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor","message":"Initializing ExecutorService 'applicationTaskExecutor'","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.LogAdapter$Log4jLog","instant":{"epochSecond":1555386057,"nanoOfSecond":714000000},"threadId":1,"threadPriority":5,"source":{"class":"org.springframework.scheduling.concurrent.ExecutorConfigurationSupport","method":"initialize","file":"ExecutorConfigurationSupport.java","line":171}}
{"thread":"main","level":"INFO","loggerName":"org.apache.coyote.http11.Http11NioProtocol","message":"Starting ProtocolHandler [\"http-nio-19999\"]","endOfBatch":false,"loggerFqcn":"java.util.logging.Logger","instant":{"epochSecond":1555386058,"nanoOfSecond":44000000},"threadId":1,"threadPriority":5,"source":{"class":"org.apache.juli.logging.DirectJDKLog","method":"log","file":"DirectJDKLog.java","line":173}}
{"thread":"main","level":"INFO","loggerName":"org.springframework.boot.web.embedded.tomcat.TomcatWebServer","message":"Tomcat started on port(s): 19999 (http) with context path ''","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.LogAdapter$Log4jLog","instant":{"epochSecond":1555386058,"nanoOfSecond":55000000},"threadId":1,"threadPriority":5,"source":{"class":"org.springframework.boot.web.embedded.tomcat.TomcatWebServer","method":"start","file":"TomcatWebServer.java","line":204}}
本片文章是在 SpringBoot 工程基础上对 Log4j 配置的说明,希望能够给大家提供帮助。