锁定老帖子 主题:log4j定时轮换文件
精华帖 (0) :: 良好帖 (13) :: 新手帖 (8) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-04-18
最后修改:2011-04-19
网友 zhangyang6380006在帖子 http://www.iteye.com/topic/1006088
正好做过,就丢出来献丑了。 ------------------------------------------------------------------------------- 同步异步 Foxswily 写道
不知道有没有考虑用slf4j+logback,log4j的作者已经转到把精力完全放倒这上边了,据说性能有提升。
另外log4j是异步输出,服务停止的瞬间不保证能输出所有的log,如果是精确度高的业务也许不合适
------------------------------------------------------------------------------- 仓库与自定义配置
说到log4j,大家最常见的用法就是 配置一个log4j.xml或properties,放在classpath的根目录下。 在里面配置上多个Appender,多个package对应的Logger或是Category,然后在代码里,直接用Class获取logger。
其实还有两点可以提一提: 1、使用命名logger,而不是class // <logger name="ASYNC_LOGGER"> Logger logger = Logger.getLogger("ASYNC_LOGGER");
2、使用仓库配置多个不同的log4j配置文件
LoggerRepository loggerRepository1 = new Hierarchy(new RootCategory(Level.DEBUG)); String path = new File("log4j_1.xml").getAbsolutePath(); new DOMConfigurator().doConfigure(path,loggerRepository1); Logger log_1 = loggerRepository1.getLogger("TEST_LOGGER_1"); LoggerRepository loggerRepository2 = new Hierarchy(new RootCategory(Level.DEBUG)); path = new File("log4j_2.xml").getAbsolutePath(); new DOMConfigurator().doConfigure(path,loggerRepository2); Logger log_2 = loggerRepository2.getLogger("TEST_LOGGER_2");
------------------------------------------------------------------------------- 轮换文件
log4j可以按大小轮换文件(FileAppender, fileSize), 按天轮换文件 (DailyRollingFileAppender ) 在我的某个应用场景中,使用log4j做数据落地,就是把每条日志数据格式化后,写入本地日志文件。 然后通过一个进程来读取所有轮换后的文件,分析每一条数据,入库(mongodb)。 做了如下的修改 1、除了使用文件大小来做轮换规则外,添加一个rollTime属性,表示需要轮换的时间s。 如果文件一直为0,不轮换,创建文件时记录下时间戳,定时与当前时间比较,超过rollTime,强制轮换。 2、同时修改轮换文件名称规则,默认的是.1,.2...这种形式。修改为.时间戳的形式。 其实还自定义了一个简单的Layout序列化数据。这个不是必须的。
使用方法,在log4j.xml中,
<appender ......
import java.io.File; import java.io.IOException; import java.io.InterruptedIOException; import java.io.Writer; import java.util.Timer; import java.util.TimerTask; import org.apache.log4j.FileAppender; import org.apache.log4j.helpers.CountingQuietWriter; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.helpers.OptionConverter; import org.apache.log4j.spi.LoggingEvent; /** * TODO 根据时间和大小轮换文件 * * @author kimmking (mailto:qinjw@primeton.com) */ public class TimeRollingFileAppender extends FileAppender { /** * The default maximum file size is 10MB. */ protected long maxFileSize = 10 * 1024 * 1024; /** * There is one backup file by default. */ protected int maxBackupIndex = 1; private long nextRollover = 0; protected int rollTime = 60; // seconds long fileTimeStamp = 0; Timer timer = null; private TimerTask getTask() { return new TimerTask() { @Override public void run() { // 时间戳 long result = System.currentTimeMillis() - fileTimeStamp - getRollTime() * 1000; if (result > 0) if (new File(fileName).length() > 0) rollOver(); } }; } /** * The default constructor simply calls its * {@link FileAppender#FileAppender parents constructor}. */ public TimeRollingFileAppender() { super(); timer = new Timer("TimeRollingFileAppender", true); long period = rollTime * 1000; TimerTask task = getTask(); timer.schedule(task, period, 1l); // 从一个轮换时间间隔以后,每秒检查一次 } /** * Returns the value of the <b>MaxBackupIndex</b> option. */ public int getMaxBackupIndex() { return maxBackupIndex; } /** * Get the maximum size that the output file is allowed to reach before * being rolled over to backup files. * * @since 1.1 */ public long getMaximumFileSize() { return maxFileSize; } /** * Implements the usual roll over behaviour. * * <p> * If <code>MaxBackupIndex</code> is positive, then files { * <code>File.1</code>, ..., <code>File.MaxBackupIndex -1</code> are * renamed to {<code>File.2</code>, ..., * <code>File.MaxBackupIndex</code> . Moreover, <code>File</code> is * renamed <code>File.1</code> and closed. A new <code>File</code> is * created to receive further log output. * * <p> * If <code>MaxBackupIndex</code> is equal to zero, then the * <code>File</code> is truncated with no backup files created. */ public// synchronization not necessary since doAppend is alreasy synched synchronized void rollOver() { File target; File file; 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); long timestamp = System.currentTimeMillis(); boolean renameSucceeded = true; // If maxBackups <= 0, then there is no file renaming to be done. // if (maxBackupIndex > 0) { // // Delete the oldest file, to keep Windows happy. // file = new File(fileName + '.' + maxBackupIndex); // if (file.exists()) // renameSucceeded = file.delete(); // // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, // // 2} // for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) { // file = new File(fileName + "." + i); // if (file.exists()) { // target = new File(fileName + '.' + (i + 1)); // LogLog.debug("Renaming file " + file + " to " + target); // renameSucceeded = file.renameTo(target); // } // } // // if (renameSucceeded) { // Rename fileName to fileName.1 target = new File(fileName + "." + timestamp); this.closeFile(); // keep windows happy. file = new File(fileName); LogLog.debug("Renaming file " + file + " to " + target); renameSucceeded = file.renameTo(target); // // if file rename failed, reopen file with append = true // 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 all renames were successful, then // if (renameSucceeded) { try { // This will also close the file. This is OK since multiple // close operations are safe. 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); } } } public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize) throws IOException { File file = new File(fileName).getParentFile(); if (!file.exists()) file.mkdirs(); super.setFile(fileName, append, this.bufferedIO, this.bufferSize); if (append) { File f = new File(fileName); ((CountingQuietWriter) qw).setCount(f.length()); } fileTimeStamp = System.currentTimeMillis(); } public void setRollTime(int rollTime) { if (this.rollTime == rollTime) return; this.rollTime = rollTime; // if (this.timer != null) { // this.timer.cancel(); // } // this.timer = new Timer("TimeRollingFileAppender", true); // // if (rollTime > 0) { // long period = rollTime * 1000; // this.timer.schedule(getTask(), period, period); // } } public final int getRollTime() { return this.rollTime; } /** * Set the maximum number of backup files to keep around. * * <p> * The <b>MaxBackupIndex</b> option determines how many backup files are * kept before the oldest is erased. This option takes a positive integer * value. If set to zero, then there will be no backup files and the log * file will be truncated when it reaches <code>MaxFileSize</code>. */ public void setMaxBackupIndex(int maxBackups) { this.maxBackupIndex = maxBackups; } /** * Set the maximum size that the output file is allowed to reach before * being rolled over to backup files. * * <p> * This method is equivalent to {@link #setMaxFileSize} except that it is * required for differentiating the setter taking a <code>long</code> * argument from the setter taking a <code>String</code> argument by the * JavaBeans {@link java.beans.Introspector Introspector}. * * @see #setMaxFileSize(String) */ public void setMaximumFileSize(long maxFileSize) { this.maxFileSize = maxFileSize; } /** * Set the maximum size that the output file is allowed to reach before * being rolled over to backup files. * * <p> * In configuration files, the <b>MaxFileSize</b> option takes an long * integer in the range 0 - 2^63. You can specify the value with the * suffixes "KB", "MB" or "GB" so that the integer is interpreted being * expressed respectively in kilobytes, megabytes or gigabytes. For example, * the value "10KB" will be interpreted as 10240. */ public void setMaxFileSize(String value) { maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1); } protected void setQWForFiles(Writer writer) { this.qw = new CountingQuietWriter(writer, errorHandler); } /** * This method differentiates RollingFileAppender from its super class. * * @since 0.9.0 */ protected void subAppend(LoggingEvent event) { super.subAppend(event); if (fileName != null && qw != null) { long size = ((CountingQuietWriter) qw).getCount(); if (size >= maxFileSize && size >= nextRollover) { rollOver(); } } } }
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-04-18
很有用哦,借用学习了
|
|
返回顶楼 | |
发表时间:2011-04-18
不错,有机会也用一下
|
|
返回顶楼 | |
发表时间:2011-04-18
引用 log4j可以按大小轮换文件(FileAppender, fileSize), 按天轮换文件 (DailyRollingFileAppender )
在我的某个应用场景中,使用log4j做数据落地,就是把每条日志数据格式化后,写入本地日志文件。 然后通过一个进程来读取所有轮换后的文件,分析每一条数据,入库(mongodb)。 做了如下的修改 1、除了使用文件大小来做轮换规则外,添加一个rollTime属性,表示需要轮换的时间s。 如果文件一直为0,不轮换,创建文件时记录下时间戳,定时与当前时间比较,超过rollTime,强制轮换。 2、同时修改轮换文件名称规则,默认的是.1,.2...这种形式。修改为.时间戳的形式。 其实还自定义了一个简单的Layout序列化数据。这个不是必须的。 log4j本来就支持这种行为,不知道为什么还要写代码? 而且这种错误日志还需要入库吗?除非是业务相关的日记。 |
|
返回顶楼 | |
发表时间:2011-04-18
最后修改:2011-04-18
1 this.closeFile(); // keep windows happy.后面注释是log4j作者写的吗,真有闲情逸致啊 ![]() 2 overwrite原先的FileAppender,是很好的实践,看了下代码,其他没有什么问题 |
|
返回顶楼 | |
发表时间:2011-04-18
kakaluyi 写道 1 this.closeFile(); // keep windows happy.后面注释是log4j作者写的吗,真有闲情逸致啊 ![]() 2 overwrite原先的FileAppender,是很好的实践,看了下代码,其他没有什么问题 我现在的项目用着呢。 我机器上测试每秒写8000笔 3.5k大小日志没什么问题。 |
|
返回顶楼 | |
发表时间:2011-04-18
ctoeye 写道 引用 log4j可以按大小轮换文件(FileAppender, fileSize), 按天轮换文件 (DailyRollingFileAppender )
在我的某个应用场景中,使用log4j做数据落地,就是把每条日志数据格式化后,写入本地日志文件。 然后通过一个进程来读取所有轮换后的文件,分析每一条数据,入库(mongodb)。 做了如下的修改 1、除了使用文件大小来做轮换规则外,添加一个rollTime属性,表示需要轮换的时间s。 如果文件一直为0,不轮换,创建文件时记录下时间戳,定时与当前时间比较,超过rollTime,强制轮换。 2、同时修改轮换文件名称规则,默认的是.1,.2...这种形式。修改为.时间戳的形式。 其实还自定义了一个简单的Layout序列化数据。这个不是必须的。 log4j本来就支持这种行为,不知道为什么还要写代码? 而且这种错误日志还需要入库吗?除非是业务相关的日记。 默认实现不支持的。 |
|
返回顶楼 | |
发表时间:2011-04-18
我和楼主有相同的需求,正准备自己写一个的~楼主可以把轮询的时间可配,1s 毕竟不能慢足大家的需求的,明天来帮楼主也再测试下~
|
|
返回顶楼 | |
发表时间:2011-04-18
之前有个项目
按照每一天的操作记录 年---》月---》日---》操作类型+serialNo |
|
返回顶楼 | |
发表时间:2011-04-19
不知道有没有考虑用slf4j+logback,log4j的作者已经转到把精力完全放倒这上边了,据说性能有提升。
另外log4j是异步输出,服务停止的瞬间不保证能输出所有的log,如果是精确度高的业务也许不合适 |
|
返回顶楼 | |