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

自定义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同样提供了相应的解决方案。 首先,让我们深入理解如何自定义日志文件名。默认情况下,Log4j的日志文件名通常是固定的或者基于时间戳生成...

    log4j生成文件及文件夹

    本文将深入探讨如何利用Log4j生成动态的日志文件名以及动态创建文件夹,帮助开发者更好地管理和分析应用程序的运行状态。 Log4j是一款功能强大的开源日志组件,它允许程序员灵活地控制日志信息的输出级别,如DEBUG...

    log4j添加日志到数据库和文件中

    Log4j是Apache的一个开源项目,它为Java应用程序提供了一个灵活的日志系统。这个系统能够帮助开发者记录程序运行过程中的各种信息,包括错误、警告、调试信息等,这对于软件的维护和故障排查至关重要。Log4j的核心...

    log4j日志输出格式化和日志文件名格式化

    Log4j的核心在于其灵活性,可以通过自定义布局模板来控制日志输出的格式。最常用的布局模板类是PatternLayout,它允许用户通过特定的模式字符串定义输出格式。例如,一个常见的模式是`%d{yyyy-MM-dd HH:mm:ss} %-5p ...

    JAVA-log4j参数

    关于appender,如`log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender`,表示A2是一个每日滚动的日志文件appender,日志文件名是DAOLog,每天生成一个新的文件,并按照'.'yyyy-MM-dd的格式进行日期切分。...

    配置Log4j的详细最好的日志工具

    通过以上介绍,我们了解到Log4j是一款非常强大的日志管理工具,它不仅提供了丰富的配置选项,还允许用户根据实际需求自定义日志级别、输出目的地及格式等。掌握Log4j的配置技巧对于提高软件开发效率和质量有着重要...

    log4j使用实战

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

    log4j.properties详细配置解释与例子

    `log4j.properties`是Apache Log4j库中用于配置日志记录行为的核心配置文件。下面将详细解析`log4j.properties`的配置项及其作用,同时提供实例来加深理解。 ### 1. Logger 日志记录的核心是`Logger`,它是Log4j中...

    mybatis查询入门(log4j控制台sql语句日记输出的)

    【标题】"mybatis查询入门(log4j控制台sql语句日记输出的)"涉及的知识点主要集中在MyBatis框架的基础使用以及如何通过Log4j在控制台输出SQL语句,以便于调试和优化数据库操作。MyBatis是一个轻量级的Java持久层框架...

    log4j.properties配置详解.doc

    此外,Log4j还支持自定义每条日志的输出格式,并且可以定义每条日志信息的级别,从而精细化地控制日志生成过程。特别的是,这些配置都可以通过一个外部配置文件完成,无需改动应用程序的源代码,极大地提高了灵活性...

    log4net使用代码配置,实现动态文件打印

    **log4net 使用代码配置详解...在提供的`Log4NetTest2010`压缩包中,可能包含了一个简单的示例项目,展示了如何在实际应用中使用上述代码配置方法。通过研究这个项目,你可以更深入地理解`log4net`的代码配置工作原理。

    log4j-在控制台打印sql的源码

    4. **Mybatis SQL打印**:当Log4j配置正确后,Mybatis会在执行每个SQL语句时,自动打印出SQL的执行信息,包括动态生成的SQL语句及其参数。 5. **实例演示**:创建一个简单的Mybatis项目,配置Log4j,并编写一个...

    log4配置文件

    Log4j 配置文件 Log4j 是一个功能强大且灵活的日志记录系统,它可以将日志信息输出到控制台、文件、数据库等多种目标。配置文件是 Log4j 的核心组件,用于定义日志记录的级别、输出目标、格式等信息。 配置根 ...

    log4j配置代码

    Log4j还支持自定义日志格式,通过`PatternLayout`可以定制输出格式,例如: ``` log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=%d{ABSOLUTE}...

    log4j格式化符号说明

    本文将详细解析log4j配置中的输出格式化符号,帮助读者更深入地理解和应用log4j。 ### log4j格式化符号详解 #### 1. `%p`: 日志级别 - `%p`表示日志级别,通常会输出DEBUG、INFO、WARN、ERROR、FATAL等不同级别的...

    1.log4j详解

    Log4j还允许用户自定义日志输出的格式。常用的格式化选项包括: - `%p`:日志级别(DEBUG、INFO、WARN、ERROR、FATAL)。 - `%d`:日志时间,默认格式为ISO8601,也可以自定义格式,例如`%d{yyyy-MM-dd HH:mm:ss....

    Log4j扩展的一个按天滚动的appender类,同时支持动态日志

    标题提到的是一个针对`Log4j`的扩展,名为`DayRollingFileAppender`,它是一个按天滚动的日志Appender,同时也支持动态日志生成。这个Appender允许日志文件按照日期进行分割,避免单个日志文件过大导致的管理困难。 ...

    log4j格式 看看哦

    除了上述基本模式外,Log4j还支持扩展模式,允许用户自定义字段的显示方式,如调整字段宽度和对齐方式: 1. **`%20c`**: 表示右对齐的类别名称,总宽度为20个字符,如果类别名称不足20个字符,则右侧填充空格。 2. ...

    slf4j完整日志文件

    SLF4J支持自定义日志输出格式,例如使用PatternLayout在Log4j中配置 `%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n`,输出日期、优先级、类名、行号和消息。 **7. 异常处理** SLF4J允许直接传递异常对象给日志...

    jboss下通过配置log4j.doc

    ### jBoss下通过配置Log4j实现Web应用的日志管理 #### 一、Log4j简介与重要性 Log4j是一款广泛使用的Java日志框架,由Apache软件基金会开发维护。它提供了一种灵活的方式来控制应用程序日志的生成,允许开发者...

Global site tag (gtag.js) - Google Analytics