0

我为单例记录器类创建了以下包装器,以便我可以记录来自任何文件和/或类的异常。我的灵感来自这里: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

4 回答 4

3

您无需在日志记录方面遇到所有这些麻烦。日志处理程序(以及所有替代方案,如 logback、log4j)或像 Commons Logging 或 slf4j 这样的包装框架将为您完成几乎所有这些工作。

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

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

于 2012-06-11T21:55:49.860 回答
2

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

cat /dev/null > file

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

于 2012-06-11T21:56:02.600 回答
2

你见过这个吗?

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

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

cat /dev/null > file.log
于 2012-06-12T14:47:45.647 回答
-1

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

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

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

好的,这就是说 - 我根本不了解任何形状或形式的 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 方法?我不知道这是否会影响已更改的文件……但我认为不会。

此外,您可能需要在您的文件处理程序上设置错误管理器 - 从事物的外观来看,如果记录器无法记录,它会向错误管理器发送一些东西。不过我对此并不熟悉,而且我可能会说胡话。

于 2012-06-11T22:49:26.153 回答