首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用java.util.logging打印线程名称

使用java.util.logging打印线程名称
EN

Stack Overflow用户
提问于 2011-07-31 19:04:12
回答 8查看 20.8K关注 0票数 17

是否可以打印java.util.logging.Logger生成的日志语句中的线程名称

一种替代方法是执行类似以下的操作:

代码语言:javascript
复制
logger.info(thread.getName() + " some useful info");

但是它是重复的,日志记录框架应该可以处理它。

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2011-07-31 19:22:24

很尴尬,但看起来java.util.logging不能这么做。

默认的java.util.logging.SimpleFormatter根本不能记录线程名。java.util.logging.FileHandler支持的模板占位符很少,它们都不是线程名称。

java.util.logging.XMLFormatter是最接近的,但只记录线程id:

代码语言:javascript
复制
<record>
  <date>2011-07-31T13:15:32</date>
  <millis>1312110932680</millis>
  <sequence>0</sequence>
  <logger></logger>
  <level>INFO</level>
  <class>java.util.logging.LogManager$RootLogger</class>
  <method>log</method>
  <thread>10</thread>
  <message>Test</message>
</record>

如果你觉得我们接近了-不是的。LogRecord类只保存线程ID,而不是它的名称--不是很有用。

票数 9
EN

Stack Overflow用户

发布于 2019-04-27 20:52:05

使用自定义Formatter

幸运的是,LogRecord包含生成日志消息的线程的ID。我们可以在编写自定义LogRecord时获取此Formatter。一旦我们有了它,我们只需要通过它的ID来获得线程的名称。

有获取对应于该ID的Thread对象的a couple of ways,下面是我的:

代码语言:javascript
复制
static Optional<Thread> getThread(long threadId) {
    return Thread.getAllStackTraces().keySet().stream()
            .filter(t -> t.getId() == threadId)
            .findFirst();
}

下面是一个最小的Formatter,它只打印线程名称和日志消息:

代码语言:javascript
复制
private static Formatter getMinimalFormatter() {
    return new Formatter() {

        @Override
        public String format(LogRecord record) {

            int threadId = record.getThreadID();
            String threadName = getThread(threadId)
                    .map(Thread::getName)
                    .orElseGet(() -> "Thread with ID " + threadId);

            return threadName + ": " + record.getMessage() + "\n";
        }
    };
}

要使用您的自定义格式化程序,还有different options,一种方法是修改默认的ConsoleHandler

代码语言:javascript
复制
public static void main(final String... args) {

    getDefaultConsoleHandler().ifPresentOrElse(
            consoleHandler -> consoleHandler.setFormatter(getMinimalFormatter()),
            () -> System.err.println("Could not get default ConsoleHandler"));

    Logger log = Logger.getLogger(MyClass.class.getName());
    log.info("Hello from the main thread");
    SwingUtilities.invokeLater(() -> log.info("Hello from the event dispatch thread"));
}

static Optional<Handler> getDefaultConsoleHandler() {
    // All the loggers inherit configuration from the root logger. See:
    // https://docs.oracle.com/javase/8/docs/technotes/guides/logging/overview.html#a1.3
    var rootLogger = Logger.getLogger("")
    // The root logger's first handler is the default ConsoleHandler
    return first(Arrays.asList(rootLogger.getHandlers()));
}

static <T> Optional<T> first(List<T> list) {
    return list.isEmpty() ?
            Optional.empty() :
            Optional.ofNullable(list.get(0));
}

然后,您的最小Formatter应生成包含线程名称的以下日志消息:

main:来自主线程的问候

AWT-EventQueue-0:来自事件分派线程的Hello

这是一个Formatter,它展示了如何记录线程名称和日志消息以外的内容:

代码语言:javascript
复制
private static Formatter getCustomFormatter() {
    return new Formatter() {

        @Override
        public String format(LogRecord record) {

            var dateTime = ZonedDateTime.ofInstant(record.getInstant(), ZoneId.systemDefault());

            int threadId = record.getThreadID();
            String threadName = getThread(threadId)
                    .map(Thread::getName)
                    .orElse("Thread with ID " + threadId);

            // See also: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Formatter.html
            var formatString = "%1$tF %1$tT %2$-7s [%3$s] %4$s.%5$s: %6$s %n%7$s";

            return String.format(
                    formatString,
                    dateTime,
                    record.getLevel().getName(),
                    threadName,
                    record.getSourceClassName(),
                    record.getSourceMethodName(),
                    record.getMessage(),
                    stackTraceToString(record)
            );
        }
    };
}

private static String stackTraceToString(LogRecord record) {
    final String throwableAsString;
    if (record.getThrown() != null) {
        var stringWriter = new StringWriter();
        var printWriter = new PrintWriter(stringWriter);
        printWriter.println();
        record.getThrown().printStackTrace(printWriter);
        printWriter.close();
        throwableAsString = stringWriter.toString();
    } else {
        throwableAsString = "";
    }
    return throwableAsString;
}

Formatter会生成如下日志消息:

2019-04-27 13:21:01 INFO AWT-EventQueue-0 package.ClassName.method:日志消息

票数 7
EN

Stack Overflow用户

发布于 2011-07-31 19:12:43

一些应用服务器隐式地记录线程ID (我知道WebSphere)。您可以创建自己的LogFormatter。传递给格式化程序的记录包含线程ID,请参见here。我为Tomcat多次实现了这种方法,但它也可以在Java环境中工作。

顺便说一句:线程名称对LogRecord不可用。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6889057

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档