Как предотвратить смешивание потоков sysout и syserr? - PullRequest
3 голосов
/ 23 ноября 2010

В моей кодовой базе есть (очень упрощенное) следующее:

public static void main (String[] args) {
   System.out.println("Starting application");
   try {
      System.out.println("About to validate");
      validate(args);
   catch (Exception e) {
      e.printStackTrace();
   }
}

public static void validate(String[] args) {
   System.out.println("Your first arg is " + args[0]);
   if (someProblemWith(args)) {
      System.out.println("Your args are wrong.  It should be: ...");
      throw new BadArgsException(e);
   }
}

, который отлично работает.Обратите внимание, что мой пример кода выше придуман и предназначен для показа нескольких операторов журнала до исключения и печати трассировки стека.Это часто означает, что мой последний оператор записи потерян в середине вывода трассировки стека.Есть ли элегантный способ попросить оператор e.printStackTrace() подождать, пока System.out завершит свою работу?По сути, я ищу, чтобы трассировка стека была самой последней напечатанной при возникновении ошибки.Вот пример выходных данных моей программы выше:

 java.lang.Throwable
 ....
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 Your args are wrong.  It should be: ...
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56)

Ответы [ 2 ]

8 голосов
/ 23 ноября 2010

Причина, по которой вы видите, что трассировка стека печатается между операторами System.out.println(), заключается в том, что System.out буферизуется, а System.err (используется трассировкой стека) - не буферизируется.

Если вы хотите, чтобы текст отображался в точном порядке, в котором происходят события, вам необходимо «снять буфер» с System.out. Самый простой способ - просто использовать System.err вместо System.out.

В противном случае, вызовите System.out.flush() до того, как ваши следы в стеке произойдут в предложениях catch.

Вариант 2. Используйте класс Logger.

Вариант 3: Реализация собственного «буфера». Другими словами, сначала запишите все в свой собственный буфер, включая трассировку стека (используя .toString() или как хотите), а затем в catch очистите свой собственный буфер. (Это несколько избыточно, так как вы можете просто сбросить System.out).

- == -

ОТ КОММЕНТАРИИ

Конечно. Класс Logger можно использовать для создания более надежного и подробного процесса регистрации. Обычно это то, что делается в приложениях. Экземпляр класса Logger извлекается из класса Logger (он является одиночным), принимая в качестве параметра класс, из которого будет использоваться. Затем вы записываете в него сообщения, используя метод .log(). Приятной особенностью класса Logger является то, что вы можете устанавливать для него уровни (например, DEBUG, WARN ...), и тогда вы сможете фильтровать / отображать только то, что вам нужно. Сообщения «log» затем отображаются в консоли единообразно, обычно в формате:

2010-11-23 14:45:32,032 DEBUG [MyClass] Your message

Вышеуказанный формат взят из log4j, но вы можете использовать стандартную Java Logger. Вывод должен быть похожим, может быть немного меньше. Но я уверен, что это можно настроить.

1 голос
/ 23 ноября 2010

Звоните e.printStackTrace(System.out);. Или, если вам это нужно только для отладки, вы можете отделить вывод процесса и ошибку от командной строки: .... 1>output.log 2>error.log

...