简体   繁体   English

Java 记录器使用

[英]Java Logger usage

I made a custom logger for my project by using java.util.logging :我使用java.util.logging为我的项目制作了一个自定义记录器:

public class SpotifyLogger {
    private static final Logger LOGGER = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
    public SpotifyLogger(String loggerFilePath) throws IOException {
        Logger myLogger = Logger.getLogger("");
        // suppress console messaging
        Handler[] handlers = myLogger.getHandlers();
        if (handlers[0] instanceof ConsoleHandler) { //exception occurs here
            myLogger.removeHandler(handlers[0]);
        }
        // set level
        LOGGER.setLevel(Level.SEVERE);
        // create a txt handler
        FileHandler textFileHandler = new FileHandler(loggerFilePath);
        SimpleFormatter simpleFormatter = new SimpleFormatter();
        textFileHandler.setFormatter(simpleFormatter);
        LOGGER.addHandler(textFileHandler);
    }
    public void log(String user, Exception e) {
        LOGGER.log(Level.SEVERE, user, e);
    }
}

For the client and the server parts of my program, I create two separate Logger objects:对于程序的客户端和服务器部分,我创建了两个单独的 Logger 对象:

// class member initialized as null, because of exception handling
private SpotifyLogger logger = null;
//...
//in constructor: 
this.logger = new SpotifyLogger(LOGGER_FILE_NAME); // the LOGGER_FILE_NAME is different for the client and the server

When I test my program manually, the loggers seem to work (the two log files contain exceptions that I have caused).当我手动测试我的程序时,记录器似乎可以工作(两个日志文件包含我造成的异常)。 Then, I wrote automatic tests.然后,我编写了自动测试。 For each class that I am testing (a total of 5), I create a separate logger object with a different destination path.对于我正在测试的每个 class(总共 5 个),我创建了一个具有不同目标路径的单独记录器 object。 The tests (for whichever class comes first) work correctly.测试(以先出现的 class 为准)工作正常。 All other tests fail because I get an ArrayIndexOutOfBoundsException , when I initialize the logger for that particular class. The reason is that I am trying to access handlers[0] , when handlers has 0 length.所有其他测试都失败了,因为当我为那个特定的 class 初始化记录器时,我得到了一个ArrayIndexOutOfBoundsException 。原因是我试图访问handlers[0] ,当handlers的长度为 0 时。 From what I understood after searching the web, this is because the logger is using parent handlers.根据我搜索 web 后的理解,这是因为记录器正在使用父处理程序。 I tried this:我试过这个:

public SpotifyLogger(String loggerFilePath) throws IOException {
    Logger myLogger = Logger.getLogger("");
    // suppress console messaging
    myLogger.setUseParentHandlers(false);
    Handler[] handlers = myLogger.getHandlers();
    if (handlers.length > 0) {
        if (handlers[0] instanceof ConsoleHandler) {
            myLogger.removeHandler(handlers[0]);
        }
    }
    //etc
}

I don't get an exception anymore but the logging doesn't work.我不再有异常,但日志记录不起作用。 What am I doing wrong?我究竟做错了什么?

This doesn't make much sense to me这对我来说没有多大意义

Logger myLogger = Logger.getLogger("")

Reference: Oracle java docs参考: Oracle java文档

If you want different Logger s, you need to supply different names for each.如果您想要不同的Logger ,则需要为每个提供不同的名称。 Hence this line of your code (in SpotifyLogger constructor) always returns the same Logger .因此,您的这一行代码(在SpotifyLogger构造函数中)始终返回相同的Logger

Logger myLogger = Logger.getLogger("");

This actually returns the java.util.logging.LogManager.RootLogger which has a single Handler which is an instance of ConsoleLogger .这实际上返回java.util.logging.LogManager.RootLogger ,它有一个Handler ,它是ConsoleLogger的一个实例。 You subsequently remove that Handler in the first invocation of SpotifyLogger constructor, hence in every subsequent invocation, method getHandlers returns an empty array.随后,您在第一次调用SpotifyLogger构造函数时删除了该Handler程序,因此在每次后续调用中,方法getHandlers返回一个空数组。

Since you only ever add Handler s to the global Logger , another FileHandler is added to the global logger every time SpotifyLogger constructor is called.由于您只将Handler添加到全局Logger ,因此每次调用SpotifyLogger构造函数时都会将另一个FileHandler添加到全局记录器。 I have not verified but I believe that a Logger will use the first, appropriate Handler in the array returned by method getHandlers , hence the behavior you are seeing whereby only the first log file is being written to, ie the file that you passed to the first invocation of SpotifyLogger constructor.我尚未验证,但我相信Logger将使用方法getHandlers返回的数组中的第一个适当的Handler程序,因此您看到的行为是仅写入第一个日志文件,即您传递给的文件第一次调用SpotifyLogger构造函数。

Note that you have not provided a reproducible example so I cannot verify any of the above with regard to your context.请注意,您没有提供可重现的示例,因此我无法根据您的上下文验证上述任何内容。 I only tested the code in your question in order to arrive at the above.我只测试了您问题中的代码以达到上述目的。

Consider the following rewrite of class SpotifyLogger – including a main method for testing purposes only.考虑以下对 class SpotifyLogger的重写——包括仅用于测试目的的main方法。

import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class SpotifyLogger {
    private static final String[]  NAMES = {"First", "Second"};
    private static int  count;

    private int  index;

    public SpotifyLogger(String loggerFilePath) throws IOException {
        index = count;
        Logger myLogger = Logger.getLogger(NAMES[count++]);
        myLogger.setUseParentHandlers(false);
        // set level
        myLogger.setLevel(Level.SEVERE);
        // create a txt handler
        FileHandler textFileHandler = new FileHandler(loggerFilePath);
        SimpleFormatter simpleFormatter = new SimpleFormatter();
        textFileHandler.setFormatter(simpleFormatter);
        myLogger.addHandler(textFileHandler);
    }

    public void log(String user, Exception e) {
        Logger myLogger = Logger.getLogger(NAMES[index]);
        myLogger.log(Level.SEVERE, user, e);
    }

    public static void main(String[] args) {
        try {
            SpotifyLogger x = new SpotifyLogger("spotifyx.log");
            SpotifyLogger y = new SpotifyLogger("spotifyy.log");
            x.log("George", new Exception());
            y.log("Martha", new RuntimeException());
        }
        catch (IOException x) {
            x.printStackTrace();
        }
    }
}

Note that you are correct regarding parent Handler s, hence the following line in the above code:请注意,关于父Handler s,您是正确的,因此上面代码中的以下行:

myLogger.setUseParentHandlers(false);

After running the above code, the contents of file spotifyx.log is:运行上述代码后,文件spotifyx.log的内容为:

Feb 12, 2022 2:12:28 PM javalogp.SpotifyLogger log
SEVERE: George
java.lang.Exception
    at javalogp/javalogp.SpotifyLogger.main(SpotifyLogger.java:38)

And the contents of file spotifyy.log is:文件spotifyy.log的内容是:

Feb 12, 2022 2:12:28 PM javalogp.SpotifyLogger log
SEVERE: Martha
java.lang.RuntimeException
    at javalogp/javalogp.SpotifyLogger.main(SpotifyLogger.java:39)

And no log messages are written to the console.并且没有日志消息写入控制台。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM