推荐阅读:
<?xml version="1.0" encoding="UTF-8"?>
<!--
status : 用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,会看到log4j2内部各种详细输出
monitorInterval : Log4j能够自动检测修改配置文件和重新配置本身, 设置间隔秒数
-->
<Configuration status="WARN" monitorInterval="600">
<Properties>
<!-- 配置日志文件输出目录 -->
<Property name="LOG_HOME">./logs</Property>
</Properties>
<Appenders>
<!-- 输出控制台的配置 -->
<Console name="Console" target="SYSTEM_OUT">
<!-- 控制台只输出 level 及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<!-- 输出日志的格式 -->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</Console>
<!-- 设置日志格式并配置日志压缩格式(sinfo.log.日期.gz) -->
<RollingRandomAccessFile name="sinfo_appender"
immediateFlush="false" fileName="${LOG_HOME}/sinfo.log"
filePattern="${LOG_HOME}/service.log.%d{yyyy-MM-dd}.log.gz">
<!--
%d{yyyy-MM-dd HH:mm:ss, SSS} : 日志生产时间
%p : 日志输出格式
%c : logger的名称
%m : 日志内容,即 logger.info("message")
%n : 换行符
%C : Java类名
%L : 日志输出所在行数
%M : 日志输出所在方法名
hostName : 本地机器名
hostAddress : 本地ip地址
-->
<PatternLayout>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{36} %L %M -- %msg%xEx%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingRandomAccessFile>
<!-- DEBUG日志格式 -->
<RollingRandomAccessFile name="sinfo_debug_appender"
immediateFlush="false" fileName="${LOG_HOME}/sinfo.log"
filePattern="${LOG_HOME}/sinfo.log.%d{yyyy-MM-dd}.debug.gz">
<PatternLayout>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{36} %L %M -- %msg%xEx%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<!-- 配置日志的根节点 -->
<root level="info">
<appender-ref ref="Console"/>
</root>
<!-- 第三方日志系统 -->
<logger name="org.springframework.core" level="info"/>
<logger name="org.springframework.beans" level="info"/>
<logger name="org.springframework.context" level="info"/>
<logger name="org.springframework.web" level="info"/>
<logger name="org.jboss.netty" level="warn"/>
<logger name="org.apache.http" level="warn"/>
<!-- 日志实例(info),其中'service-log'继承root,但是root将日志输出控制台,而'service-log'将日志输出到文件,通过属性'additivity="false"'将'service-log'的
的日志不再输出到控制台 -->
<logger name="sinfo_log" level="info" includeLocation="true" additivity="true">
<appender-ref ref="sinfo_appender"/>
</logger>
<!-- 日志实例(debug) -->
<logger name="sinfo_log" level="info" includeLocation="true" additivity="false">
<appender-ref ref="sinfo_debug_appender"/>
</logger>
</Loggers>
</Configuration>
一、Log4J 组件
-
Logger
:日志记录器,负责收集处理日志记录 (如何处理日志) -
Level
: 日志级别,规定输出的日志级别(输出什么级别的日志) -
Appender
:日志输出目的地,负责日志的输出 (输出到什么 地方) -
Layout
:日志格式化,负责对输出的日志格式化(以什么形式展现)
二、log4J2 配置种类及加载顺序
1、四种实现方式
- 通过 XML、JSON、YAML、properties 格式的配置文件
- 通过创建一个 ConfigurationFactory 和 Configuration 接口实现
- 调用 Configuration 接口暴露的方法来在默认配置的基础上添加其他组件
- 通过在内部 Logger 类上调用方法
2、配置文件加载顺序
Log4J 启动时可以按照以下顺序自动加载配置文件:
- 先查找
log4j.configurationFile
文件,并尝试使用ConfigurationFactory
加载指定配置文件在代码中调用
System.setProperties("log4j.configurationFile","FILE_PATH")
或将-Dlog4jconfigurationFile=file://C:/configuration.xml
参数传递给 JVM - 接着在 classpath 中寻找
log4j2-test.properties
配置文件 - 接着在 classpath 中寻找
log4j2-test.yaml
或log4j2-test.yml
配置文件 - 接着在 classpath 中寻找
log4j2-test.json
或log4j2-test.jsn
配置文件 - 接着在 classpath 中寻找
log4j2-test.xml
配置文件 - 接着在 classpath 中寻找
log4j2.properties
配置文件 - 接着在 classpath 中寻找
log4j2.yaml
或log4j2.yml
配置文件 - 接着在 classpath 中寻找
log4j2.json
或log4j2.jsn
配置文件 - 接着在 classpath 中寻找
log4j2.xml
配置文件 - 若上面的配置文件都没有找到,就使用默认的 DefaultConfiguration 配置
默认配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<!-- 默认打印到控制台 -->
<Console name="Console" target="SYSTEM_OUT">
<!-- 默认打印格式 -->
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<!-- 默认打印日志级别为 error -->
<Root level="error">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
三、xml 配置文件详解
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug" strict="true" name="XMLConfigTest"
packages="org.apache.logging.log4j.test">
<Properties>
<Property name="filename">target/test.log</Property>
</Properties>
<Filter type="ThresholdFilter" level="trace"/>
<Appenders>
<Appender type="Console" name="STDOUT">
<Layout type="PatternLayout" pattern="%m MDC%X%n"/>
<Filters>
<Filter type="MarkerFilter" marker="FLOW" onMatch="DENY" onMismatch="NEUTRAL"/>
<Filter type="MarkerFilter" marker="EXCEPTION" onMatch="DENY" onMismatch="ACCEPT"/>
</Filters>
</Appender>
<Appender type="Console" name="FLOW">
<Layout type="PatternLayout" pattern="%C{1}.%M %m %ex%n"/><!-- class and line number -->
<Filters>
<Filter type="MarkerFilter" marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
<Filter type="MarkerFilter" marker="EXCEPTION" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
</Appender>
<Appender type="File" name="File" fileName="${filename}">
<Layout type="PatternLayout">
<Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
</Layout>
</Appender>
</Appenders>
<Loggers>
<Logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
<Filter type="ThreadContextMapFilter">
<KeyValuePair key="test" value="123"/>
</Filter>
<AppenderRef ref="STDOUT"/>
</Logger>
<Logger name="org.apache.logging.log4j.test2" level="debug" additivity="false">
<AppenderRef ref="File"/>
</Logger>
<Root level="trace">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
1、Configuration 标签
Configuration 元素可以使用以下属性:
-
advertiser
:可选,用来通知个别 FileAppender 或 SocketAppender 的配置目前唯一可用 Advertiser 名为
multicastdns
-
dest
:err (将输出到 stderr 上)或一个文件路径或一个URL -
monitorInterval
:检查配置文件是否有更新的间隔秒数 -
name
:配置的名称 -
packages
:逗号分隔,用于搜索插件的包名列表插件只会被每个类加载器加载一次,所以仅重新配置该项不会生效
-
schema
:为类加载器定位 XML Schema 位置以验证配置仅当 strict 属性设置为 true 时该属性才有效,如果不设置该属性,则不会验证 Schema
-
shutdownHook
:设置当 JVM 关闭时 log4j 是否也自动关闭,默认启用,也可设置为 disable 来禁用关闭钩子 -
shutdownTimeout
:设置当 JVM 关闭后 Appender 和后台任务超时多少毫秒才关闭,默认为 0 ,表示每个 Appender 使用其默认的超时,不等待后台任务 -
status
:打印到控制台的 Log4j 日志级别,可设置的值有 trace、debug、info、warn、error 和 fatal -
strict
:使用严格的 XML 格式, JSON 格式的配置文件不支持该属性 -
verbose
:加载插件时是否显示诊断信息
2、Appender 标签
Log4j 使用 Appender 将日志事件数据写到各种目标位置:控制台、文件、多种数据库 API、远程套接字服务器、Apache Flume、JMS、远程 UNIX Syslog daemon 等
- Appender 将格式化事件的责任委托给 Layout
- Appender 可以通过特定的 Appender 插件名或 appender 元素(带有指定 Appender 插件名的 type 属性)来配置
- Appender 必须有 name 属性,用来指定一个去别区其他 Appender 的唯一标识,该标识的值在 Logger 中通过 AppenderRef 来引用,从而将该 Appender 配置到该 Logger 中
- Appender 必须实现 Appender 接口,多数 Appender 都扩展自 AbstractAppender ,该抽象类添加了 Lifecycle 和 Filterable 支持
- Lifecycle 可以对日志组件在配置加载后进行初始化和在关闭时进行清理等操作
- Filterable 可以让日志组件绑定用于处理日志事件的过滤器
3、ConsoleAppender
ConsoleAppender 会将输出写入 System.out(默认)或 System.err 中,必须提供一个 Layout 来格式化 LogEvent
参数名 | 类型 | 描述 |
---|---|---|
filter | Filter | 指定一个过滤器来决定是否将日志事件传递给 Appender 处理,可以指定为 CompositeFilter 来使用多个过滤器 |
layout | Layout | 指定格式化 LogEvent 的 Layout,默认使用 %m%n 格式 |
follow | boolean | 可通过 System.setOut 或 System.setErr 来重新指定输出位置为 System.out 或 System.err |
direct | boolean | 绕开 java.lang.System.out/.err 直接写入 java.io.FileDescriptor |
name | String | 必选,区别于其他 Appender 的唯一标识 |
ignoreExceptions | boolean | 默认为 true,表示当输出事件时出现的异常会被内部记录而忽略;当设置为 false 时,则会将异常传播给调用者 当将该 Appender 包装成 FailoverAppender 时,必须设置为 false |
target | String | SYSTEM_OUT 或 SYSTEM_ERR,默认为 SYSTEM_OUT |
典型的 ConsoleAppender 配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
4、RollingFileAppender
RollingFileAppender 会将日志输出到 fileName 参数指定的文件中,且需要指定 TriggeringPolicy 和 RolloverStrategy:
-
TriggeringPolicy
决定是否生成新的日志文件 -
RolloverStrategy
决定如何生成新的日志文件,默认使用 DefaultRolloverStrategy
参数名 | 类型 | 描述 |
---|---|---|
append | boolean | 为 true(默认)时,日志记录将会添加到文件末尾;为 false 时,日志记录写入文件之前会清空文件 |
bufferedIO | boolean | 为 true(默认)时,日志记录将会写入一个缓冲区,当缓冲区满或设置了 immediateFlush ,日志记录才会写入磁盘中 该属性不能使用文件锁,缓冲 I/O 能够显著提高性能,即使启用了immediateFlush |
bufferSize | int | 当 bufferedIO 为 true 时,该属性用来设置缓冲区的大小,默认为 8192 字节 |
createOnDemand | boolean | Appender 按需创建文件,仅当日志事件通过所有过滤器并到达 Appender 时,该 Appender 才会创建文件,默认 false |
filter | Filter | 指定一个过滤器来决定是否将日志事件传递给 Appender 处理,可以指定为一个 CompositeFilter 来使用多个过滤器 |
fileName | String | 设置写入日志记录的文件名,若该文件或其父目录不存在,则会自动创建 |
filePattern | String | 归档日志文件的文件名模式 pattern ,依赖于所用的 RolloverPolicy |
immediateFlush | boolean | 为 true(默认)时,每次写入都会跟随一次 flush ,保证数据写入磁盘,但会影响性能;异步的 Logger 和 Appender 会在一批次的日志事件末尾自动 flush |
layout | Layout | 指定格式化 LogEvent 的 Layout ,若没有指定 Layout ,则默认使用 %m%n 格式 |
name | String | 必选的 Appender 的名称,表示区别于其他 Appender 的唯一标识 |
policy | TriggeringPolicy | 设置确定是否创建文件的规则 policy
|
strategy | RolloverStrategy | 设置确定归档文件的文件名和位置的策略 strategy
|
ignoreExceptions | boolean | 默认为 true ,表示当输出事件时出现的异常将会被内部记录而忽略;当为 false 时,则会将异常传播给调用者 当将该 Appender 包装成 FailoverAppender 时,必须设置为 false |
filePermissions | String | 设置每当创建文件时所用的 POSIX 格式的文件属性权限,比如: rw------- 或 rw-rw-rw- 等 |
fileOwner | String | 指定每次创建文件的属主,仅当有效的目标用户 ID 和文件的用户 ID 相同,或目标用户 ID 具有修改文件属主的权限时才会处理 |
fileGroup | String | 指定每次创建文件的属组,底层文件系统应该支持 POSIX 格式的文件属性视图 |
(1) 滚动触发案例
案例一:同时指定基于时间和大小的触发规则,将会一天最多创建 7 个归档文件(未配置 DefaultRolloverStrategy 时,max 属性默认为 7),存放在当前年月目录下,每个归档文件使用 gzip 进行压缩
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
案例二:在删除前保留 20 个文件的重新生成策略
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
<DefaultRolloverStrategy max="20"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
案例三:同时指定基于时间和大小的触发规则,将会一天最多创建 7 个归档文件,存放在当前年月目录下,每个归档文件使用 gzip 进行压缩,每 6 个小时滚动一次(小时数能被 6 整除)
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="6" modulate="true"/>
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
案例四:同时使用基于 cron 表达式和大小的触发规则,直接将日志以编号无限制的方式写入的归档文件中。cron 触发器会每小时滚动一次,而每个日志文件的大小限制在 250 MB,超过此大小就会滚动(新文件的编号递增)
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<RollingFile name="RollingFile" filePattern="logs/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<CronTriggeringPolicy schedule="0 0 * * * ?"/>
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
案例五:下面的配置和上面的基本一样,但是限制每小时里文件编号最大为 10
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<RollingFile name="RollingFile" filePattern="logs/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<CronTriggeringPolicy schedule="0 0 * * * ?"/>
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
<DirectWriteRolloverStrategy maxFiles="10"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
(2) 滚动删除案例
案例一:使用 cron 触发规则,每天晚上触发一次,归档文件存放在当前年月目录,所有位于基准目录下匹配 */app-*.log.gz
的文件,达到或超过 60 天的文件将会在滚动时删除
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Properties>
<Property name="baseDir">logs</Property>
</Properties>
<Appenders>
<RollingFile name="RollingFile" fileName="${baseDir}/app.log"
filePattern="${baseDir}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd}.log.gz">
<PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
<CronTriggeringPolicy schedule="0 0 0 * * ?"/>
<DefaultRolloverStrategy>
<Delete basePath="${baseDir}" maxDepth="2">
<IfFileName glob="*/app-*.log.gz" />
<IfLastModified age="60d" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
案例二:使用基于时间和文件大小的触发规则,每天最多生成 100 个归档日志文件,使用 gzip 压缩,存放在当前年月目录,每小时都会滚动。每次滚动都会删除匹配 */app-*.log.gz
、达到或超过 30 天的文件,但会保留最近 100 GB 的文件或最近的 1000 个文件(这两个条件哪个先满足就使用哪一个条件)
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Properties>
<Property name="baseDir">logs</Property>
</Properties>
<Appenders>
<RollingFile name="RollingFile" fileName="${baseDir}/app.log"
filePattern="${baseDir}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
<PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
<DefaultRolloverStrategy max="100">
<!--
Nested conditions: the inner condition is only evaluated on files
for which the outer conditions are true.
-->
<Delete basePath="${baseDir}" maxDepth="2">
<IfFileName glob="*/app-*.log.gz">
<IfLastModified age="30d">
<IfAny>
<IfAccumulatedFileSize exceeds="100 GB" />
<IfAccumulatedFileCount exceeds="1000" />
</IfAny>
</IfLastModified>
</IfFileName>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
(3) 滚动时自定义文件属性
案例:为当前和已滚动日志文件定义了不同的 POSIX 文件属性视图
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace" name="MyApp" packages="">
<Properties>
<Property name="baseDir">logs</Property>
</Properties>
<Appenders>
<RollingFile name="RollingFile" fileName="${baseDir}/app.log"
filePattern="${baseDir}/$${date:yyyy-MM}/app-%d{yyyyMMdd}.log.gz"
filePermissions="rw-------">
<PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
<CronTriggeringPolicy schedule="0 0 0 * * ?"/>
<DefaultRolloverStrategy stopCustomActionsOnError="true">
<PosixViewAttribute basePath="${baseDir}/$${date:yyyy-MM}" filePermissions="r--r--r--">
<IfFileName glob="*.gz" />
</PosixViewAttribute>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>