2009-08-12 111 views
13

我试图配置Java Logging API的FileHandler以将我的服务器记录到我主目录中文件夹内的文件,但我不想创建这些目录在它运行的每台机器上。配置Java FileHandler日志记录以创建目录(如果它们不存在)

例如在logging.properties文件我注明:

java.util.logging.FileHandler 
java.util.logging.FileHandler.pattern=%h/app-logs/MyApplication/MyApplication_%u-%g.log 

这将让我收我的主目录(%H)日志MyApplication的,并会使用%u旋转他们(和%g个变量)。

的Log4j支持这个时候我在我的log4j.properties注明:

log4j.appender.rolling.File=${user.home}/app-logs/MyApplication-log4j/MyApplication.log 

它看起来像有反对的日志文件处理器中的错误: Bug 6244047: impossible to specify driectorys to logging FileHandler unless they exist

听起来好像他们不打算修复它或暴露任何属性以解决问题(除了让应用程序解析logging.properties或硬编码所需路径):

它看起来像 java.util.logging.FileHandler不会 期望指定的目录 可能不存在。通常情况下,它必须 无论如何检查这个条件。此外,它还需要检查写入 权限的目录。另一个问题 是如果其中一个检查 没有通过该怎么办。

如果 用户具有适当的权限,则一种可能性是在路径中创建 缺少的目录。另一个 是抛出一个IOException和一个 明确的消息有什么不对。后面的方法看起来更加一致。

回答

8

这似乎是log4j版本1.2.15做到了。

这里是做它

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; 
      } 
    } 
    Writer fw = createWriter(ostream); 
    if(bufferedIO) { 
     fw = new BufferedWriter(fw, bufferSize); 
    } 
    this.setQWForFiles(fw); 
    this.fileName = fileName; 
    this.fileAppend = append; 
    this.bufferedIO = bufferedIO; 
    this.bufferSize = bufferSize; 
    writeHeader(); 
    LogLog.debug("setFile ended"); 
} 

这段代码是从FileAppender代码的片断,RollingFileAppender进行延伸FileAppender。

这里没有检查我们是否有权创建父文件夹,但是如果父文件夹不存在,那么它会尝试创建父文件夹。

EDITED

如果你想要一些额外的functionalily,你总是可以延长RollingFileAppender进行并覆盖setFile()方法。

+3

