`
kimmking
  • 浏览: 537024 次
  • 性别: Icon_minigender_1
  • 来自: 中华大丈夫学院
社区版块
存档分类
最新评论

log4j定时轮换文件

    博客分类:
  • java
阅读更多

网友 zhangyang6380006在帖子

http://www.iteye.com/topic/1006088

主题:求一个log文件定时生成功能

 

正好做过,就丢出来献丑了。

 -------------------------------------------------------------------------------

同步异步

Foxswily 写道
不知道有没有考虑用slf4j+logback,log4j的作者已经转到把精力完全放倒这上边了,据说性能有提升。

另外log4j是异步输出,服务停止的瞬间不保证能输出所有的log,如果是精确度高的业务也许不合适


http://www.iteye.com/topic/900845
log4j内置的三种 输出方式

flush=true 直接输出到文件,同步不缓存
bufferedIO 按一定字节大小缓存,同步缓存
AsynFileAppender  按一定的条数缓存,异步输出

  -------------------------------------------------------------------------------

仓库与自定义配置

 

说到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
  class="xxx.log.TimeRollingFileAppender"
  name="ROLLING_FILE">
  <param name="MaxBackupIndex" value="1024" />
  <param name="Encoding" value="UTF-8" />
  <param name="File" value="esb.log" />
  <!--
   <param name="BufferSize" value="8192" />
   <param name="BufferedIO" value="true" />
  -->
  <param name="ImmediateFlush" value="true" />
  <param name="RollTime" value="60" />
  <param name="MaxFileSize" value="100MB" />

   ......

 

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();
			}
		}
	}
}

 

 

 

分享到:
评论
28 楼 kimmking 2011-04-26  
mercyblitz 写道
kimmking 写道
你的方式考虑过,写了半分钟数据,然后没写,不会rollover,
但是我的需求是不行的。

rollover后的文件,我有一个进程处理入库。
这个进程是与生成log的esb进程独立的。
我的需求里,入库的数据要求延迟不能太大。
就是说:esb里来了一条数据,我必须让它在2分钟内在governor的控制台上可以看到。

ps:其实可以esb的log直接入库,但是考虑入库的效率和esb的稳定性,这两步分离了。






是的,你的实现需要比较精确的写日志。我的方法是被动式,还是有问题的,呵呵。

JDK7正式发布就好了,文件大小限制可以通过File Modification Notification事件来回调,Timer只管理定时了,这样代码更加好维护。又做定时和大小还是比较麻烦的,尤其是多线程。

File Modification Notification的话,
可以直接把这部分用 native的方式来做。

ps: dotnet一直都支持 filewatch。
27 楼 mercyblitz 2011-04-26  
kimmking 写道
你的方式考虑过,写了半分钟数据,然后没写,不会rollover,
但是我的需求是不行的。

rollover后的文件,我有一个进程处理入库。
这个进程是与生成log的esb进程独立的。
我的需求里,入库的数据要求延迟不能太大。
就是说:esb里来了一条数据,我必须让它在2分钟内在governor的控制台上可以看到。

ps:其实可以esb的log直接入库,但是考虑入库的效率和esb的稳定性,这两步分离了。






是的,你的实现需要比较精确的写日志。我的方法是被动式,还是有问题的,呵呵。

JDK7正式发布就好了,文件大小限制可以通过File Modification Notification事件来回调,Timer只管理定时了,这样代码更加好维护。又做定时和大小还是比较麻烦的,尤其是多线程。
26 楼 kimmking 2011-04-26  
你的方式考虑过,写了半分钟数据,然后没写,不会rollover,
但是我的需求是不行的。

rollover后的文件,我有一个进程处理入库。
这个进程是与生成log的esb进程独立的。
我的需求里,入库的数据要求延迟不能太大。
就是说:esb里来了一条数据,我必须让它在2分钟内在governor的控制台上可以看到。

ps:其实可以esb的log直接入库,但是考虑入库的效率和esb的稳定性,这两步分离了。



25 楼 mercyblitz 2011-04-26  
<div class="quote_title">kimmking 写道</div>
<div class="quote_div">
<p class="name">网友 zhangyang6380006在帖子 </p>
<p><a href="/topic/1006088">http://www.iteye.com/topic/1006088</a></p>
<p><a href="/topic/1006088"><span style="color: #006699;">主题:求一个log文件定时生成功能</span></a></p>
<p> </p>
<p>正好做过,就丢出来献丑了。</p>
<p> -------------------------------------------------------------------------------</p>
<p><strong>同步异步</strong></p>
<div class="quote_title">Foxswily 写道</div>
<div class="quote_div">不知道有没有考虑用slf4j+logback,log4j的作者已经转到把精力完全放倒这上边了,据说性能有提升。 <br><br>另外log4j是异步输出,服务停止的瞬间不保证能输出所有的log,如果是精确度高的业务也许不合适</div>
<p><br><a href="/topic/900845">http://www.iteye.com/topic/900845</a> <br>log4j内置的三种 输出方式 <br><br>flush=true 直接输出到文件,同步不缓存 <br>bufferedIO 按一定字节大小缓存,同步缓存 <br>AsynFileAppender  按一定的条数缓存,异步输出</p>
<p>  -------------------------------------------------------------------------------</p>
<p><strong>仓库与自定义配置</strong></p>
<p><strong></strong> </p>
<p>说到log4j,大家最常见的用法就是 配置一个log4j.xml或properties,放在classpath的根目录下。</p>
<p>在里面配置上多个Appender,多个package对应的Logger或是Category,然后在代码里,直接用Class获取logger。</p>
<p> </p>
<p>其实还有两点可以提一提:</p>
<p>1、使用命名logger,而不是class</p>
<pre name="code" class="java">// &lt;logger  name="ASYNC_LOGGER"&gt;
Logger logger = Logger.getLogger("ASYNC_LOGGER");</pre>
<p> </p>
<p>2、使用仓库配置多个不同的log4j配置文件</p>
<p> </p>
<pre name="code" class="java">       LoggerRepository loggerRepository1 =  new Hierarchy(new RootCategory(Level.DEBUG));
String path = new File("<span style="background-color: #ff0000;">log4j_1.xml</span>").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("<span style="background-color: #ff0000;">log4j_2.xml</span>").getAbsolutePath();
new DOMConfigurator().doConfigure(path,loggerRepository2);
Logger log_2 = loggerRepository2.getLogger("TEST_LOGGER_2");</pre>
<p> </p>
<p> </p>
<p> -------------------------------------------------------------------------------</p>
<p><strong>轮换文件</strong></p>
<p> </p>
<p>  log4j可以按大小轮换文件(FileAppender, fileSize), 按天轮换文件 (<span style="font-size: x-small;">DailyRollingFileAppender </span>)</p>
<p>在我的某个应用场景中,使用log4j做数据落地,就是把每条日志数据格式化后,写入本地日志文件。</p>
<p>然后通过一个进程来读取所有轮换后的文件,分析每一条数据,入库(mongodb)。</p>
<p>做了如下的修改</p>
<p>1、除了使用文件大小来做轮换规则外,添加一个rollTime属性,表示需要轮换的时间s。</p>
<p>如果文件一直为0,不轮换,创建文件时记录下时间戳,定时与当前时间比较,超过rollTime,强制轮换。</p>
<p>2、同时修改轮换文件名称规则,默认的是.1,.2...这种形式。修改为.时间戳的形式。</p>
<p>其实还自定义了一个简单的Layout序列化数据。这个不是必须的。</p>
<p> </p>
<p>使用方法,在log4j.xml中,</p>
<p> </p>
<p>&lt;appender<br><span style="background-color: #ff0000;">  class="xxx.log.TimeRollingFileAppender"<br></span>  name="ROLLING_FILE"&gt;<br>  &lt;param name="MaxBackupIndex" value="1024" /&gt;<br>  &lt;param name="Encoding" value="UTF-8" /&gt;<br>  &lt;param name="File" value="esb.log" /&gt;<br>  &lt;!--<br>   &lt;param name="BufferSize" value="8192" /&gt;<br>   &lt;param name="BufferedIO" value="true" /&gt;<br>  --&gt;<br>  &lt;param name="ImmediateFlush" value="true" /&gt;<br>  <span style="background-color: #ff0000;">&lt;param name="RollTime" value="60" /&gt;<br></span>  &lt;param name="MaxFileSize" value="100MB" /&gt;</p>
<p>   ......</p>
<p> </p>
<pre name="code" class="java">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 &gt; 0)
if (new File(fileName).length() &gt; 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 &lt;b&gt;MaxBackupIndex&lt;/b&gt; 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.
*
* &lt;p&gt;
* If &lt;code&gt;MaxBackupIndex&lt;/code&gt; is positive, then files {
* &lt;code&gt;File.1&lt;/code&gt;, ..., &lt;code&gt;File.MaxBackupIndex -1&lt;/code&gt; are
* renamed to {&lt;code&gt;File.2&lt;/code&gt;, ...,
* &lt;code&gt;File.MaxBackupIndex&lt;/code&gt; . Moreover, &lt;code&gt;File&lt;/code&gt; is
* renamed &lt;code&gt;File.1&lt;/code&gt; and closed. A new &lt;code&gt;File&lt;/code&gt; is
* created to receive further log output.
*
* &lt;p&gt;
* If &lt;code&gt;MaxBackupIndex&lt;/code&gt; is equal to zero, then the
* &lt;code&gt;File&lt;/code&gt; 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 &lt;= 0, then there is no file renaming to be done.
// if (maxBackupIndex &gt; 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 &gt;= 1 &amp;&amp; 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 &gt; 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.
*
* &lt;p&gt;
* The &lt;b&gt;MaxBackupIndex&lt;/b&gt; 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 &lt;code&gt;MaxFileSize&lt;/code&gt;.
*/
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.
*
* &lt;p&gt;
* This method is equivalent to {@link #setMaxFileSize} except that it is
* required for differentiating the setter taking a &lt;code&gt;long&lt;/code&gt;
* argument from the setter taking a &lt;code&gt;String&lt;/code&gt; 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.
*
* &lt;p&gt;
* In configuration files, the &lt;b&gt;MaxFileSize&lt;/b&gt; 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 &amp;&amp; qw != null) {
long size = ((CountingQuietWriter) qw).getCount();
if (size &gt;= maxFileSize &amp;&amp; size &gt;= nextRollover) {
rollOver();
}
}
}
}</pre>
<p> </p>
<p> </p>
<p> </p>
</div>
<p> </p>
<p><span style="">kimmking </span>哥你搞复杂了,呵呵!</p>
<p> </p>
<p>扩张一下DailyRollingFileAppender的<span style="white-space: pre;">subAppend:</span></p>
<p> </p>
<p> </p>
<pre name="code" class="java">protected void subAppend(LoggingEvent event) {
    long n = System.currentTimeMillis();
    if (n &gt;= nextCheck) {
      now.setTime(n);
      nextCheck = rc.getNextCheckMillis(now);
      try {
rollOver();
      }
      catch(IOException ioe) {
LogLog.error("rollOver() failed.", ioe);
      }
    }
    super.subAppend(event);
   }</pre>
<p> </p>
<p>每次调用log方法时做了定期检查,不过这个DailyRollingFileAppender只能定位到分钟,不能粒度更小(不过应该可以满足99%的需要)。</p>
<p> </p>
<p>加一个限定文件大小的check就OK了。</p>
24 楼 leeaee 2011-04-26  
kimmking 写道
leeaee 写道
kimmking 写道
leeaee 写道
多进程同时写一个log文件的时候,貌似roller文件的就会出现问题,有没有更好的解决方案呢?

没发现这个问题。
我这里是几百个线程。



是进程,线程是很安全的,但很多个JVM同时写一个log文件,ROLLOVER的时候会出先混乱...

恩,进程肯定不行。
没有相互协调的简单机制。

写多个文件吧。


好吧,谢谢~
23 楼 kimmking 2011-04-26  
leeaee 写道
kimmking 写道
leeaee 写道
多进程同时写一个log文件的时候,貌似roller文件的就会出现问题,有没有更好的解决方案呢?

没发现这个问题。
我这里是几百个线程。



是进程,线程是很安全的,但很多个JVM同时写一个log文件,ROLLOVER的时候会出先混乱...

恩,进程肯定不行。
没有相互协调的简单机制。

写多个文件吧。
22 楼 leeaee 2011-04-26  
kimmking 写道
leeaee 写道
多进程同时写一个log文件的时候,貌似roller文件的就会出现问题,有没有更好的解决方案呢?

没发现这个问题。
我这里是几百个线程。



是进程,线程是很安全的,但很多个JVM同时写一个log文件,ROLLOVER的时候会出先混乱...
21 楼 kimmking 2011-04-26  
leeaee 写道
多进程同时写一个log文件的时候,貌似roller文件的就会出现问题,有没有更好的解决方案呢?

没发现这个问题。
我这里是几百个线程。
20 楼 leeaee 2011-04-26  
多进程同时写一个log文件的时候,貌似roller文件的就会出现问题,有没有更好的解决方案呢?
19 楼 leeaee 2011-04-20  
kimmking 写道
leeaee 写道
貌似有个小小的BUG:

构造函数TimeRollingFileAppender()里面,第一次运行的时候的 rollTime 始终是定义的值 60,以后才会读去配置的值...
setRollTime() 在构造函数后运行造成的?

如果这里修改了,就完美了。

log4j的配置文件加载机制是,
调用构造函数,
然后读取xml中的key-value,set到appender的property中去。

构造函数里的那个只是检查的时间,不是rollover的时间。

另外,注释掉的那一段timer的代码,就是解决你说的这个问题的,
根据set的rollTime,重设检查时间,后来发现没必要。


嗯,谢谢~了解的,本来我想的是可以重载下activateOptions这个方法...
18 楼 kimmking 2011-04-20  
leeaee 写道
貌似有个小小的BUG:

构造函数TimeRollingFileAppender()里面,第一次运行的时候的 rollTime 始终是定义的值 60,以后才会读去配置的值...
setRollTime() 在构造函数后运行造成的?

如果这里修改了,就完美了。

log4j的配置文件加载机制是,
调用构造函数,
然后读取xml中的key-value,set到appender的property中去。

构造函数里的那个只是检查的时间,不是rollover的时间。

另外,注释掉的那一段timer的代码,就是解决你说的这个问题的,
根据set的rollTime,重设检查时间,后来发现没必要。
17 楼 leeaee 2011-04-20  
貌似有个小小的BUG:

构造函数TimeRollingFileAppender()里面,第一次运行的时候的 rollTime 始终是定义的值 60,以后才会读去配置的值...
setRollTime() 在构造函数后运行造成的?

如果这里修改了,就完美了。
16 楼 kimmking 2011-04-19  
leeaee 写道
貌似这段代码,运行的时候 maxBackupIndex 设置没有作用了... 楼主能说明下么?

被我注释掉了。~
15 楼 leeaee 2011-04-19  
貌似这段代码,运行的时候 maxBackupIndex 设置没有作用了... 楼主能说明下么?
14 楼 cobb.chan 2011-04-19  
最近总是迷惑日志记录方式,今天学习啦,感谢LZ...
13 楼 Technoboy 2011-04-19  
项目中也用过这个!
顶一个了
12 楼 kimmking 2011-04-19  
Foxswily 写道
不知道有没有考虑用slf4j+logback,log4j的作者已经转到把精力完全放倒这上边了,据说性能有提升。

另外log4j是异步输出,服务停止的瞬间不保证能输出所有的log,如果是精确度高的业务也许不合适

http://www.iteye.com/topic/900845

log4j内置的三种 输出方式

flush=true 直接输出到文件,同步不缓存
bufferedIO 按一定字节大小缓存,同步缓存
AsynFileAppender  按一定的条数缓存,异步输出
11 楼 tcray 2011-04-19  
看了标题我就知道是你 哈哈 其实你把自己的名字都留在程序上了 哈哈
10 楼 Foxswily 2011-04-19  
不知道有没有考虑用slf4j+logback,log4j的作者已经转到把精力完全放倒这上边了,据说性能有提升。

另外log4j是异步输出,服务停止的瞬间不保证能输出所有的log,如果是精确度高的业务也许不合适
9 楼 elan1986 2011-04-18  
之前有个项目
按照每一天的操作记录
年---》月---》日---》操作类型+serialNo

相关推荐

Global site tag (gtag.js) - Google Analytics