`
lettoo
  • 浏览: 34242 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
博客专栏
58ccff5b-5ca6-387a-9c99-a277f31a9e51
我和Java数据库操作的那...
浏览量:9289
社区版块
存档分类
最新评论

自定义log4j生成的log文件名

阅读更多
    很多时候,log4j的RollingFileAppender配置如下:

log4j.logger.cn.lettoo.Test=INFO, file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.MaxFileSize=100KB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.File=test.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout  
log4j.appender.file.layout.ConversionPattern=[%d{MM/dd/yyyy HH:mm:ss.SSS} %m%n


    RollingFileAppender会自动在一个文件满了之后,生成一个如text.log.1的文件,一直生成到text.log.x(x值可配置log4j.appender.file.MaxBackupIndex=10)为止,再回写text.log。

    当我们有需要在产生一些自定义的log文件名的时候,比如:
引用

test_[process_name]_0_20111031.log
test_[process_name]_1_20111031.log
test_[process_name]_2_20111031.log
......

    要在文件名显示是哪一个进程名,第一个文件为0,后面是1,2,3......,并且要加上日期,再使用RollingFileAppender做简单的配置是无论如何也实现不了了。

    打开RollingFileAppender.java的源码,我看到它主要是用setFile(),subAppend()和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);
      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 + "." + 1);

      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 {
    super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
    if(append) {
      File f = new File(fileName);
      ((CountingQuietWriter) qw).setCount(f.length());
    }
  }


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

    如果我继承这个类,然后在子类里实现它的这三个方法,不就可以实现我要的功能了吗?
代码如下:

public class MWLogFileAppender extends RollingFileAppender {

    private long nextRollover = 0;

    public 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);
            file = new File(getRollingFileName(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);
                file = new File(getRollingFileName(fileName, i));
                if (file.exists()) {
                    //target = new File(fileName + '.' + (i + 1));
                    target = new File(getRollingFileName(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 + "." + 1);
                target = new File(this.getRollingFileName(fileName, 1));

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

    private String getRollingFileName(String fileName, int index) {
        Pattern p = Pattern.compile("_\\d+\\."); 
        Matcher m=p.matcher(fileName);
        
        return m.replaceFirst(String.format("_%d.", index));
    }

    public synchronized void setFile(String fileName, boolean append,
            boolean bufferedIO, int bufferSize) throws IOException {
        String processName = "01";

        SimpleDateFormat format = new SimpleDateFormat("MMddyyyy");
        String dateString = format.format(new Date(System.currentTimeMillis()));

        String processId = String.valueOf(Thread.currentThread().getId());
        String temp = String.format(fileName, processName, dateString,
                processId);
        //System.out.println(temp);
        super.setFile(temp, append, bufferedIO, bufferSize);
    }

    protected void subAppend(LoggingEvent event) {
        super.subAppend(event);
        if (fileName != null && qw != null) {
            long size = ((CountingQuietWriter) qw).getCount();
            if (size >= maxFileSize && size >= nextRollover) {
                rollOver();
            }
        }
    }

}


    在setFile方法里,通过String的替换来实现我要的自定义字符串的功能,当然,这里只是一个示例。
    文件满了之后生成新的文件编号,不再在log后面加数据,而是在文件名体现,我这里加了一个getRollingFileName()来根据正则表达式来替换。

    当然,配置文件可以修改如下了:
log4j.logger.cn.lettoo.Test=INFO, file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.MaxFileSize=100KB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.File=test-%s_%s_0.%s.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout  
log4j.appender.file.layout.ConversionPattern=[%d{MM/dd/yyyy HH:mm:ss.SSS} %m%n


    虽然以上的做法满足了我的要求,但是我感觉也有缺点,主要是:
  • 配置文件必须要按我自定义的格式来写,即log4j.appender.file.File=test-%s_%s_0.%s.log不能搞错了
  • RollingFileAppender的几个方法扩展的都不好,还把原来的代码copy过来修改的。


    目前也没有想到更好的方法,暂时先记下来。
分享到:
评论

相关推荐

    log4j使用实战

    过了时间将原日志文件命名为原文件名后加上log4j.appender.File.DatePattern='.'yyyy-MM-dd-HH对应格式的日期, 注意不能用:和_。 关于DailyRollingFileAppender的使用,参考:...

    POC bomber -资源

    shiro,泛微OA,致远OA,通达OA等易受攻击组件的漏洞检测,支持调用dnslog平台检测无回显的rce(包括log4j2的检测),支持单个目标检测和批量检测,程序采用高并发线程池,支持自定义导入poc/exp,并能够生成漏洞报告 ...

    BugNet问题跟踪器 v1.10源码2012817

    附件文件名的截取 2、Runtime error, "Could not load file or assembly 'log4net," 修复运行时错误,“无法加载文件或程序集”log4net的 3、Open Issue count doesn't match 未解决问题数量不匹配 4、Deleted ...

    C#常用功能类库(20111202最新整理)

    12.SR.ShareFunc.WinFunc.LogFunc 按照指定路径、文件名生成日志信息 13.SR.ShareFunc.WinFunc.MouseMoveControl 给指定控件绑定鼠标移动事件,例如Label绑定后,鼠标点击该Label可进行窗体拖拽 或实现自定义的...

    Java代码混淆工具 Proguard4.10(官方免费下载)

    混淆结束后,处理前与处理后对应关系会记录在obf.map中,文件名可以自定义 参照附件中《obf.map》 注:该文档自动生成 8、《testjava.pro》是我自己的配置文档(一个helloWorld),仅供参考 9、日记《success-log....

    ssh(structs,spring,hibernate)框架中的上传下载

     fileContent字段映射为Spring所提供的BlobByteArrayType类型,BlobByteArrayType是用户自定义的数据类型,它实现了Hibernate 的org.hibernate.usertype.UserType接口。BlobByteArrayType使用从sessionFactory获取...

    Excel导入SQL数据库

    A: 同一用户生成的Excel文件用同一个文件名,文件名可用用户ID号或SessionID号等可确信不重复字符串组成。这样新文件生成时自动覆盖上一文件。 B: 在Global.asa文件中设置Session_onEnd事件激发时,删除这个用户的...

    Ultra PDF 2.26

    4、颜色:支持CIE色彩空间,嵌入ICC Profile,直接生成印刷品质的PDF。 5、加密:支持128 Bits RC4 加密 6、路径:多种方式指定目标PDF文件名,支持PDF合并,支持添加附件。 7、Ultra PDF工具:批量转换,图片...

    asp.net知识库

    关于能自定义格式的、支持多语言的、支持多数据库的代码生成器的想法 发布Oracle存储过程包c#代码生成工具(CodeRobot) New Folder XCodeFactory3.0完全攻略--序 XCodeFactory3.0完全攻略--基本思想 XCodeFactory...

    X-Scan-v3.2

    X-Scan-v3.2 使用说明 一. 系统要求:Windows NT/2000/XP/2003 理论上可运行于Windows NT系列操作... “扫描报告”项 - 扫描结束后生成的报告文件名,保存在LOG目录下。扫描报告目前支持TXT、HTML和XML三种格式。

    84PHP开源框架-PHP

    修复Session模块中影响图像生成的代码错误;调整Vcode模块Base方法,使其返回验证码文本;修复了Wrong模块对AJAX请求识别错误的问题;新增用以缓存数据的Data模块;修复Setting模块中Set方法出错的问题;修复Page...

    MaxDOS 9.1 全能装机版

    4.启动控制台时如不存在备份还原主文件将自动生成,默认存放镜像路径为硬盘最后分区 5.支持设置“自动备份”及“自动还原功能”的独立密码,安装者或装机商可以直接在这里 设置密码限制用户使用此功能,可有效防止用户...

    X-Scan-v3.3-cn

    “扫描报告”项 - 扫描结束后生成的报告文件名,保存在LOG目录下。扫描报告目前支持TXT、HTML和XML三种格式。 “其他设置”项: “跳过没有响应的主机” - 若目标主机不响应ICMP ECHO及TCP SYN报文,X-Scan将跳过...

    winrar3.7 Beta8

    当生成的压缩文件是自解压的并且压缩文件大小超过 4 GB,WinRAR 显示一个警告。 Windows 不能运行应用程序。 of such size. &lt;br&gt; 5. 修正 ISO 处理的代码。 &lt;br&gt; 版本 3.70 beta 2 &lt;br&gt; 1. 压缩...

    landing-page-domotica

    Less等) 添加图像,字体和文件使用public文件夹更改HTML 在模块系统之外添加资产何时使用public文件夹使用全局变量添加引导程序使用自定义主题增加流量添加自定义环境变量在HTML中引用环境变量在Shell中添加临时...

Global site tag (gtag.js) - Google Analytics