如果我在log4j框架内但是我使用Java Logging框架,并且没有拦截FileHandler创建调用的钩子(除了首次访问Logger时捕获异常,例如记录器.info(“test”)。 – Dougnukem 2009-08-12 05:24:31

+0

我的意思是你可以编写自己的appender。 – 2009-08-12 05:50:26

+0

用户没有询问Log4J。 – 2017-08-09 12:26:32

5

你可以写这样的东西。

package org.log; 

import java.io.IOException; 
import org.apache.log4j.RollingFileAppender; 

public class MyRollingFileAppender extends RollingFileAppender { 

    @Override 
    public synchronized void setFile(String fileName, boolean append, 
     boolean bufferedIO, int bufferSize) throws IOException { 
     //Your logic goes here 
     super.setFile(fileName, append, bufferedIO, bufferSize); 
    } 

} 

然后在你的配置

log4j.appender.fileAppender=org.log.MyRollingFileAppender 

这完全适用于我。

+0

我得看看我要做什么来创建一个自定义的Logging处理程序在Java Logging框架中,但我敢打赌,它与Log4j框架相似 – Dougnukem 2009-08-12 05:56:56

4

要解决的Java日志框架的限制,以及尚未解决的错误:Bug 6244047: impossible to specify driectorys to logging FileHandler unless they exist

我拿出2层的方法(虽然只有第一种方式将实际工作),都需要你的静态无效的主要()方法来初始化日志系统。

例如

public static void main(String[] args) {  

    initLogging(); 
    ... 
    } 

第一种方法对您希望存在的日志目录进行硬编码,如果它们不存在,则创建它们。

private static void initLogging() { 
    try { 
     //Create logging.properties specified directory for logging in home directory 
     //TODO: If they ever fix this bug (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6244047) in the Java Logging API we wouldn't need this hack 
     File homeLoggingDir = new File (System.getProperty("user.home")+"/webwars-logs/weblings-gameplatform/"); 
     if (!homeLoggingDir.exists()) { 
      homeLoggingDir.mkdirs(); 
      logger.info("Creating missing logging directory: " + homeLoggingDir); 
     } 
    } catch(Exception e) { 
     e.printStackTrace(); 
    } 

    try { 
     logger.info("[GamePlatform] : Starting..."); 
    } catch (Exception exc) { 
     exc.printStackTrace(); 

    } 
} 

第二种方法可以赶上IOException异常并创建例外列出的目录,这种方法的问题是,日志框架已经无法创建文件处理器,以便捕捉和解决错误仍然留下记录系统处于不良状态。

+0

您认为这种方法将会用于所有场景,例如登录Web应用程序,我们需要在记录器初始化之前调用拦截器。 由于我们可以编写我们自己的logAppender,我认为这将会b这是一个更好的选择,它可以解决大部分情况。 – 2009-08-12 06:20:00

+0

我同意,我将在记录框架中执行该操作,并将附加我的答案。 – Dougnukem 2009-08-12 15:28:53

+0

我刚刚尝试通过复制java.util.logging.FileHandler创建自己的CustomFileHandler,这里有一些初始问题。您需要位于java.util.logging。*包中以访问Manager .getStringProperty方法。所以我尝试使用该包创建一个类,但是在运行时加载该类时存在安全异常: 无法加载日志处理程序“java.util.logging.CustomFileHandler” java.lang.SecurityException:禁用的程序包名称:java .util.logging – Dougnukem 2009-08-12 15:51:40

1

作为一种可能的解决方案,我认为有两种方法(查看一些以前的答案)。我可以扩展Java日志处理程序类并编写我自己的自定义处理程序。我也可以复制log4j功能,并将其调整到Java Logging框架。

这里的基本复印的FileHandler和创建CustomFileHandler看到pastebin for full class的例子:

的关键是openFiles散()方法,它试图创建一个FileOutputStream和检查,并创建父目录,如果它不存在(我也有复制包保护日志管理方法,为什么他们甚至让那些包反正保护):

// Private method to open the set of output files, based on the 
// configured instance variables. 
private void openFiles() throws IOException { 
    LogManager manager = LogManager.getLogManager(); 

...

// Create a lock file. This grants us exclusive access 
    // to our set of output files, as long as we are alive. 
    int unique = -1; 
    for (;;) { 
     unique++; 
     if (unique > MAX_LOCKS) { 
      throw new IOException("Couldn't get lock for " + pattern); 
     } 
     // Generate a lock file name from the "unique" int. 
     lockFileName = generate(pattern, 0, unique).toString() + ".lck"; 
     // Now try to lock that filename. 
     // Because some systems (e.g. Solaris) can only do file locks 
     // between processes (and not within a process), we first check 
     // if we ourself already have the file locked. 
     synchronized (locks) { 
      if (locks.get(lockFileName) != null) { 
       // We already own this lock, for a different FileHandler 
       // object. Try again. 
       continue; 
      } 
      FileChannel fc; 
      try { 
       File lockFile = new File(lockFileName); 
       if (lockFile.getParent() != null) { 
        File lockParentDir = new File(lockFile.getParent()); 
        // create the log dir if it does not exist 
        if (!lockParentDir.exists()) { 
         lockParentDir.mkdirs(); 
        } 
       } 

       lockStream = new FileOutputStream(lockFileName); 
       fc = lockStream.getChannel(); 
      } catch (IOException ix) { 
       // We got an IOException while trying to open the file. 
       // Try the next file. 
       continue; 
      } 
      try { 
       FileLock fl = fc.tryLock(); 
       if (fl == null) { 
        // We failed to get the lock. Try next file. 
        continue; 
       } 
       // We got the lock OK. 
      } catch (IOException ix) { 
       // We got an IOException while trying to get the lock. 
       // This normally indicates that locking is not supported 
       // on the target directory. We have to proceed without 
       // getting a lock. Drop through. 
      } 
      // We got the lock. Remember it. 
      locks.put(lockFileName, lockFileName); 
      break; 
     } 
    } 

... }

1

我通常会尽量避免使用静态代码,但要解决这个限制,这里是我的方法,在我的项目上工作。

我将子类java.util.logging.FileHandler与其超级调用实现了所有构造函数。我在该类中放置了一个静态代码块,它在user.home文件夹中为我的应用程序创建文件夹(如果它们不存在)。

在我的日志记录属性文件中,我用我的新类替换了java.util.logging.FileHandler。

相关问题