欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

升级log4j 2.x版本 缓存异步化配置解读

程序员文章站 2022-04-14 13:29:52
...

 转载请注明出处:http://zl378837964.iteye.com/blog/2359382

 

现在最新的Log4j 2 是V2.8版本,使用2.x版本需要引入jar如下:

<dependency>
	<groupId>org.apache.logging.log4j</groupId>
	<artifactId>log4j-core</artifactId>
	<version>2.5</version>
</dependency>
<dependency>
	<groupId>org.apache.logging.log4j</groupId>
	<artifactId>log4j-api</artifactId>
	<version>2.5</version>
</dependency>

 下面两个分别是兼容V1.x 和 实现异步化需要的jar:

(Disruptor它是开源的并发框架,能够在无锁的情况下实现网络的Queue并发操作。)

<dependency>
	<groupId>org.apache.logging.log4j</groupId>
	<artifactId>log4j-1.2-api</artifactId>
	<version>2.5</version>
</dependency>
(注意:require disruptor-3.3.3.jar or higher)
<dependency>
	<groupId>com.lmax</groupId>
	<artifactId>disruptor</artifactId>
	<version>3.3.4</version>
</dependency>

     

        V2.x版本的配置方式,除了编码式的写入,还有XML, JSON, YAML 和 Properties(注意这个是V2.4之后重新支持的,配置方式类似XML和 JSON不同于以往V1.x版本) 配置文件 on the classpath 即可实现,还有定义变量,过滤设置,定时删除日志,支持JDK8的Lambda等新特性;还能兼容 Log4j 1.2, SLF4J, Commons Logging 和 java.util.logging (JUL) APIs等各个日志工具;也可以定时重载配置文件,只需简单添加如下:

<Configuration monitorInterval="30" status="INFO">

... 单位是s,最小间隔5s

... 共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF

</Configuration>

 

 

若想使用YAML格式,需要引入格式化工具如下:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-yaml</artifactId>
    <version>2.8.5</version>
</dependency>

 若想使用JSON格式,需要引入格式化工具如下:

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.8.5</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.8.5</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.8.5</version>
</dependency>

 

### Log4j2最突出即支持高效低延迟的异步化写日志 ###

 

Asynchronous Loggers是一个新增特性在Log4j 2 ,可以实现完全异步也可以和同步混合使用,还可以只异步化Appender,以提升系统性能,官方数据显示混合没有完全异步化效果好(下图)。

升级log4j 2.x版本 缓存异步化配置解读
            
    
    博客分类: java java日志log4j异步性能优化

1、完全异步化XML配置+参数如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. -->
    <RandomAccessFile name="RandomAccessFile" fileName="async.log" immediateFlush="false" append="false">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m %ex%n</Pattern>
      </PatternLayout>
    </RandomAccessFile>
  </Appenders>
  <Loggers>
    <Root level="info" includeLocation="false">
      <AppenderRef ref="RandomAccessFile"/>
    </Root>
  </Loggers>
</Configuration>

 注意啦,注意啦!配置参数!

A.想要loggers完全异步化一定不要忘记设置启动参数: -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector 

B.或者,建立log4j2.component.properties文件放classpath下面,log4j2会在启动时自动加载,然后日志输出就变成异步输出。

文件内容:Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

 

2、Mixed同步和异步,由于使用了disruptor,标签化实现不再需要设置启动参数(关于Log4jContextSelector);

<asyncRoot> 或 <asyncLogger>可以和<root> 或 <logger>混合使用。

混合使用的xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<!-- No need to set system property "Log4jContextSelector" to any value when using <asyncLogger> or <asyncRoot>. -->
<Configuration status="WARN">
  <Appenders>
    <!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. -->
    <RandomAccessFile name="RandomAccessFile" fileName="asyncWithLocation.log"
              immediateFlush="false" append="false">
      <PatternLayout>
        <Pattern>%d %p %class{1.} [%t] %location %m %ex%n</Pattern>
      </PatternLayout>
    </RandomAccessFile>
  </Appenders>
  <Loggers>
    <!-- pattern layout actually uses location, so we need to include it -->
    <AsyncLogger name="com.foo.Bar" level="trace" includeLocation="true">
      <AppenderRef ref="RandomAccessFile"/>
    </AsyncLogger>
    <Root level="info" includeLocation="true">
      <AppenderRef ref="RandomAccessFile"/>
    </Root>
  </Loggers>
</Configuration>

