slf4j: как записать отформатированное сообщение, массив объектов, исключение

275

Как правильно регистрировать заполненное сообщение и трассировку стека исключения?

logger.error(
    "\ncontext info one two three: {} {} {}\n",
    new Object[] {"1", "2", "3"},
    new Exception("something went wrong"));

Я хотел бы сделать вывод, похожий на этот:

context info one two three: 1 2 3
java.lang.Exception: something went wrong
stacktrace 0
stacktrace 1
stacktrace ...

slf4j версия 1.6.1

Роу
источник
3
Я не понимаю, почему slf4j использует собственный синтаксис строки формата вместо стандартного стиля% s. Раздражает.
Кит Тайлер
@KeithTyler Мне нравится {}больше, дело вкуса ...
Бетлиста
@KeithTyler toString()Метод аргументов может быть дорогим. С этим синтаксисом передается только ссылка на каждый объект, и toString()метод вызывается только в том случае, если конкретное сообщение действительно регистрируется. Объекты, на которые ссылаются при info()вызове журнала, не будут вызывать свой toString()метод, если уровень журнала равен WARNили выше. {}Синтаксис напоминает пользователям , что это не String.format()-как операция, то есть они должны передавать объекты , а не строковые представления их.
user149408

Ответы:

427

Начиная с SLF4J 1.6.0, при наличии нескольких параметров и если последний аргумент в операторе ведения журнала является исключением, тогда SLF4J будет предполагать, что пользователь хочет, чтобы последний аргумент рассматривался как исключение, а не как простой параметр. Смотрите также соответствующую запись FAQ .

Итак, написание (в SLF4J версии 1.7.x и выше)

 logger.error("one two three: {} {} {}", "a", "b", 
              "c", new Exception("something went wrong"));

или писать (в SLF4J версии 1.6.x)

 logger.error("one two three: {} {} {}", new Object[] {"a", "b", 
              "c", new Exception("something went wrong")});

даст

one two three: a b c
java.lang.Exception: something went wrong
    at Example.main(Example.java:13)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at ...

Точный вывод будет зависеть от базовой структуры (например, logback, log4j и т. Д.), А также от того, как настроена базовая структура. Однако, если последний параметр является исключением, он будет интерпретироваться как таковой независимо от базовой структуры.

Ceki
источник
4
Какую базовую структуру ведения журналов вы используете? Как упомянуто в моем ответе выше, если последний параметр является исключением, он будет интерпретироваться как таковой независимо от базовой структуры. (Проверено с logback, slf4j-log4j12, slf4j-jdk14 и slf4j-simple.)
Ceki
3
Извините, я не узнал, что в вашем примере вы использовали n = 3 заполнителя в строке формата и n + 1 = 4 элемента в массиве объектов. У меня было n заполнителей в строке формата, а также n элементов в массиве объектов плюс исключение в качестве третьего параметра. Я ожидал, что исключение будет напечатано с помощью трассировки стека, но этого не произошло. Это работает как задумано? Кроме того, если у меня есть n заполнителей и n элементов в массиве объектов, за исключением последнего элемента, я не вижу никакой трассировки стека. Возможно, n заполнителей с n + 1 объектами в массиве должны быть немного более подчеркнуты.
Роу
7
Я собирался дать @Ceki трудное время, потому что он не в Javadocs, а на вершине Loggerкласса javadoc: slf4j.org/apidocs/org/slf4j/Logger.html
Адам Гент
1
Я создал запрос на улучшение , вы можете проголосовать за него, если вам это нравится.
Бетлиста
8

В дополнение к ответу @Ceki: если вы используете logback и настраиваете файл конфигурации в своем проекте (обычно logback.xml), вы можете определить журнал для построения трассировки стека, используя

<encoder>
    <pattern>%date |%-5level| [%thread] [%file:%line] - %msg%n%ex{full}</pattern> 
</encoder>

% ex в шаблоне - вот что делает разницу

Янов
источник