百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

log4j按小时输出日志,并且限制日志保存的天数

toyiye 2024-05-19 19:35 13 浏览 0 评论

最近做项目的时候,遇到了日志的输出问题。我们想按小时输出日志,同时最多保存7天的日志。log4j本身自带的appender如下:

org.apache.log4j.ConsoleAppender 输出到控制台

org.apache.log4j.FileAppender 输出到文件

org.apache.log4j.DailyRollingFileAppender

org.apache.log4j.RollingFileAppender 文件大小到达指定尺寸的时候产生一个新的文件

按小时输出可以使用DailRollingFileAppender,但是这个类没法限制文件的数量。如果继承该类,该类输出日志的方法rollover是default,无法重写。参考了其他博主的思路,DailRollingFileAppender继承了FileAppender,我们可以自己写一个类,继承FileAppender,代码还是用DailRollingFileAppender的代码,在其中添加限制文件保存天数的方法。

CustomLogAppender 类代码如下:

import org.apache.log4j.FileAppender;

import java.io.File;

import java.io.IOException;

import java.io.InterruptedIOException;

import java.text.SimpleDateFormat;

import java.util.*;

import org.apache.log4j.Layout;

import org.apache.log4j.helpers.LogLog;

import org.apache.log4j.spi.LoggingEvent;

/**

* @author

* @date 2018/10/30 16:41

* 按小时滚动日志,指定保存的时间,删除超出时间的日志

*/

public class CustomLogAppender extends FileAppender {

static final int TOP_OF_TROUBLE = -1;

static final int TOP_OF_MINUTE = 0;

static final int TOP_OF_HOUR = 1;

static final int HALF_DAY = 2;

static final int TOP_OF_DAY = 3;

static final int TOP_OF_WEEK = 4;

static final int TOP_OF_MONTH = 5;

private String datePattern = "'.'yyyy-MM-dd";

private String scheduledFilename;

/** 最多保存天数,默认七天 */

private int maxBackupIndex = 7;

private long nextCheck = System.currentTimeMillis() - 1L;

Date now = new Date();

SimpleDateFormat sdf;

SimpleDateFormat newSdf = new SimpleDateFormat("'.'yyyy-MM-dd");

RollingCalendar rc = new RollingCalendar();

int checkPeriod = -1;

static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");

public CustomLogAppender() {

}

public CustomLogAppender(Layout layout, String filename, String datePattern) throws IOException {

super(layout, filename, true);

this.datePattern = datePattern;

this.activateOptions();

}

public void setDatePattern(String pattern) {

this.datePattern = pattern;

}

public String getDatePattern() {

return this.datePattern;

}

public void activateOptions() {

super.activateOptions();

if (this.datePattern != null && this.fileName != null) {

this.now.setTime(System.currentTimeMillis());

this.sdf = new SimpleDateFormat(this.datePattern);

int type = this.computeCheckPeriod();

this.printPeriodicity(type);

this.rc.setType(type);

File file = new File(this.fileName);

this.scheduledFilename = this.fileName + this.sdf.format(new Date(file.lastModified()));

} else {

LogLog.error("Either File or DatePattern options are not set for appender [" + this.name + "].");

}

}

void printPeriodicity(int type) {

switch(type) {

case 0:

LogLog.debug("Appender [" + this.name + "] to be rolled every minute.");

break;

case 1:

LogLog.debug("Appender [" + this.name + "] to be rolled on top of every hour.");

break;

case 2:

LogLog.debug("Appender [" + this.name + "] to be rolled at midday and midnight.");

break;

case 3:

LogLog.debug("Appender [" + this.name + "] to be rolled at midnight.");

break;

case 4:

LogLog.debug("Appender [" + this.name + "] to be rolled at start of week.");

break;

case 5:

LogLog.debug("Appender [" + this.name + "] to be rolled at start of every month.");

break;

default:

LogLog.warn("Unknown periodicity for appender [" + this.name + "].");

}

}

int computeCheckPeriod() {

RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.getDefault());

Date epoch = new Date(0L);

if (this.datePattern != null) {

for(int i = 0; i <= 5; ++i) {

SimpleDateFormat simpleDateFormat = new SimpleDateFormat(this.datePattern);

simpleDateFormat.setTimeZone(gmtTimeZone);

String r0 = simpleDateFormat.format(epoch);

rollingCalendar.setType(i);

Date next = new Date(rollingCalendar.getNextCheckMillis(epoch));

String r1 = simpleDateFormat.format(next);

if (r0 != null && r1 != null && !r0.equals(r1)) {

return i;

}

}

}

return -1;

}

