Как отправить трассировку стека в log4j?

152

Допустим, вы перехватываете исключение и получаете следующее в стандартном выводе (например, в консоли), если выполняете e.printStackTrace () :

java.io.FileNotFoundException: so.txt
        at java.io.FileInputStream.<init>(FileInputStream.java)
        at ExTest.readMyFile(ExTest.java:19)
        at ExTest.main(ExTest.java:7)

Теперь я хочу отправить это в регистратор, например, log4j, чтобы получить следующее:

31947 [AWT-EventQueue-0] ERROR Java.io.FileNotFoundException: so.txt
32204 [AWT-EventQueue-0] ERROR    at java.io.FileInputStream.<init>(FileInputStream.java)
32235 [AWT-EventQueue-0] ERROR    at ExTest.readMyFile(ExTest.java:19)
32370 [AWT-EventQueue-0] ERROR    at ExTest.main(ExTest.java:7)

Как я могу это сделать?

try {
   ...
} catch (Exception e) {
    final String s;
    ...  // <-- What goes here?
    log.error( s );
}
SyntaxT3rr0r
источник

Ответы:

262

Вы передаете исключение непосредственно в регистратор, например,

try {
   ...
} catch (Exception e) {
    log.error( "failed!", e );
}

Это до log4j для рендеринга стека трассировки.

skaffman
источник
32
Регистратор принимает объект в качестве первого аргумента и выполняет toString (). Однако второй аргумент должен быть Throwable и отображать трассировку стека.
Питер Лори
1
Я никогда не знаю, что добавить в первую строку, обычно я просто заканчиваю тем, log.error(e.getLocalizedMessage(), e)что полностью излишним. Это обрабатывает нуль для первого аргумента?
Марк Питерс
5
@Mark: попробуйте дать ему сообщение, которое имеет большее отношение к контексту, чем сообщение об исключении, например, что он на самом деле пытался сделать в то время?
Скаффман
2
@Mark Peters, хорошим примером может быть запись аргументов текущего метода в виде сообщения или - для исключения FileNotFound полное имя пути, который пытались открыть. Все, что может помочь вам выяснить, что не так - просто подумайте, что вы не можете отладить ситуацию.
Торбьерн Равн Андерсен
1
@skaffman: На самом деле я использую, log4j-1.2.8.jarи я хотел напечатать все stackTraceв моем файле журнала, поэтому я попытался, как вы упомянули выше, но это печать только на моем файле журнала nullPointerException. Я был использован в моем коде, e.printStackTrace()он печатает все следы. Почему этот Колаверы?
Юбарадж
9

Если вы хотите записать трассировку стека без исключения, просто сделайте это:

String message = "";

