Log4j 的 FileAppender 中的 FileNotFoundException

问题描述 投票:0回答:1

我得到下面的 FileNotFoundException 是完整的错误日志:

java.io.FileNotFoundException: /opt/workspace/**/addUserNoDefaultRole.log (No such file or directory)
at java.base/java.io.FileOutputStream.open0(Native Method)
at java.base/java.io.FileOutputStream.open(FileOutputStream.java:298)
at java.base/java.io.FileOutputStream.<init>(FileOutputStream.java:237)
at java.base/java.io.FileOutputStream.<init>(FileOutputStream.java:158)
at org.apache.log4j.FileAppender.setFile(FileAppender.java:294)
at org.apache.log4j.FileAppender.<init>(FileAppender.java:110)
at com.scene7.api.apiclient.ProcessingNode.getLogger(ProcessingNode.java:217)
at com.scene7.api.apiclient.ProcessingNode.getLogger(ProcessingNode.java:227)
at com.scene7.api.apiclient.ProcessingNode.getLogger(ProcessingNode.java:227)
at com.scene7.api.apiclient.RequestSetNode.process(RequestSetNode.java:51)
at com.scene7.api.apiclient.ContainerNode.processChildren(ContainerNode.java:21)
at com.scene7.api.apiclient.IncludeNode.process(IncludeNode.java:90)
at com.scene7.api.apiclient.ContainerNode.processChildren(ContainerNode.java:21)
at com.scene7.api.apiclient.ContainerNode.process(ContainerNode.java:16)
at com.scene7.api.apiclient.ApiClient.processScript(ApiClient.java:58)
at com.scene7.api.regression.ApiClientCallable.call(ApiClientCallable.java:18)
at com.scene7.api.regression.ApiClientCallable.call(ApiClientCallable.java:7)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)

我调用 getLogger() 的代码如下:

public Logger getLogger() {
    if (this.logger != null) {
        return this.logger;
    } else if (getAttributeValue(OUTPUT_FILE_ATTR_QNAME) != null) {
        try {
            String outputFile = getAttributeValue(OUTPUT_FILE_ATTR_QNAME);
            File file = new File(outputFile);
            outputFile = file.getCanonicalPath();
            this.logger = Logger.getLogger(outputFile);
            this.logger.setAdditivity(false);
            Layout layout = new PatternLayout(ProcessingNode.logPattern);
            FileAppender fileAppender = new FileAppender(layout, outputFile, false);
            fileAppender.setEncoding("UTF-8");
            this.logger.addAppender(fileAppender);
            this.logger.setLevel(Level.INFO);

            return this.logger;
        } catch (Exception e) {
            e.printStackTrace(System.err);
        }
    } else if (this.parent != null) {
        return this.parent.getLogger();
    }

    return null;
}

我的log4j.properties如下:

    log4j.rootLogger=WARN, R
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=${catalina.base}/logs/defaultLog4j.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n

我将使用大小为 10 的线程池执行我的测试用例,这个问题是间歇性发生的,这意味着一些测试用例会通过,而很少有测试用例会通过 Abobe Exception。 我在用

log4j1.1.3

解决方法: 我在 setFile() 方法中检查了 log4j FileAppender.java 源代码,如下所示

    public
  synchronized
  void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
                                                            throws IOException {
    LogLog.debug("setFile called: "+fileName+", "+append);

    // It does not make sense to have immediate flush and bufferedIO.
    if(bufferedIO) {
      setImmediateFlush(false);
    }

    reset();
    FileOutputStream ostream = null;
    try {
          //
          //   attempt to create file
          //
          ostream = new FileOutputStream(fileName, append);
    } catch(FileNotFoundException ex) {
          //
          //   if parent directory does not exist then
          //      attempt to create it and try to create file
          //      see bug 9150
          //
          String parentName = new File(fileName).getParent();
          if (parentName != null) {
             File parentDir = new File(parentName);
             if(!parentDir.exists() && parentDir.mkdirs()) {
                ostream = new FileOutputStream(fileName, append);
             } else {
                throw ex;
             }
          } else {
             throw ex;
          }
    }

导致问题意味着,多个线程可以进入这个方法并导致尝试创建文件,

causing the race condition.

任何形式的帮助都将不胜感激。

java logging log4j regression
1个回答
0
投票

求值时出现竞态条件:

if(!parentDir.exists() && parentDir.mkdirs())

你的代码创造了大量的

FileAppender
s。可能发生的情况是:

  1. A
    FileNotFoundException
    被扔在两个线程中,
  2. 其中一个线程创建父目录并继续成功,
  3. 在另一个线程中
    !parentDir.exists()
    返回
    false
    并重新抛出异常。

备注:堆栈跟踪中的行号与您使用的版本 (1.1.3) 不匹配,但它们与版本 1.2.17 匹配。这个版本已经发布了 10 多年前,而 Log4j 1.x 已经在 8 年前结束了生命周期。考虑升级到 Log4j 2.x.

© www.soinside.com 2019 - 2024. All rights reserved.