Java:单例类的这种正确行为是用来保存基本的JDK日志文件吗?

时间:2012-06-11 21:40:41

标签: java logging error-handling

我为单例记录器类创建了以下包装器,以便我可以记录来自任何文件和/或类的异常。我的灵感来自这里:Logging to one file from multiple java files

我是java的新手,这是我第一次尝试将异常记录到文件中。虽然下面的代码确实有效,但我注意到一些问题,我想询问它们是否是“正常行为”或是否存在变通方法。

(1)创建日志文件并用异常写入日志文件后,如果我编辑日志文件(例如删除一些文本行),那么从那一刻开始就不再写入日志文件。在再次写入日志文件之前,Web服务器需要重新启动与Web应用程序关联的域。这是正常的吗?理想情况下,我只想在日志文件中保留相关错误,并删除不相关的错误,而无需在Web服务器中重新启动Web应用程序的域。

(2)如果我删除了日志文件,那么稍后在java程序中发生异常,则不会再次创建日志文件,并且异常将丢失。同样,Web服务器需要在创建新日志文件之前重新启动与Web应用程序关联的域。这是正常的,还是通过编辑以下代码以某种方式解决方法?理想情况下,我希望能够随时删除日志文件并让应用程序创建一个新文件。

再次,我是新来的,所以请随意指出上述意图是糟糕的设计等。

------代码遵循------

这是文件:LoggerWrapper.java

import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.logging.Logger;
import java.util.logging.Level;   
import java.util.logging.FileHandler;  
import java.util.logging.SimpleFormatter;

public class LoggerWrapper {
public static final Logger myLogger = Logger.getLogger("Test");
private static LoggerWrapper instance = null;  

 public static LoggerWrapper getInstance() {  
    if(instance == null) {  
        prepareLogger();  
        instance = new LoggerWrapper ();  
    }  
    return instance;  
 }  

private static void prepareLogger() {
try {
   FileHandler myFileHandler = new FileHandler("/path/to/myLogFile.log", true);  
   myFileHandler.setFormatter(new SimpleFormatter());  
   myLogger.addHandler(myFileHandler);  
   myLogger.setUseParentHandlers(false);  
   myLogger.setLevel(Level.ALL);
} catch (Exception e) {
   ...
}
}    
} 

要在不同的文件或类中调用上述代码,请发出以下行(例如):

LoggerWrapper loggerWrapper = LoggerWrapper.getInstance();
...
loggerWrapper.myLogger.log(Level.SEVERE, "some text here"+e.fillInStackTrace());

4 个答案:

答案 0 :(得分:3)

您无需通过日志记录解决所有这些问题。日志处理程序(以及所有备选方案,如logback,log4j)或包含Commons Logging或slf4j的包装器框架将为您完成所有这些工作。

最广泛接受的使用日志记录的方法是使用包装器系统(slf4j非常流行),然后只包含日志类作为每个类的私有静态属性。然后,您可以使用单独的程序执行所有配置,也可以使用配置文件为您设置所有内容。

如果你想用代码设置你的日志记录系统(不是我会这样做的,但是你可以...),你可以在一个你知道会相对较早加载的静态初始化程序中进行。一旦记录系统获得了它的信息,就不需要再次配置它。

答案 1 :(得分:2)

我假设这是在linux上运行的?当您打开文件时,它指向对该文件的引用。当您删除文件时,引用已经消失,但由于您将引用保存在静态变量中,因此您的代码现在持有一个指向任何内容的文件句柄。相反,你应该做类似

的事情
cat /dev/null > file

在不更改文件指向的实际inode的情况下,只会在文件上复制任何内容。

答案 2 :(得分:2)

你见过this吗?

它可能与您的编辑器/操作系统有关。链接问题的海报与log4j有类似的问题。

正如另一个答案所述,清除日志文件不会干扰处理程序:

cat /dev/null > file.log

答案 3 :(得分:-1)

我建议你不要编辑文件!并且不要删除它们!

哈哈哈,那将是一个王牌解决方案,不是吗?

你应该真正使用开源日志记录(我总是喜欢log4j - 大多数IB使用它,或者是slf4j),这是Jonathan建议的 - 它是标准的记录方式,没有人像你一样记录日志这样做。至少,不是我所知道的。

好吧,那说 - 而且我根本不知道linux,无论是任何形状或形式 - 听起来像Rick建议的那样,无论你指向什么,当你编辑/删除文件时都会消失。所以,在伪代码中(因为,我很抱歉 - 正如我所指出的,我使用的是Windows所以无法测试):

public class LoggerWrapper {
    *private* FileHandler myFileHandler;
    *private* static final Logger myLogger = Logger.getLogger("Test");
    private static LoggerWrapper instance = null;  

    /*
      here check if the file you're using has been changed! If so, re-do the file setting
    */
    public void log(Level level, String message){
        //argh you are on your own here. I don't know how to *check* the file being used by the file handler...
        //you know what? you can just do this (but it isn't too clean)
        myLogger.removeFileHandler(myFileHandler);
        myFileHandler = new FileHandler("/path/to/myLogFile.log", true); 
        myLogger.addHandler(myFileHandler);
        myLogger.log(level,message);     
    }  

    private static void prepareLogger() {
        try {
            //don't shadow the myFileHandler by accident!
            myFileHandler = new FileHandler("/path/to/myLogFile.log", true); 

...

当然,每次登录时都会重置文件处理程序。并且您不会使用以下命令登录:

loggerWrapper.myLogger.log(Level.SEVERE, "some text here"+e.fillInStackTrace());

但是

loggerWrapper.log(Level.SEVERE, "some text here"+e.fillInStackTrace());

或者只是使用开源日志(log4j!)并且开心!可能有某种方法来检查文件是否丢失 - 哦!也许检查isLoggable方法?我不知道是否会接收到已更改的文件......但我认为不会这样做。

此外,您可能需要在fileHandler上设置setError - 从事物的外观来看,如果记录器不能,那么,记录,它会向errorManager发送内容。我对此并不熟悉,而且我可能会说乱七八糟。