for(StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {                         
    message = message + System.lineSeparator() + stackTraceElement.toString();
}   
log.warn("Something weird happened. I will print the the complete stacktrace even if we have no exception just to help you find the cause" + message);
borjab
источник
3
+1 для System.lineSeparator (), это помогло мне напечатать трассировку стека, которую я получил в ответ от удаленного сервиса
Стефани
1
что я искал, но вы должны использовать StringBuilder здесь
Xerus
9

Вы также можете получить трассировку стека в виде строки через ExceptionUtils.getStackTrace.

Смотрите: ExceptionUtils.java

Я использую его только для того log.debug, чтобы держать log.errorпростой.

ktsujister
источник
4

Просто потому, что это случилось со мной и может быть полезным. Если вы делаете это

try {
   ...
} catch (Exception e) {
    log.error( "failed! {}", e );
}

вы получите заголовок исключения, а не всю трассировку стека. Потому что регистратор будет думать, что вы передаете строку. Сделай это так, {}как сказал скаффман

iberbeu
источник
1
Конечно, вы получите всю трассировку стека, однако {} будет напечатан дословно (без подстановки)?
k1eran
1
не будь так уверен, мой друг! Это не сработало для меня, я получил только заголовок. Это может зависеть от версии log4j
iberbeu
@iberbeu прав, потому Throwable.toString()что не возвращает трассировку стека. (Предполагается, что вы используете регистратор, который знает, что делать с '{}'.)
4

Ответ от Скаффмана, безусловно, правильный ответ. Все методы ОК , такие как error(), warn(), info(), debug()взять метательную в качестве второго параметра:

try {
...
 } catch (Exception e) {
logger.error("error: ", e);
}

Тем не менее, вы также можете извлечь Stacktrace в виде строки. Иногда это может быть полезно, если вы хотите воспользоваться возможностью форматирования с использованием заполнителя "{}" - см. Метод. void info(String var1, Object... var2);В этом случае, скажем, у вас есть трассировка стека как String, тогда вы можете сделать что-то вроде этого:

try {
...
 } catch (Exception e) {
String stacktrace = TextUtils.getStacktrace(e);
logger.error("error occurred for usename {} and group {}, details: {}",username, group, stacktrace);
}

Это выведет параметризованное сообщение и трассировку стека в конце так же, как и для метода: logger.error("error: ", e);

Я на самом деле написал библиотеку с открытым исходным кодом, в которой есть утилита для извлечения трассировки стека в виде строки с возможностью интеллектуальной фильтрации некоторого шума из трассировки стека. Т.е., если вы укажете префикс пакета, который вас интересует в извлеченной трассировке стека, он будет отфильтрован из не относящихся к делу частей и предоставит вам очень обобщенную информацию. Вот ссылка на статью, которая объясняет, какие утилиты есть в библиотеке и где ее взять (как в виде артефактов maven, так и в источниках git) и как ее использовать. Java-библиотека с открытым исходным кодом с фильтрацией трассировки стека, преобразованием Unicode Sarsnt String и сравнением версий. См. Параграф « Фильтр шума Stacktrace »

Майкл Гантман
источник
1
Закрытый, но хороший ответ.
Пейн
Спасибо, @payne. Я ценю хорошие отзывы
Майкл Гантман
2

Этот ответ может быть не связан с заданным вопросом, но связан с названием вопроса.

public class ThrowableTest {

    public static void main(String[] args) {

        Throwable createdBy = new Throwable("Created at main()");
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintWriter pw = new PrintWriter(os);
        createdBy.printStackTrace(pw);
        try {
            pw.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.debug(os.toString());
    }
}

ИЛИ

public static String getStackTrace (Throwable t)
{
    StringWriter stringWriter = new StringWriter();
    PrintWriter  printWriter  = new PrintWriter(stringWriter);
    t.printStackTrace(printWriter);
    printWriter.close();    //surprise no IO exception here
    try {
        stringWriter.close();
    }
    catch (IOException e) {
    }
    return stringWriter.toString();
}

ИЛИ

StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
for(StackTraceElement stackTrace: stackTraceElements){
    logger.debug(stackTrace.getClassName()+ "  "+ stackTrace.getMethodName()+" "+stackTrace.getLineNumber());
}
Канагавелу Сугамар
источник
1

В Log4j 2 вы можете использовать Logger.catching () для регистрации трассировки стека из обнаруженного исключения.

    try {
        String msg = messages[messages.length];
        logger.error("An exception should have been thrown");
    } catch (Exception ex) {
        logger.catching(ex);
    }
mbonness
источник
0

это было бы хорошо, если бы log4j регистрировал ошибки / исключения - можно было прочитать с помощью splunk / other logging / monitor s / w. все является формой пары ключ-значение. log4j получит трассировку стека из Exception obje

    try {
          ---
          ---
    } catch (Exception e) {
        log.error("api_name={} method={} _message=\"error description.\" msg={}", 
                  new Object[]{"api_name", "method_name", e.getMessage(), e});
    }
src3369
источник
0
Try this:

catch (Throwable t) {
    logger.error("any message" + t);
    StackTraceElement[] s = t.getStackTrace();
    for(StackTraceElement e : s){
        logger.error("\tat " + e);
    }   
}
Радждип Ачарья Чоудхури
источник
-1

Вы можете использовать приведенный ниже код:

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class LogWriterUtility {
    Logger log;

    public LogWriterUtility(Class<?> clazz) {
        log = LogManager.getLogger(clazz);
    }

public void errorWithAnalysis( Exception exception) {

        String message="No Message on error";
        StackTraceElement[] stackTrace = exception.getStackTrace();
        if(stackTrace!=null && stackTrace.length>0) {
            message="";
            for (StackTraceElement e : stackTrace) {
                message += "\n" + e.toString();
            }
        }
        log.error(message);


    }

}

Здесь вы можете просто позвонить: LogWriterUtility.errorWithAnalysis( YOUR_EXCEPTION_INSTANCE);

Он выведет stackTrace в ваш журнал.

Г-н Саджедул Карим
источник
-2

Создайте это class:

public class StdOutErrLog {

private static final Logger logger = Logger.getLogger(StdOutErrLog.class);

public static void tieSystemOutAndErrToLog() {
    System.setOut(createLoggingProxy(System.out));
    System.setErr(createLoggingProxy(System.err));
}

public static PrintStream createLoggingProxy(final PrintStream realPrintStream) {
    return new PrintStream(realPrintStream) {
        public void print(final String string) {
            logger.info(string);
        }
        public void println(final String string) {
            logger.info(string);
        }
    };
}
}

Назовите это в своем коде

StdOutErrLog.tieSystemOutAndErrToLog();
user2281804
источник