log4j2配置详解及自定义Appender

一、背景


最近由于项目需要开始捣鼓项目组日志系统,日志系统中日志打印采用的是log4j2,同时需要支持公司日志采集需求,所以也会用到公司扩展的appender。之前做过的项目有有日志打印的功能也是采用log4j2组件。这篇文章主要是对这个组件的各个属性进行下总结,同时介绍下如何基于log4j2的Appender自定义Appender,满足项目需求。后边也会陆续的对log4j2的原理、性能等进行分析......

二、log4j2日志组件属性介绍


1.关于配置文件的名称以及在项目中的存放位置

log4j 2.x版本不再支持像1.x中的.properties后缀的文件配置方式,2.x版本配置文件后缀名只能为".xml",".json"或者".jsn"。

系统选择配置文件的优先级(从先到后)如下:

(1).classpath下的名为log4j2-test.json 或者log4j2-test.jsn的文件。

(2).classpath下的名为log4j2-test.xml的文件。

(3).classpath下名为log4j2.json 或者log4j2.jsn的文件。

(4).classpath下名为log4j2.xml的文件。

我们一般默认使用log4j2.xml进行命名。如果本地要测试,可以把log4j2-test.xml放到classpath,而正式环境使用log4j2.xml,则在打包部署的时候不要打包log4j2-test.xml即可。

2.缺省默认配置文件


      
      
  
      
      
    
       
       
      
        
        
        
         
         
      
        
        
    
       
       
    
       
       
      
        
        
       
         
         
     
        
        
   
       
       
 
      
      

3.配置文件节点解析

(1). 根节点Configuration有两个属性:status和monitorinterval,有两个子节点:Appenders和Loggers(表明可以定义多个Appender和Logger)。

status用来指定log4j本身的打印日志的级别。monitorinterval用于指定log4j自动重新配置的监测间隔时间,单位是s,最小是5s,例如:monitorInterval=”600” 指log4j2每隔600秒(10分钟),自动监控该配置文件是否有变化,如果变化,则自动根据文件内容重新配置。

(2).Appenders节点,常见的有三种子节点:Console、RollingFile、File。

Console节点用来定义输出到控制台的Appender。

name:指定Appender的名字。

target:SYSTEM_OUT 或 SYSTEM_ERR,一般只设置默认:SYSTEM_OUT。

PatternLayout:输出格式,不设置默认为:%m%n。

如:


      
      
    
       
       

      
      

RollingFile节点用来定义超过指定大小自动删除旧的创建新的的Appender。

name:指定Appender的名字。

fileName:指定输出日志的目的文件带全路径的文件名。

PatternLayout:输出格式,不设置默认为:%m%n。

filePattern:指定新建日志文件的名称格式。

Policies:指定滚动日志的策略,就是什么时候进行新建日志文件输出日志。

TimeBasedTriggeringPolicy:Policies子节点,基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour。modulate=true用来调整时间:比如现在是早上3am,interval是4,那么第一次滚动是在4am,接着是8am,12am...而不是7am。

SizeBasedTriggeringPolicy:Policies子节点,基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小。

DefaultRolloverStrategy:用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性)。

如:

      
      
    
       
       
        
       
       
            
        
        
            
        
        
        
       
       
    
       
       

      
      

File节点用来定义输出到指定位置的文件的Appender。

name:指定Appender的名字。

fileName:指定输出日志的目的文件带全路径的文件名。

PatternLayout:输出格式,不设置默认为:%m%n。

相对RollingFile来说File在项目中用的比较少。

(3).Loggers节点,常见的有两种:Root和Logger。

Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出

level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF。

AppenderRef:Root的子节点,用来指定该日志输出到哪个Appender。

Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。

level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF。

name:用来指定该Logger所适用的类或者类所在的包全路径,继承自Root节点。

AppenderRef:Logger的子节点,用来指定该日志输出到哪个Appender,如果没有指定,就会默认继承自Root。如果指定了,那么会在指定的这个Appender和Root的Appender中都会输出,此时我们可以设置Logger的additivity="false"只在自定义的Appender中进行输出。

(4).关于日志level

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

All:最低等级的,用于打开所有日志记录.

Trace:是追踪,就是程序推进以下,你就可以写个trace输出,所以trace应该会特别多,不过没关系,我们可以设置最低日志级别不让他输出。

Debug:指出细粒度信息事件对调试应用程序是非常有帮助的。

Info:消息在粗粒度级别上突出强调应用程序的运行过程。

Warn:输出警告及warn以下级别的日志。

Error:输出错误信息日志。

Fatal:输出每个严重的错误事件将会导致应用程序的退出的日志。

OFF:最高等级的,用于关闭所有日志记录。

程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少

4.比较完整的log4j2.xml配置模板


      
      
 
      
      
  
      
      
  
      
      
  
      
      
      
       
       
      
       
       
      
        
        
          
        
        
         
         
         
             
         
         
         
        
        
     
        
        
     
        
        
        
         
         
     
        
        
     
        
        
         
        
        
             
         
                 
             
         
         
             
         
         
             
         
         
                 
          
          
                 
          
          
             
         
         
         
        
        
         
        
        
             
         
         
             
         
         
             
         
         
                 
          
          
                 
          
          
             
         
         
         
         
         
             
         
         
         
        
        
         
        
        
             
         
         
             
         
         
             
         
         
                 
          
          
                 
          
          
             
         
         
         
        
        
     
       
       
     
       
       
     
       
       
         
        
        
         
        
        
         
        
        
         
        
        
             
         
         
             
         
         
             
         
         
             
         
         
         
        
        
     
       
       
 
      
      

三、自定义Appender

虽然log4j2自带了很多种Appender,通过这些Appender可以将日志输出到文件、DB、ES,但是有时候需要自定义Appender来满足业务需求,将日志输出到指定的位置。例如log4j2就没有为Scribe添加appender。

自定义Appender,继承 AbstractAppender 只需要覆盖自已想要的方法即可。

构建自定义的Appender需要注意以下几个点:

- @Plugin..注解:这个注解,是为了在之后配置log4j2.xml时,指定的Appender Tag。
- 构造函数:除了使用父类的以外,也可以增加一些自己的配置。
- 重写append()方法:这里面需要实现具体的逻辑,日志的去向。
- createAppender()方法:主要是接收log4j2.xml中的配置项。

先借用下大牛的代码:https://github.com/hawkingfoo/log-demo

贴一下实例分析下:

package logger;

import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;

import java.io.IOException;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
 * Created by hawkingfoo on 2017/6/29 0029.
 */
/*name就是在配置文件中要用到的标签<FileAppender/>*/
@Plugin(name = "FileAppender", category = "Core", elementType = "appender", printObject = true)
public class FileAppender extends AbstractAppender {
    private String fileName;

    /* 构造函数,除了实现父类需要的参数以外,还可以自定义需要的参数 */
    public FileAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions, String fileName) {
        super(name, filter, layout, ignoreExceptions);
        this.fileName = fileName;
    }

    /* 覆盖append方法,实现自定义功能,比如将日志写入文件或者发送到日志收集中心等 */
    @Override
    public void append(LogEvent event) {
        final byte[] bytes = getLayout().toByteArray(event);
        writerFile(bytes);

    }

    /* 接收配置文件中的参数 */
    @PluginFactory
    public static FileAppender createAppender(@PluginAttribute("name") String name,
                                              @PluginAttribute("fileName") String fileName,
                                              @PluginElement("Filter") final Filter filter,
                                              @PluginElement("Layout") Layout<? extends Serializable> layout,
                                              @PluginAttribute("ignoreExceptions") boolean ignoreExceptions) {
        if (name == null) {
            LOGGER.error("no name defined in conf.");
            return null;
        }
        if (layout == null) {
            layout = PatternLayout.createDefaultLayout();
        }
        // 创建文件
        if (!createFile(fileName)) {
            return null;
        }
        return new FileAppender(name, filter, layout, ignoreExceptions, fileName);
    }

    private static boolean createFile(String fileName) {
        Path filePath = Paths.get(fileName);
        try {
            // 每次都重新写文件,不追加
            if (Files.exists(filePath)) {
                Files.delete(filePath);
            }
            Files.createFile(filePath);
        } catch (IOException e) {
            LOGGER.error("create file exception", e);
            return false;
        }
        return true;
    }

    private void writerFile(byte[] log) {
        try {
            Files.write(Paths.get(fileName), log, StandardOpenOption.APPEND);
        } catch (IOException e) {
            LOGGER.error("write file exception", e);
        }
    }
}

参考资料

https://my.oschina.net/kkrgwbj/blog/734530

http://www.cnblogs.com/hafiz/p/6170702.html

http://blog.csdn.net/z69183787/article/details/52403027

http://blog.csdn.net/heyutao007/article/details/72773077

http://blog.csdn.net/u010201484/article/details/51723455

http://m.blog.csdn.net/f59130/article/details/74014729

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值