log4j日志重写ExPatternParser及ExRollingFileAppender类

-根据项目需要,log4j在输出日志时,需要进行定制化的格式,由于log4j本身的格式化不能够满足需求,因此需要重写log4j中的方法,修改格式化的方法。而log4j输出文件时,公司的日志标准中规定,需要同时根据时间和大小进行日志文件的输出,并且日志文件名需要明明为特定的格式,因此同时需要重写log4j中的方法,同时满足输出文件的条件和文件名格式的需求。考虑到公司会有其他项目会同时使用到该功能,因此将重写的方法放到了maven的jar项目中,方便其他项目的引用。在引用该jar工程时,需要在原有的工程中的config.properties文件中添加项目名称,即添加projectName=“项目名称”,后面日志输入和日志文件名都会使用。如不添加,则会显示为默认的名称,即“coms”。本工程主要重写了ExPatternParser类中的方法,用于格式化日志输出的格式,和ExRollingFileAppender中的方法,用于格式化输出日志文件名和日志文件分割的标准。以下将会分别讲解ExPatternParser和ExRollingFileAppender中的大体代码逻辑,如有格式化输出日志和特定日志文件名及分割日志文件需求的伙伴,可以下载本项目,修改其中的方法已满足自己的需求。

重写ExPatternParser中方法

根据项目需要,在日志输出时,需要进行特殊的格式化,因log4j原有的格式化不能满足格式化要求,因此对ExPatternParser类进行了重写,定制化格式化要求,格式化后的输出日志格式如下:[*&^%][2018010216:59:02,763][CRM-DEV1-4][1092][15][coms][com.csc.coms.modules.sys.dao.DictDao.findAllList][DEBUG],翻译后的内容如下:[日志记录起始标识][时间][服务器名称][进程号][线程号][系统名称][模块名称][交易流水号(可选)][日志类型][行为类型(可选)][源系统(可选)][目标系统(可选)][报文类(可选)][异步报文号(可选)]。
_**重写finalizeConverter方法,修改输出日志中的占位符,代码如下:**

/**
     * 重写finalizeConverter,对特定的占位符进行处理,T表示线程ID占位符,f表示服务器名称占位符,P表示进程号占位符
    */
    @Override
    protected void finalizeConverter(char c) {
        if (c == 'T' || c == 'f' || c == 'P') {
          this.addConverter(new ExPatternConverter(this.formattingInfo,c));
        }else {
          super.finalizeConverter(c);
        }
    }

_**重写convert方法,修改其中的逻辑,代码如下:**

/**
    * 重写方法,增加日志信息的输出格式
    * T表示线程号,f表示服务器名称,P表示进程号
*/
@Override
protected String convert(LoggingEvent event) {
    String result = null;
    if(patterns == 'T'){
        result = String.valueOf(Thread.currentThread().getId());
    }else if(patterns == 'f'){
        String name = ManagementFactory.getRuntimeMXBean().getName();
        result = name.split("@")[0];
    }else if(patterns == 'P'){
        String name = ManagementFactory.getRuntimeMXBean().getName();
        result = name.split("@")[1];
    }
    return result;
}

ExPatternParser类中重写的方法不多,主要就涉及到这两个方法,代码中的注释说明的也比较清楚,因为不进行过多的解释。

重写ExRollingFileAppender类中的方法

根据公司日志标准的需要,第一个需求是在日志输出时,需要同时满足按照日志文件大小、时间、日志类别进行日志文件的分割操作。第二个需求是在日志输出文件时,对文件名需要进行定制化命名规则。为了同时满足这两项需求,因此需要重写ExRollingFileAppender类中相应的方法,由于以上两点需求,导致了原本log4j中删除文件的方法也无法使用,因此在重写ExRollingFileAppender时,也修改了log4j原本删除文件的业务逻辑,考虑到日志输出的性能和可能会影响到日志输出的功能,因此将删除日志功能单独启动了一个线程。日志文件名的格式如下:S0001_INFO_jf-vra-app0001_2017090117_001.log,文件格式翻译后的内容如下:系统名日志类型服务器名称时间日志序列号_识别号。下面将对ExRollingFileAppender类中的方法进行大题的解释。

_**重写subAppend方法,该方法是日志文件分割的主要方法,重写的方法代码如下:**

