Як надіслати стек-трек до 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 );
}

Відповіді:


262

Виняток передаєте безпосередньо до реєстратора, наприклад

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

Це до log4j, щоб надати слід стека.


32
Реєстратор бере об'єкт за його перший аргумент і буде йогоString (). Однак другий аргумент повинен бути Throwable і відображає слід стека.
Пітер Лоурі

1
Я ніколи не знаю, що вкласти в першу струну, зазвичай я просто закінчую робити log.error(e.getLocalizedMessage(), e)це абсолютно зайвим. Чи обробляє це нуль для першого аргументу?
Марк Петерс

5
@Mark: Спробуйте надати йому повідомлення, яке більше стосується контексту, ніж повідомлення про виняток, наприклад, що він насправді намагався зробити у той час?
skaffman

2
@Mark Peters, Хорошим прикладом може бути записування аргументів до поточного методу як повідомлення, або - для виключення FileNotFound - повне ім'я шляху, який намагався відкрити. Все, що може допомогти вам з’ясувати, що не так - просто подумайте, що ви не можете налагодити ситуацію.
Thorbjørn Ravn Andersen

1
@skaffman: Насправді я використовую, log4j-1.2.8.jarі я хотів роздрукувати все stackTraceв своєму журналі журналу, тому я намагався, як ви сказали вище, але друкує лише на моєму файлі журналу nullPointerException. Я був використаний на моєму коді, e.printStackTrace()він друкує всі сліди. Чому саме цей Колавері?
Yubaraj

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);

3
+1 для System.lineSeparator (), це допомогло мені надрукувати стек-трек, який я отримав у відповідь від віддаленої служби
Стефані

1
що я шукав, але ви повинні використовувати StringBuilder тут
Xerus

9

Ви також можете отримати слід стека як рядок через ExceptionUtils.getStackTrace.

Див.: ExceptionUtils.java

Я використовую його тільки для того log.debug, щоб тримати log.errorпростий.


4

Просто тому, що це сталося зі мною і може бути корисним. Якщо ви це зробите

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

ви отримаєте заголовок винятку, а не всю стек-трек. Тому що лісоруб подумає, що ти передаєш String. Робіть це без того, {}як сказав скафман


1
Звичайно, тут ви отримаєте цілий слід стека, однак {} буде надруковано дослівно (без жодної заміни)?
k1eran

1
не будь так впевнений, мій друже! Мені це не вийшло, я отримав лише заголовок. Це може залежати від версії log4j, хоча
iberbeu

@iberbeu має рацію, оскільки Throwable.toString()не повертає стек-трек. (Припустимо, що ви використовуєте реєстратор, який знає, що робити з "{}".)

4

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

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

Однак ви також можете витягувати стектрек у вигляді рядка. Іноді це може бути корисно, якщо ви хочете скористатися функцією форматування за допомогою заповнювача "{}" - див. Метод. 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);

Я фактично написав бібліотеку з відкритим кодом, яка має утиліту для вилучення стек-треків як String з можливістю розумно відфільтрувати шум із стека. Тобто, якщо ви вкажете префікс пакету, що вас зацікавив ваш видобутий стек-трак, він би відфільтрований з деяких невідповідних частин і залишив би вам дуже сформовану інформацію. Ось посилання на статтю, яка пояснює, які утиліти має бібліотека та де її отримати (як джерела артефактів, так і джерела git) та як їх також використовувати. Бібліотека Java з відкритим кодом з фільтрацією слідів стека, безшумним розбором конвертора Unicode та порівнянням версій Див. Параграф " Шум-фільтр стеки "


1
Похована, але приємна відповідь.
Payne

Дякую, @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);
    }

0

це було б добре log4j помилка / реєстрація винятків - читається за допомогою прокрутки / інших журналів / моніторингу s / w. все - це пара ключа-значення. log4j отримає слід стека від Obje

    try {
          ---
          ---
    } catch (Exception e) {
        log.error("api_name={} method={} _message=\"error description.\" msg={}", 
                  new Object[]{"api_name", "method_name", e.getMessage(), 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();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.