eg.一个完整项目XML配置实例如下: 

 

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="ERROR">
    <Properties>
        <Property name="baseDir">/Users/chocolate/logs</Property>
        <Property name="filename">/Users/chocolate/logs/baseCollection.log</Property>
        <Property name="filenameError">/Users/chocolate/logs/baseCollectionError.log</Property>
    </Properties>

    <Appenders>
        <Console name="STDOUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %l - %msg%n"/>
        </Console>
        <RollingFile name="RollingFile" fileName="${filename}"
                     filePattern="${baseDir}/${date:yyyy-MM}/baseCollection-%d{yyyy-MM-dd-HH-mm}.log.gz">
            <PatternLayout pattern="%d %-5level [%t]%l - %msg%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="200 MB"/>
                <TimeBasedTriggeringPolicy interval="10" modulate="true"/>
            </Policies>
            <!--自动删除超过120天的日志压缩文件-->
            <DefaultRolloverStrategy>
                <Delete basePath="${baseDir}" maxDepth="2">
                    <IfFileName glob="*/baseCollection-*.log.gz"/>
                    <IfLastModified age="20d"/>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>
        <!--错误日志入文件-->
        <RollingFile name="RollingFileError" fileName="${filenameError}"
                     filePattern="${baseDir}/${date:yyyy-MM}/baseCollectionError-%d{yyyy-MM-dd-HH}.log">
            <PatternLayout pattern="%d %-5level [%t]%l - %msg%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="200 MB"/>
                <TimeBasedTriggeringPolicy interval="24" modulate="true"/>
            </Policies>
            <!--自动删除超过120天的日志压缩文件-->
            <DefaultRolloverStrategy>
                <Delete basePath="${baseDir}" maxDepth="2">
                    <IfFileName glob="*/baseCollectionError-*.log"/>
                    <IfLastModified age="30d"/>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>
    </Appenders>
    <Loggers>
        <!--采用异步输出日志-->
        <AsyncLogger name="com.choco" level="info">
            <!--写入info级别-->
            <AppenderRef ref="RollingFile"/>
            <!--写入error级别-->
            <AppenderRef ref="RollingFileError" level="error"/>
        </AsyncLogger>
        <Root level="debug">
            <AppenderRef ref="STDOUT"/>
        </Root>
    </Loggers>
</Configuration>

 注意点:

<I>

有时候会出现同一日志文件中log4j日志打印重复,这是因为如下配置中 Console 被设置成logger和root的appender了,

此时只需要设置additivity="false"即可解决。(the appender associated with logger com.foo.Bar is first used, which writes the first instance to the Console. Next, the parent of com.foo.Bar, which in this case is the root logger, is referenced. The event is then passed to its appender, which is also writes to the Console, resulting in the second instance.)

<?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>
    <!--控制输出trace,不继承-->
    <Logger name="com.foo.Bar" level="trace" additivity="false">
      <!--控制台打印指定包路径下面的info以上-->
      <AppenderRef ref="Console" level="info"/>
    </Logger>
    <Root level="error">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

 

<II> 

Log4jV1.x升级V2.x需注意,原项目用的是log4j或者self4j,获取logger方式不同:

Log4j实例:

import org.apache.log4j.Logger;

private static final Logger LOGGER = Logger.getLogger(X.class);

Slf4j实例: 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

private static final Logger logger = LoggerFactory.getLogger(X.class);

Log4j2的使用: 

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

private static final Logger logger = LogManager.getLogger(X.class);

Log4j V2.x基于上面不同提供了转换包,只需要导入几个转换包就可以透明的使用Log4j2配置,从而避免大工程中的代码修改,耶耶耶!

但是,官方出来几个限制条件:

  1. They must not access methods and classes internal to the Log4j 1.x implementation such as Appenders, LoggerRepository or Category's callAppenders method.
  2. They must not programmatically configure Log4j.
  3. They must not configure by calling the classes DOMConfigurator or PropertyConfigurator.

<III> 

 log4j输出缓存日志以8K为单位,磁盘的一个block为8K,这样可以减少碎片;也就是说假设你设置缓存为20K,log4j在16K(8K*2)的时候就会输出),而不是20K。

 

附录A:

Appenders 官方文档:http://logging.apache.org/log4j/2.x/manual/appenders.html(23种应有尽有)

Async Low-Latency Loggers 官方文档:http://logging.apache.org/log4j/2.x/manual/async.html

log4j 2 官方配置:http://logging.apache.org/log4j/2.x/manual/configuration.html

 

附录B:

Properties configuration files support the advertiser, monitorInterval, name, packages, shutdownHook, shutdownTimeout, status, verbose, and dest attrbutes. See Configuration Syntax for the definitions of these attributes.(Props方式在V2.x不通用于各个版本,不建议使用)

status = error
dest = err
name = PropertiesConfig
 
property.filename = target/rolling/rollingtest.log
 
filter.threshold.type = ThresholdFilter
filter.threshold.level = debug
 
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %m%n
 
appender.rolling.type = RollingFile
appender.rolling.name = RollingFile
appender.rolling.fileName = ${filename}
appender.rolling.filePattern = target/rolling2/test1-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 2
appender.rolling.policies.time.modulate = true
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling.policies.size.size=100MB
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 5
 
appender.list.type = List
appender.list.name = List
appender.list.filter.threshold.type = ThresholdFilter
appender.list.filter.threshold.level = error
 
logger.rolling.name = com.example.my.app
logger.rolling.level = debug
logger.rolling.additivity = false
logger.rolling.appenderRef.rolling.ref = RollingFile
 
rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT