Apache Log4j 2是对Log4j的升级版,参考了logback的一些优秀的设计,并且修复了一些问题,因此带来了一些重大的提升,主要有:
异常处理,在 logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异常处理机制。
性能提升, log4j2相较于log4j 和logback都具有很明显的性能提升。
自动重载配置,参考了 logback的设计,会提供自动刷新参数配置,最实用的就是我们在生产上可以动态的修改日志的级别而不需要重启应用。
无垃圾机制, log4j2在大部分情况下,都可以使用其设计的一套无垃圾机制,避免频繁的日志收集导致的jvm gc。
Log4j2入门:目前市面上最主流的日志门面就是SLF4J,虽然Log4j2也是日志门面,因为它的日志实现功能非常强大,性能优越。
但一般还是将Log4j2看作是日志的实现,代码和前一章是没有区别的,主要是通过修改配置文件和pom.xml依赖,Slf4j + Log4j2是未来的大势所趋。
1.创建工程,引入依赖
不使用日志门面 SLF4J,使用 log4j2 的API:
<dependencies> <!-- Log4j2 门面API--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.11.2</version> </dependency> <!-- Log4j2 日志实现 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.11.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
使用日志门面 SLF4J:
<dependencies> <!--使用slf4j作为日志的门面,使用log4j2来记录日志 --> <!-- Log4j2 门面API--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.11.2</version> </dependency> <!-- Log4j2 日志实现 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.11.2</version> </dependency> <!--为slf4j绑定日志实现 log4j2的适配器 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.9.1</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
2.配置文件 log4j2.xml ,无论是否使用日志门面 SLF4J 配置都是一样的
<?xml version="1.0" encoding="UTF-8"?> <!-- status="warn" 日志框架本身的输出日志级别 monitorInterval="5" 自动加载配置文件的间隔时间,不低于 5 秒 --> <Configuration status="debug" monitorInterval="5"> <!-- 集中配置属性进行管理 使用时通过:${name} --> <properties> <property name="LOG_HOME">d:/logs</property> </properties> <!--日志处理--> <Appenders> <!--控制台输出 appender--> <Console name="Console" target="SYSTEM_ERR"> <!-- SYSTEM_OUT 黑色 --> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n" /> </Console> <!--日志文件输出 appender--> <File name="file" fileName="${LOG_HOME}/log4j2.log"> <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" /> </File> <!--使用随机读写流的日志文件输出 appender,性能提高--> <RandomAccessFile name="accessFile" fileName="${LOG_HOME}/myAcclog.log"> <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" /> </RandomAccessFile> <!--按照一定规则拆分日志文件的 appender--> <RollingFile name="rollingFile" fileName="${LOG_HOME}/myrollog.log" filePattern="d:/logs/$${date:yyyy-MM-dd}/myrollog-%d{yyyy-MM-dd-HH-mm}-%i.log"> <!--日志级别过滤器--> <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" /> <!--日志消息格式--> <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %msg%n" /> <Policies> <!--在系统启动时,触发拆分规则,生产一个新的日志文件--> <OnStartupTriggeringPolicy /> <!--按照文件大小拆分,10MB --> <SizeBasedTriggeringPolicy size="10 MB" /> <!--按照时间节点拆分,规则根据filePattern定义的--> <TimeBasedTriggeringPolicy /> </Policies> <!--在同一个目录下,文件的个数限定为 30 个,超过进行覆盖--> <DefaultRolloverStrategy max="30" /> </RollingFile> </Appenders> <!--logger 定义--> <Loggers> <!--使用 rootLogger 配置 日志级别 level="trace"--> <Root level="trace"> <!--指定日志使用的处理器--> <AppenderRef ref="Console" /> <AppenderRef ref="file" /> <AppenderRef ref="accessFile" /> <AppenderRef ref="rollingFile" /> </Root> </Loggers> </Configuration>
3.测试
不使用日志门面 SLF4J,使用 log4j2 的API:
public class Log4j2Test { // 定义日志记录器对象 public static final Logger LOGGER = LogManager.getLogger(Log4j2Test.class); @Test public void testQuick() { LOGGER.fatal("fatal"); LOGGER.error("error"); LOGGER.warn("warn"); LOGGER.info("info"); LOGGER.debug("debug"); LOGGER.trace("trace"); } }
使用日志门面 SLF4J:
public class Slf4jTest { //定义日志对象 public final static Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class); @Test public void test01() { //打印日志信息 LOGGER.error("error"); LOGGER.warn("warn"); LOGGER.info("info"); LOGGER.debug("debug"); LOGGER.trace("trace"); } }
Log4j2异步日志:
log4j2最大的特点就是异步日志,其性能的提升主要也是从异步日志中受益
Log4j2 提供了两种实现异步日志的方式,一个是通过AsyncAppender(性能低,一般不使用),一个是通过AsyncLogger(分混合异步和全局异步),分别对应前面的Appender组件和Logger组件。
注意:配置异步日志需要添加依赖
<!--异步日志依赖--> <dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.4.2</version> </dependency>
AsyncLogger方式
全局异步:所有的日志都异步的记录,在配置文件上不用做任何改动,只需要添加一个 log4j2.component.properties 配置
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
混合异步:可以在应用中同时使用同步日志和异步日志,这使得日志的配置方式更加灵活
<!--logger 定义--> <Loggers> <!--自定义异步 logger 对象 includeLocation="false" 关闭日志记录的行号信息 additivity="false" 不在继承 rootlogger 对象 --> <AsyncLogger name="pers.fgy" level="trace" includeLocation="false" additivity="false"> <AppenderRef ref="Console"/> </AsyncLogger> <!--使用 rootLogger 配置 日志级别 level="trace"--> <Root level="trace"> <!--指定日志使用的处理器--> <AppenderRef ref="Console" /> <AppenderRef ref="file" /> <AppenderRef ref="accessFile" /> <AppenderRef ref="rollingFile" /> </Root> </Loggers>
如上配置: pers.fgy 日志是异步的,root日志是同步的。
使用异步日志需要注意的问题:
1. 如果使用异步日志,AsyncAppender、AsyncLogger和全局日志,不要同时出现,否则性能会和AsyncAppender一致,降至最低。
2. 设置includeLocation=false ,因为打印位置信息会急剧降低异步日志的性能,比同步日志还要慢。