是否可以在java.util.logging.Logger生成的日志语句中打印线程名称?一种替代方法是执行以下操作:
logger.info(thread.getName() + " some useful info");
Run Code Online (Sandbox Code Playgroud)
但它是重复的,日志框架应该处理它.
令人尴尬,但看起来java.util.logging不能这样做......
默认情况下java.util.logging.SimpleFormatter根本无法记录线程名称.该java.util.logging.FileHandler支架几个模板占位符,它们都不是线程名.
java.util.logging.XMLFormatter 是最接近的,但只记录线程ID:
<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>
Run Code Online (Sandbox Code Playgroud)
如果你认为我们正在接近 - 我们不是.LogRecordclass只保存线程ID,而不是它的名字 - 不是很有用.
Formatter幸运的是,LogRecord包含生成日志消息的线程的 ID。我们可以LogRecord在编写自定义Formatter. 一旦我们有了它,我们只需要通过它的 ID 获取线程名称。
有几种方法可以获取Thread与该 ID 对应的对象,这是我的:
static Optional<Thread> getThread(long threadId) {
return Thread.getAllStackTraces().keySet().stream()
.filter(t -> t.getId() == threadId)
.findFirst();
}
Run Code Online (Sandbox Code Playgroud)
以下是Formatter仅打印线程名称和日志消息的最小值:
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";
}
};
}
Run Code Online (Sandbox Code Playgroud)
要使用自定义格式化程序,还有不同的选项,一种方法是修改默认值ConsoleHandler:
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));
}
Run Code Online (Sandbox Code Playgroud)
Formatter然后你的minimal应该产生包含线程名称的以下日志消息:
main:来自主线程的你好
和
AWT-EventQueue-0:来自事件调度线程的Hello
这是一个Formatter显示如何记录线程名称和日志消息的更多信息:
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;
}
Run Code Online (Sandbox Code Playgroud)
这Formatter会产生这样的日志消息:
2019-04-27 13:21:01 INFO [AWT-EventQueue-0] package.ClassName.method:日志消息
| 归档时间: |
|
| 查看次数: |
15818 次 |
| 最近记录: |