void rollOver() throws IOException {

if (this.datePattern == null) {

this.errorHandler.error("Missing DatePattern option in rollOver().");

} else {

String datedFilename = this.fileName + this.sdf.format(this.now);

if (!this.scheduledFilename.equals(datedFilename)) {

this.closeFile();

File target = new File(this.scheduledFilename);

if (target.exists()) {

target.delete();

}

File file = new File(this.fileName);

boolean result = file.renameTo(target);

if (result) {

LogLog.debug(this.fileName + " -> " + this.scheduledFilename);

} else {

LogLog.error("Failed to rename [" + this.fileName + "] to [" + this.scheduledFilename + "].");

}

// 删除过期文件

if (maxBackupIndex > 0) {

File folder = new File(file.getParent());

List<String> maxBackupIndexDates = getMaxBackupIndexDates();

for (File ff : folder.listFiles()) {

// 遍历目录,将日期不在备份范围内的日志删掉

if (ff.getName().startsWith(file.getName()) && !ff.getName().equals(file.getName())) {

// 获取文件名带的日期时间戳

String marked = ff.getName().substring( file.getName().length());

String markedDate = marked.substring(0,marked.lastIndexOf("-"));

if (!maxBackupIndexDates.contains(markedDate)) {

result = ff.delete();

}

if (result) {

LogLog.debug(ff.getName() + " -> deleted ");

} else {

LogLog.error("Failed to deleted old DayRollingFileAppender file :" + ff.getName());

}

}

}

}

try {

this.setFile(this.fileName, true, this.bufferedIO, this.bufferSize);

} catch (IOException var6) {

this.errorHandler.error("setFile(" + this.fileName + ", true) call failed.");

}

this.scheduledFilename = datedFilename;

}

}

}

/**

* 根据maxBackupIndex配置的保存天数,获取要保留log文件的日期范围集合

* @return list<'fileName+yyyy-MM-dd'>

*/

List<String> getMaxBackupIndexDates() {

List<String> result = new ArrayList<String>();

if (maxBackupIndex > 0) {

for (int i = 0; i < maxBackupIndex; i++) {

Calendar calendar = Calendar.getInstance();

calendar.setTime(new Date(System.currentTimeMillis()));

calendar.set(Calendar.HOUR_OF_DAY, 0);

calendar.set(Calendar.MINUTE, 0);

calendar.set(Calendar.SECOND, 0);

calendar.set(Calendar.MILLISECOND, 0);

// 注意MILLISECOND,毫秒也要置0...否则错了也找不出来的

calendar.add(Calendar.DATE, -i);

result.add(newSdf.format(calendar.getTime()));

}

}

return result;

}

protected void subAppend(LoggingEvent event) {

long n = System.currentTimeMillis();

if (n >= this.nextCheck) {

this.now.setTime(n);

this.nextCheck = this.rc.getNextCheckMillis(this.now);

try {

this.rollOver();

} catch (IOException var5) {

if (var5 instanceof InterruptedIOException) {

Thread.currentThread().interrupt();

}

LogLog.error("rollOver() failed.", var5);

}

}

super.subAppend(event);

}

public int getMaxBackupIndex() {

return maxBackupIndex;

}

public void setMaxBackupIndex(int maxBackupIndex) {

this.maxBackupIndex = maxBackupIndex;

}

}

//这个类是org.apache.log4j里的私有类,外类无法引用,所以我在这里完全copy了出来

class RollingCalendar extends GregorianCalendar {

//private static final long serialVersionUID = -3560331770601814177L;

int type = -1;

RollingCalendar() {

}

RollingCalendar(TimeZone tz, Locale locale) {

super(tz, locale);

}

void setType(int type) {

this.type = type;

}

public long getNextCheckMillis(Date now) {

return this.getNextCheckDate(now).getTime();

}

public Date getNextCheckDate(Date now) {

this.setTime(now);

switch(this.type) {

case 0:

this.set(13, 0);

this.set(14, 0);

this.add(12, 1);

break;

case 1:

this.set(12, 0);

this.set(13, 0);

this.set(14, 0);

this.add(11, 1);

break;

case 2:

this.set(12, 0);

this.set(13, 0);

this.set(14, 0);

int hour = this.get(11);

if (hour < 12) {

this.set(11, 12);

} else {

this.set(11, 0);

this.add(5, 1);

}

break;

case 3:

this.set(11, 0);

this.set(12, 0);

this.set(13, 0);

this.set(14, 0);

this.add(5, 1);

break;

case 4:

this.set(7, this.getFirstDayOfWeek());

this.set(11, 0);

this.set(12, 0);

this.set(13, 0);

this.set(14, 0);

this.add(3, 1);

break;

case 5:

this.set(5, 1);

this.set(11, 0);

this.set(12, 0);

this.set(13, 0);

this.set(14, 0);

this.add(2, 1);

break;

default:

throw new IllegalStateException("Unknown periodicity type.");

}

return this.getTime();

}

}

然后在log4j.properties里使用这个appender。

log4j.rootLogger=INFO,CONSOLE,day

log4j.appender.day=改类所在路径.CustomLogAppender

log4j.appender.day.File=日志输出路径/日志名.log

log4j.appender.day.Threshold=INFO

#日志的后缀名格式,按小时

log4j.appender.day.DatePattern='.'yyyy-MM-dd-HH

#最多保存7天

log4j.appender.day.MaxBackupIndex=7

log4j.appender.day.Append=true

log4j.appender.day.layout=org.apache.log4j.PatternLayout

log4j.appender.day.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH:mm:ss}][%l] %m%n

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码