@Override
    protected void subAppend(LoggingEvent event) {
        level = event.level.toString();
        String nowDate = sdf.format(new Date());
        if(StringUtils.isEmpty(projectName)){
            LogLog.warn("从配置文件中未获取到projectName项目名称,设置日志文件名的项目名称默认为coms。请在项目中的config.properties里设置projectName属性。");
            projectName = "coms";
        }
        if(fileName.indexOf(separator) == -1){
            //新启动项目时,修改日志文件的名称
            String fileNames = getFileName(fileName,1);
            this.setFile(fileNames);
            LogLog.debug("项目启动后文件名称修改为:"+fileName);
        }else{
            //更新日志文件的名称中的日期时间,否则在获取日志文件名称时会有问题 
            String fileDate = fileName.substring(0, fileName.lastIndexOf(separator));
            fileDate = fileDate.substring(fileDate.lastIndexOf(separator)+1, fileDate.length());
            LogLog.debug("修改文件名前的文件名称中的时间为:"+fileDate+",获取到的当前时间为"+nowDate);
            if(!nowDate.equals(fileDate)){
                String fileNames = getFileName(fileName,1);
                this.setFile(fileNames);
                LogLog.debug("由于文件名称中的时间不同进行修改,修改后的文件名称为:"+fileName);
            }
        }
        super.subAppend(event);
        if (fileName != null && qw != null) {
            //获取当前日志文件的大小
            long size = ((CountingQuietWriter) qw).getCount();
            //获取判断日志文件的时间差是否满足条件
            boolean flag = diffDate(fileName);
            if ((size >= maxFileSize && size >= nextRollover) || flag) {
                LogLog.debug("日志文件进行分割的条件为,当前文件大小:"+size+",文件日期判断结果为:"+flag);
                rollOver();
            }
        }
    }
  • 重写isAsSevereAsThreshold方法,修改按照日志类型分割文件,代码如下:
 /**
     * 实现不同级别的日志输出到不同的文件中
     */
    @Override  
    public boolean isAsSevereAsThreshold(Priority priority) {    
          //只判断是否相等,而不判断优先级     
        return this.getThreshold().equals(priority);    
    } 
  • 重写rollOver方法,实现分割后的日志重命名及删除文件的逻辑,代码如下:
@Override
    public void rollOver() {
        File target;
        File file;

        if (qw != null) {
            long size = ((CountingQuietWriter) qw).getCount();
            nextRollover = size + maxFileSize;
        }
        LogLog.debug("maxBackupIndex=" + maxBackupIndex);
        boolean renameSucceeded = true;
        if (maxBackupIndex > 0) {
            //计算当前日志文件夹下的文件数量是否超过阈值,超过则进行删除
            countFile(fileName,maxBackupIndex);
            // 所有文件名序号加1  
            for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) {  
                file = new File(getFileName(fileName,i));  
                if (file.exists()) {  
                    target = new File(getFileName(fileName,i+1));  
                    renameSucceeded = file.renameTo(target);  
                }  
            } 
            if (renameSucceeded) {
                target = new File(getFileName(fileName,1));
                this.closeFile(); 
                file = new File(fileName);
                renameSucceeded = file.renameTo(target);
                if (!renameSucceeded) {
                    try {
                        this.setFile(fileName, true, bufferedIO, bufferSize);
                    } catch (IOException e) {
                        if (e instanceof InterruptedIOException) {
                            Thread.currentThread().interrupt();
                        }
                        LogLog.error("setFile(" + fileName + ", true) call failed.", e);
                    }
                }
            }
        }
        if (renameSucceeded) {
            try {
                this.setFile(fileName, false, bufferedIO, bufferSize);
                nextRollover = 0;
            } catch (IOException e) {
                if (e instanceof InterruptedIOException) {
                    Thread.currentThread().interrupt();
                }
                LogLog.error("setFile(" + fileName + ", false) call failed.", e);
            }
        }
 }
  • 以上就是对log4j进行定制化重写的大体解释,如需要完整的代码工程,可进行下面的连接进行下载,连接地址为:https://download.csdn.net/download/songyou05/10360993。针对本工程中的代码有更好的建议,可见qq(734108708)进行交流。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值