自定义log4j日志文件命名规则说明
作者:dream_lixiang 发布时间:2021-11-21 16:55:51
标签:自定义,log4j,日志文件,命名
自定义log4j日志文件命名规则
项目中的日志需要采用一致的命名规范和文件规范,命名规则为:项目模块标识_index_日期时间_日志级别.log,且每个级别日志文件放在单独的文件夹,且每个文件夹下日志的数量不得超过10个,当数量超过限制时,删除相对较旧的日志,保留较新的日志。
但是发现log4j并不能满足此要求,于是
根据log4j的API定义自己的FileAppender
代码如下:
package com.dear.simpler.dbrpc.util.log;
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.RollingFileAppender;
import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;
/**;
*
* @author lixiang
* 自定义log文件的命名规则
*/
public class MyLogFileAppender extends RollingFileAppender {
private long nextRollover = 0;
private static AtomicInteger logIndex = new AtomicInteger(0); //index
public void rollOver() {
File file = null;
if (qw != null) {
long size = ((CountingQuietWriter) qw).getCount();
LogLog.debug("rolling over count=" + size);
// if operation fails, do not roll again until
// maxFileSize more bytes are written
nextRollover = size + maxFileSize;
}
LogLog.debug("maxBackupIndex=" + maxBackupIndex);
if (maxBackupIndex > 0) {
file = new File(getRollingFileName(fileName, logIndex.incrementAndGet()));
if (fileExisted(file)){
file = new File(getRollingFileName(fileName, logIndex.incrementAndGet()));
}
deleteOldFile(file.getParentFile(), maxBackupIndex);
this.closeFile();
}
try {
this.setFile(getRollingFileName(fileName, logIndex.get()), false, bufferedIO, bufferSize);
nextRollover = 0;
} catch (IOException e) {
if (e instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
LogLog.error("setFile(" + fileName + ", false) call failed.", e);
}
}
private String getRollingFileName(String fileName, int index) { //使用正则表达式替代index
Pattern p = Pattern.compile("_\\d+\\_");
Matcher m=p.matcher(fileName);
String str = m.replaceFirst(String.format("_%d_", index));
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); //日期
String dateString = format.format(new Date(System.currentTimeMillis()));
str = str.replaceAll("\\d{14}", dateString);
return str;
}
public synchronized void setFile(String fileName, boolean append, //修改文件名
boolean bufferedIO, int bufferSize) throws IOException {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); //日期
String dateString = format.format(new Date(System.currentTimeMillis()));
String temp = String.format(fileName , dateString); //文件名
super.setFile(temp, append, bufferedIO, bufferSize);
if(append) {
File f = new File(temp);
((CountingQuietWriter)this.qw).setCount(f.length());
}
}
private boolean fileExisted(File file){
boolean res = false;
String[] fts = file.getName().split("_");
File parentFile = file.getParentFile();
for(File f : parentFile.listFiles()){
String[] fns = f.getName().split("_");
if(fns[0].equals(fts[0]) && fns[1].equals(fts[1])){
res = true;
break;
}
}
return res;
}
private void deleteOldFile(File dir , int maxInt){
if(getFileNum(dir) >= maxBackupIndex ){
File[] files = orderByDate(dir);
for (int i = 0; i <= files.length - maxBackupIndex; i++) {
File f = files[i];
f.delete();
}
}
}
private int getFileNum(File file){
return file.list().length;
}
//将文件按日期排序
public File[] orderByDate(File dir) {
File[] fs = dir.listFiles();
Arrays.sort(fs,new Comparator< File>(){
@Override
public int compare(File f1, File f2) {
long diff = f1.lastModified() - f2.lastModified();
if (diff > 0)
return 1;
else if (diff == 0)
return 0;
else
return -1;
}
@Override
public boolean equals(Object obj) {
return true;
}
});
return fs;
}
@Override
protected void subAppend(LoggingEvent event) {
super.subAppend(event);
if (fileName != null && qw != null) {
long size = ((CountingQuietWriter) qw).getCount();
if (size >= maxFileSize && size >= nextRollover) {
rollOver();
}
}
}
}
对应的log4j.properties的配置文件如下
### set log levels ###
log4j.rootLogger = out,E,I
#log4j.logger.com.dear.simpler.dbrpc.util.log.TestUtil=out,D
log4j.appender.D = com.dear.simpler.dbrpc.util.log.MyLogFileAppender
log4j.appender.D.File = ../../logs/db_logs/debug/DB_0_%s_debug.log
log4j.appender.D.Append = true
log4j.appender.D.MaxFileSize=1024MB
log4j.appender.D.MaxBackupIndex=10
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = com.dear.simpler.dbrpc.util.log.ExPatternLayout
log4j.appender.D.layout.ConversionPattern = [%d{yyyy/MM/dd HH:mm:ss,SSS}][%T:%t][%p][%F:%L:%M][%m]%n
log4j.appender.E = com.dear.simpler.dbrpc.util.log.MyLogFileAppender
log4j.appender.E.File = ../../logs/db_logs/error/DB_0_%s_error.log
log4j.appender.E.Append = true
log4j.appender.E.MaxFileSize=10MB
log4j.appender.E.MaxBackupIndex=10
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = com.dear.simpler.dbrpc.util.log.ExPatternLayout
log4j.appender.E.layout.ConversionPattern = [%d{yyyy/MM/dd HH:mm:ss,SSS}][%T:%t][%p][%F:%L:%M][%m]%n
log4j.appender.I = com.dear.simpler.dbrpc.util.log.MyLogFileAppender
log4j.appender.I.File = ../../logs/db_logs/info/DB_0_%s_info.log
log4j.appender.I.Append = true
log4j.appender.I.MaxFileSize=10MB
log4j.appender.I.MaxBackupIndex=10
log4j.appender.I.Threshold = INFO
log4j.appender.I.layout = com.dear.simpler.dbrpc.util.log.ExPatternLayout
log4j.appender.I.layout.ConversionPattern = [%d{yyyy/MM/dd HH:mm:ss,SSS}][%T:%t][%p][%F:%L:%M][%m]%n
输出的日志文件命名如下
log4j自定义生成文件的名称
我们在使用Log4j的RollingFileAppender循环生成文件的时候,生成的文件的名称有点儿恶心,例如,文件名称为app.log,那么生成的文件名依次为app.log.1,app.log.2,....
那么如何去改变生成文件的名称的规则呢?下面是一个简单示例:
log4j.properties
log4j.logger.major= INFO, majorMsg
log4j.additivity.logError = false
log4j.appender.majorMsg=com.zws.log.MyRollingFileAppender
log4j.appender.majorMsg.File=${catalina.home}/logs/itc/majorMsg.log
log4j.appender.majorMsg.layout=org.apache.log4j.PatternLayout
log4j.appender.majorMsg.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss}|%p|%C|%M|%L|%m%n
log4j.appender.majorMsg.MaxFileSize=1KB
log4j.appender.majorMsg.MaxBackupIndex=10
MyRollingFileAppender.java
package com.zws.log;
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import org.apache.log4j.Priority;
import org.apache.log4j.RollingFileAppender;
import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;
/**
*
* @author wensh.zhu
*
*/
public class MyRollingFileAppender extends RollingFileAppender {
private long nextRollover = 0;
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) {
//删除序号最大(最早的文件)的文件
file = new File(genFileName(fileName, maxBackupIndex));
if (file.exists())
renameSucceeded = file.delete();
//所有文件名序号加1
for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) {
file = new File(genFileName(fileName, i));
if (file.exists()) {
target = new File(genFileName(fileName, i + 1));
renameSucceeded = file.renameTo(target);
}
}
if (renameSucceeded) {
target = new File(genFileName(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);
}
}
}
private String genFileName(String name, int index) {
String fileName = "";
if (index > 0) {
String num = index < 10 ? "0" + index : String.valueOf(index);
fileName = name.replace(".log", "") + "_" + num + ".log";
} else {
fileName = name;
}
return fileName;
}
protected void subAppend(LoggingEvent event) {
super.subAppend(event);
if (fileName != null && qw != null) {
long size = ((CountingQuietWriter) qw).getCount();
if (size >= maxFileSize && size >= nextRollover) {
rollOver();
}
}
}
}
以上示例将文件名的生成规则为:如果文件名为app.log,那么后续的文件为app_01.log,app_02.log.
仅为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家
来源:https://blog.csdn.net/dream_lixiang/article/details/55264203


猜你喜欢
- properties和yml的区别这几天刚好看到Spring Boot当中有两种配置文件的方式,但是这两种配置方式有什么区别呢?proper
- 前言:因为项目中显示图片是用Picasso,设置placeholder和error图片的时候发现,本地图片的大小无法满足我的需求,需要先对图
- 下文笔者讲述SpringBoot配置log4j的方法分享,如下所示SpringBoot日志输出springboot框架中默认使用logbac
- 一、技术介绍1.chatgpt-java是一个OpenAI的Java版SDK,支持开箱即用。目前以支持官网全部Api。支持最新版本GPT-3
- 本文实例讲述了C#将指定目录所有文件名转换成小写的方法。分享给大家供大家参考。具体如下:using System;using System.
- 1、使用pom安装依赖<dependency> <groupId>com.alibaba&
- Hadoop环境搭建详见此文章https://www.jb51.net/article/33649.htm。我们已经知道Hadoop能够通过
- Java中的main函数的详细介绍JAVA中的主函数是我们再熟悉不过的了,相信每个学习过JAVA语言的人都能够熟练地写出这个程序的入口函数,
- 问题 @Cacheable注解不支持配置过期时间,所有需要通过配置CacheManneg来配置默认的过期时间和针对每个类或者是方法进行缓存
- 一、dfs(深度优先搜索)1.图的dfs/** * 深度优先搜索 * * @param node * @param set */publi
- PrintStream 介绍PrintStream 是打印输出流,它继承于FilterOutputStream。PrintStream 是用
- Google在Android 4.4版本加入了半透明的界面样式,在Android 5.0的时候推出了Material Design的概念。这
- Vector(向量)是 java.util 包中的一个类,该类实现了类似动态数组的功能。向量和数组相似,都可以保存一组数据(数据列表)。但是
- 本文讲述了Java实现画线、矩形、椭圆、字符串功能的实例代码。分享给大家供大家参考,具体如下:import java.awt.Frame;
- 所谓前人栽树,后人乘凉,在此感谢博主的贡献。 原文:边缘凹凸的卡劵效果先上效果图:我实现的效果和原博主实现的效果是不一样的,我是左右边缘凹凸
- Lambda表达式的心得如题,因为博主也是最近才接触到Lambda表达式的(PS 在这里汗颜一会)。我并不会讲解它的原理,诚然任何一件事物如
- 最近做的一个项目涉及到文件上传与下载。前端上传采用百度webUploader插件。有关该插件的使用方法还在研究中,日后整理再记录。本文主要介
- 一、简介ThreadPool相比Thread来说具备了很多优势,但是ThreadPool却又存在一些使用上的不方便。比如:Task支持线程的
- 定义:定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。类型:行为类模式类图: 
- 本文实例为大家分享了java GUI学生图书管理的具体代码,供大家参考,具体内容如下- mysql数据库建表:1.book表 2.bs借书记