如何在使用Java日志API时禁用默认控制台处理程序?

98

你好,我正在尝试在我的应用程序中实现Java日志记录。我想使用两个处理器:文件处理器和自定义的控制台处理器。我的两个处理器都能正常工作,我的日志被发送到文件和控制台。然而默认的控制台处理器也会将日志输出到控制台上,这不是我想要的。如果您运行我的代码,您会看到额外的两行输出到控制台上。请问有谁知道如何禁用默认的控制台处理器?我只想使用我创建的两个处理器。

Handler fh = new FileHandler("test.txt");
fh.setFormatter(formatter);
logger.addHandler(fh);

Handler ch = new ConsoleHandler();
ch.setFormatter(formatter);
logger.addHandler(ch);

import java.util.Date;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

public class LoggingExample {
    private static Logger logger = Logger.getLogger("test");

    static {
        try {
            logger.setLevel(Level.INFO);

            Formatter formatter = new Formatter() {

                @Override
                public String format(LogRecord arg0) {
                    StringBuilder b = new StringBuilder();
                    b.append(new Date());
                    b.append(" ");
                    b.append(arg0.getSourceClassName());
                    b.append(" ");
                    b.append(arg0.getSourceMethodName());
                    b.append(" ");
                    b.append(arg0.getLevel());
                    b.append(" ");
                    b.append(arg0.getMessage());
                    b.append(System.getProperty("line.separator"));
                    return b.toString();
                }

            };

            Handler fh = new FileHandler("test.txt");
            fh.setFormatter(formatter);
            logger.addHandler(fh);

            Handler ch = new ConsoleHandler();
            ch.setFormatter(formatter);
            logger.addHandler(ch);

            LogManager lm = LogManager.getLogManager();
            lm.addLogger(logger);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        logger.info("why does my test application use the standard console logger ?\n" + " I want only my console handler (Handler ch)\n " + "how can i turn the standard logger to the console off. ??");
    }
}

1
我可以温和地建议使用b.append(formatMessage(arg0))而不是b.append(arg0.getMessage())。使用formatMessage方法,您可以使格式化程序与public void log(Level level, String msg, Object param1)等方法兼容。 - Victor
5个回答

117

只需要执行

LogManager.getLogManager().reset();

1
谢谢,这是正确的答案。标记为正确的答案不起作用。 - Andreas L.
1
这应该指出,这将影响每个命名为“Logger”的处理程序,因此对于更复杂的日志系统可能会造成问题。这应该在进程开始时调用一次,以确保未来的记录器不会受到影响。当然,需要控制台的那个人需要接收一个ConsoleHandler以按预期工作。 - AxelH

114

默认的控制台处理程序附加到根记录器,它是所有其他记录器(包括您自己的)的父记录器。因此,我看到解决您问题的两种方法:

如果这只影响你特定的类,最简单的解决方案是禁用向上传递日志消息到父记录器:

logger.setUseParentHandlers(false);

如果你想要改变整个应用程序的此行为,你可以在添加自己的处理程序之前完全删除根记录器的默认控制台处理程序:

Logger globalLogger = Logger.getLogger("global");
Handler[] handlers = globalLogger.getHandlers();
for(Handler handler : handlers) {
    globalLogger.removeHandler(handler);
}

注意:如果您想在其他类中也使用相同的日志处理程序,最好的方法是将日志配置长期保存在配置文件中。


2
setUseParentHandlers方法可行,谢谢。我该如何从根记录器中删除默认的控制台处理程序? - loudiyimo
10
你也可以使用Logger.getLogger("") - 这对我起作用,而"global"则不行(可能是因为混合了SLF4J?) - sehugg
2
如果你想使用slf4j,我建议你使用以下代码:LogManager.getLogManager().reset(); SLF4JBridgeHandler.install(); - Somatik
9
"" 是根记录器的标识符。"global" 是一个命名记录器(根记录器的子记录器),默认情况下会被创建,并应在简单日志记录场景中使用。 - Paolo Fulgoni
1
这个答案对我不起作用,但Dominique的答案可以。 - BullyWiiPlaza
显示剩余6条评论

22

这很奇怪,但是 Logger.getLogger("global") 在我的设置中不起作用(以及 Logger.getLogger(Logger.GLOBAL_LOGGER_NAME))。

然而,Logger.getLogger("")表现良好。

希望这些信息也能帮到别人......


3
为什么 getLogger(Logger.GLOBAL_LOGGER_NAME) 不起作用,但 getLogger("") 却可以? - deinocheirus
2
@deinocheirus 请看我对这个答案的评论。 - Paolo Fulgoni

9

执行配置重置,并将根级别设置为关闭

LogManager.getLogManager().reset();
Logger globalLogger = Logger.getLogger(java.util.logging.Logger.GLOBAL_LOGGER_NAME);
globalLogger.setLevel(java.util.logging.Level.OFF);

6

您必须指示您的记录器不要将其消息发送到其父记录器:

...
import java.util.logging.*;
...
Logger logger = Logger.getLogger(this.getClass().getName());
logger.setUseParentHandlers(false);
...

然而,在向记录器添加更多处理程序之前,应该先执行此操作。

这在我的情况下起作用了,尽管我不得不为此记录器手动添加处理程序。 - Sachin Gorade

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接