免责声明:我很抱歉这个问题太长了。我已经添加了代码,因为我已经探索了这里提出的建议,并在提出我最初的问题后进行了额外的研究。
我正在使用 Java 开发一个开源项目,并希望在我的应用程序中实现日志记录,以便在/如果用户报告应用程序问题时进行错误跟踪和调试。我正在查看标准 Java API 中的 java.util.logging 包。当捕获到异常时,我已经添加了一些日志记录代码。例如,我有
Logger.getLogger(FindCardsPanel.class.getName()).log(Level.SEVERE, "Storage I/O error", ex);
每行代码的唯一区别是类名和消息字符串。
我已经读过使用记录器的正确方法是为每个类名字符串使用一个。这有点道理,因为它在过滤日志消息方面提供了很大的灵活性。
我当前的问题是所有日志消息当前都转到stderr。我需要将它们写入文件。我找到了促进这一点的 FileHandler 类。但是,由于我有几十个类,所以我有几十个记录器名称。我是否需要将 FileHandler 添加到其中的每一个?这似乎需要做很多工作,尤其是当我决定在我的代码库中添加另一个类时。
我知道记录器有某种树状层次结构。这会自动发生吗?如果没有,我如何创建自己的层次结构?无论它是否是自动的,我应该在层次结构中的哪个位置添加我的 FileHandler 以便所有日志记录都转到同一个文件?
编辑:
根据@spdaley 提供的链接,我创建了以下 SSCCE:
记录SSCCE.java:
package loggingsscce;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LoggingSSCCE {
private static String LOG_FILE_NAME = "loggingsscce.log";
public static void main(String[] args) throws IOException {
LoggingSSCCE.initLogger();
LogTest lta = new LogTestA();
lta.doLog();
LogTest ltb = new LogTestB();
ltb.doLog();
}
private static void initLogger() throws IOException {
FileHandler handler = null;
try {
boolean append = true;
handler = new FileHandler(LoggingSSCCE.LOG_FILE_NAME, append);
handler.setFormatter(new SimpleFormatter());
Logger logger = Logger.getLogger("");
logger.setLevel(Level.ALL);
logger.addHandler(handler);
} finally {
handler.close();
}
}
}
日志测试.java:
package loggingsscce;
interface LogTest {
public void doLog();
}
LogTestA.java:
package loggingsscce;
import java.util.logging.Level;
import java.util.logging.Logger;
class LogTestA implements LogTest {
@Override
public void doLog() {
Logger.getLogger(LogTestA.class.getName()).log(Level.INFO, "LogTestA.doLog()");
}
}
LogTestB.java:
package loggingsscce;
import java.util.logging.Level;
import java.util.logging.Logger;
class LogTestB implements LogTest {
@Override
public void doLog() {
Logger.getLogger(LogTestA.class.getName()).log(Level.INFO, "LogTestB.doLog()");
}
}
当我在 NetBeans 中运行它时,输出窗口显示
run:
Sep 09, 2012 5:36:56 PM loggingsscce.LogTestA doLog
INFO: LogTestA.doLog()
Sep 09, 2012 5:36:56 PM loggingsscce.LogTestB doLog
INFO: LogTestB.doLog()
BUILD SUCCESSFUL (total time: 0 seconds)
但“loggingsscce.log”文件是空的。
那么我错过了什么?
另一个编辑:
我在http://onjava.com/pub/a/onjava/2002/06/19/log.html?page=2找到了一个我修改过的例子:
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.LogManager;
import java.util.logging.SimpleFormatter;
public class HelloWorld {
private static Logger theLogger = Logger.getLogger(HelloWorld.class.getName());
public static void main( String[] args ) throws IOException {
Logger rootLogger = Logger.getLogger("");
Handler handler = new FileHandler("hello.log");
handler.setFormatter(new SimpleFormatter());
rootLogger.addHandler(handler);
// The root logger's handlers default to INFO. We have to
// crank them up. We could crank up only some of them
// if we wanted, but we will turn them all up.
Handler[] handlers = Logger.getLogger( "" ).getHandlers();
for ( int index = 0; index < handlers.length; index++ ) {
handlers[index].setLevel( Level.FINE );
}
// We also have to set our logger to log finer-grained
// messages
theLogger.setLevel(Level.FINE);
HelloWorld hello = new HelloWorld("Hello world!");
hello.sayHello();
}
private String theMessage;
public HelloWorld(String message) {
theMessage = message;
}
public void sayHello() {
theLogger.fine("Hello logging!");
System.err.println(theMessage);
}
}
这会从命令行生成以下输出:
lib_lab_ref08@LBP-REF87XVMDP1 /e/devel/src/java/stackoverflow
$ javac HelloWorld.java
lib_lab_ref08@LBP-REF87XVMDP1 /e/devel/src/java/stackoverflow
$ java HelloWorld
Sep 09, 2012 6:13:33 PM HelloWorld sayHello
FINE: Hello logging!
Hello world!
lib_lab_ref08@LBP-REF87XVMDP1 /e/devel/src/java/stackoverflow
$ cat hello.log
Sep 09, 2012 6:13:33 PM HelloWorld sayHello
FINE: Hello logging!
lib_lab_ref08@LBP-REF87XVMDP1 /e/devel/src/java/stackoverflow
$
所以这个单类示例工作得很好。当我在以前的代码中在多个文件中有多个类时有什么区别?
对 LoggingSSCCE 类的修改:
我添加了一个静态字段:
private static FileHandler HANDLER = null;
并改变了initLogger()
方法:
private static void initLogger() throws IOException {
LoggingSSCCE.HANDLER = new FileHandler(LoggingSSCCE.LOG_FILE_NAME);
LoggingSSCCE.HANDLER.setFormatter(new SimpleFormatter());
Logger logger = Logger.getLogger("");
logger.setLevel(Level.ALL);
logger.addHandler(LoggingSSCCE.HANDLER);
}
这适用于“loggingsscce.log”的以下内容:
Sep 09, 2012 6:50:16 PM loggingsscce.LogTestA doLog
INFO: LogTestA.doLog()
Sep 09, 2012 6:50:16 PM loggingsscce.LogTestB doLog
INFO: LogTestB.doLog()
我仍然无法在我更复杂的 Swing 项目中完成这一切。我怀疑我的 FileHandler 可能被垃圾收集器关闭了?