Log4j生成压缩形式日志
转:http://blog.csdn.net/zhaosen241/article/details/3248331
Log4j提供了强大的日志功能,但是只能生成文本形式的日志文件,对于输出日志很频繁的应用会产生一些资源的浪费,例如我们的一个项目平均每20分钟就会生成一个大约10M的日志文件。为了节约硬盘资源,最近几天修改了一下Log4j,做了一个自己的版本将日志文件做成压缩包。
记录下这几天的工作吧:
1. 下载Log4j 1.2.15源代码,链接是:http://logging.apache.org/log4j/1.2/download.html
下载apache-log4j-1.2.15.tar.gz是带有源代码的包
2. Log4j是用Maven2打包的,在链接http://maven.apache.org/download.html中下载
apache-maven-2.1.0-M1-bin.zip,这里需要注意下,2.0.9中有bug,打包会失败。
下载Maven后需要配置一下环境变量,就不细说了。
3. 下载安装MinGW,用来构建NTEventLogAppender.dll。下载链接:
http://mmtele3.skycn.com/down/MinGWStudioFullSetup-2_05.exe
4. 用Maven打包Log4j工程没问题后就可以开始修改里面的源代码了。在前一篇blog中转载了关于log4j的详细信息,我们主要更改两种方式的log,一种是DailyRollingFileAppender,一种是RollingFileAppender。
DailyRollingFileAppender在往日志文件打log的时候会检测日志文件上次修改的时间,如
果系统当前时间与上次修改时间不是一天,则将日志文件重新命名,在生成一个新的日志文件,例如日志文件是log.log,检测上次修改时间早于当天,则将log.log重命名为log.log.2008-11-7,并将log.log清空来打新的日志,其中2008-11-7是有配置文件指定的。
RollingFileAppender在往日志文件打log的时候会根据配置文件设置的最大文件大小来与当前日志文件做比较,如果比文件大时,则将log文件重命名,规则为:根据最大日志备份个数做备份,例如最大日志备份个数设置为3,则将log.log更名为log.log.1、log.log.2、log.log.3、每次会判断这三个文件是否存在,如果存在,则将后缀最大的那个删掉,往后顺移一个,将log.log放到log.log.1中。
5. 现在需要做的就是将这两种方式的操作做一下修改。
DailyRollingFileAppender在判断需要将log.log重命名为log.log.2008-11-7时,我们将重命名这个操作改成将log.log打到zip包里面即可;同理,RollingFileAppender也是将文件重命名的操作改成打zip包。
6. 实现中主要需要修改两个类中的两个方法,相关代码如下:
DailyRollingFileAppender.java
修改方法rollOver
- void rollOver() throws IOException {
- // Compute filename, but only if datePattern is specified
- if (datePattern == null) {
- errorHandler.error("Missing DatePattern option in rollOver().");
- return;
- }
- String datedFilename = fileName+sdf.format(now);
- // It is too early to roll over because we are still within the
- // bounds of the current interval. Rollover will occur once the
- // next interval is reached.
- if (scheduledFilename.equals(datedFilename)) {
- return;
- }
- // close current file, and rename it to datedFilename
- this.closeFile();
- File target = new File(scheduledFilename + ".zip");
- if (target.exists()) {
- target.delete();
- }
- //log old file
- File file = new File(fileName);
- //creat zip output stream to build zip file
- ZipOutputStream out = null;
- FileInputStream fin = null;
- byte[] buf = new byte[1024];
- //file -> zip
- try{
- fin = new FileInputStream(file);
- out = new ZipOutputStream(new FileOutputStream(scheduledFilename + ".zip"));
- out.putNextEntry(new ZipEntry(file.getPath()));
- LogLog.debug(fileName + " -> " + scheduledFilename + ".zip");
- int len;
- while ((len = fin.read(buf)) > 0) {
- out.write(buf, 0, len);
- }
- out.closeEntry();
- fin.close();
- LogLog.debug(fileName + " -> " + scheduledFilename + ".zip successful!");
- }catch(IOException e) {
- errorHandler.error("add zip file("+scheduledFilename+") failed.");
- }
- finally{
- if (out != null) {
- out.closeEntry();
- out.close();
- }
- if (fin != null)
- fin.close();
- }
- //delete old file
- file.delete();
- try {
- // This will also close the file. This is OK since multiple
- // close operations are safe.
- this.setFile(fileName, true, this.bufferedIO, this.bufferSize);
- }
- catch(IOException e) {
- errorHandler.error("setFile("+fileName+", true) call failed.");
- }
- scheduledFilename = datedFilename;
- }
RollingFileAppender.java
同样是修改rollOver方法:
- public// synchronization not necessary since doAppend is alreasy synched
- 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);
- 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 + ".zip");
- 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 + ".zip");
- if (file.exists()) {
- target = new File(fileName + (i + 1) + ".zip");
- LogLog.debug("Renaming file " + file + " to " + target);
- renameSucceeded = file.renameTo(target);
- }
- }
- if (renameSucceeded) {
- // zip fileName to fileName1.zip
- this.closeFile(); // keep windows happy.
- file = new File(fileName);
- // LogLog.debug("compress file " + file + " to " + target);
- ZipOutputStream out = null;
- FileInputStream fin = null;
- byte[] buf = new byte[8192];
- try {
- //create zip out put stream to build zip file
- fin = new FileInputStream(file);
- out = new ZipOutputStream(new FileOutputStream(fileName
- + 1 + ".zip"));
- out.putNextEntry(new ZipEntry(file.getPath()));
- LogLog.debug(fileName + " -> " + fileName + 1
- + ".zip");
- int len;
- while ((len = fin.read(buf)) > 0) {
- out.write(buf, 0, len);
- }
- out.closeEntry();
- fin.close();
- LogLog.debug(fileName + " -> " + fileName + 1
- + ".zip successful!");
- file.delete();
- } catch (IOException e) {
- errorHandler.error("add zip file(" + fileName + 1
- + ".zip) failed.");
- }finally{
- try {
- if (out != null) {
- out.closeEntry();
- out.close();
- }
- if (fin != null)
- fin.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- errorHandler.error("close out and fin failed.");
- }
- }
- // if file compress 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);
- }
- }
- }
7. 最后,由于打zip包的时候用到了Ant中的zip代码,下载带源代码的Ant包,链接是
http://archive.apache.org/dist/ant/source/apache-ant-1.6.5-src.zip 。将里面zip的类放入log4j工程中,并用refactor将包重命名到org.apache.log4j中。
PS:这样做肯定会影响Log4j对输出日志的性能的影响,需要做进一步的性能方面的测试。