2014-01-28 8 views
0

В более крупной программе я использую статический экземпляр java.util.logging.Logger, но перенаправляю System.err нескольким различным файлам подряд. Logger не удается зарегистрировать второй раз, когда я пытаюсь перенаправить System.err.System.setErr() вмешивается в Logger

Вот тестовая программа, чтобы показать проблему:

import java.io.FileNotFoundException; 
import java.io.PrintStream; 
import java.util.logging.Logger; 

class TestRedirect { 
    static final Logger logger = Logger.getLogger("test"); 

    public static void main(String[] args) throws FileNotFoundException { 
     for (int i = 1; i <= 2; i++) { 
      TestRedirect ti = new TestRedirect(); 
      ti.test(i); 
     } 
    } 

    void test(int i) throws FileNotFoundException { 
     PrintStream filePrintStream = new PrintStream("test" + i + ".log"); 
     PrintStream stderr = System.err; // Save stderr stream. 
     System.setErr(filePrintStream); // Redirect stderr to file. 
     System.err.println("about to log " + i); 
     logger.info("at step " + i); 
     System.setErr(stderr);   // Restore stderr stream. 
     filePrintStream.close(); 
    } 
} 

Вот вывод:

test1.log:

about to log 1 
Jan 28, 2014 4:34:20 PM TestRedirect test 
INFO: at step 1 

test2.log:

about to log 2 

Я думал, что увижу сообщение сгенерированное Logger в test2.log. Почему Logger перестает работать, и что я могу сделать по этому поводу?

+0

Обычно я рекомендую не перенаправлять стандартные потоки на Java, если есть другой возможный подход. Вы уверены, что вам нужно использовать 'setErr()'? – Darkhogg

+0

@ Darkhogg: оригинальная программа на самом деле использовала Groovy 'SystemOutputInterceptor' (в основном« tee »на основе« FilteredOutputStream') для прямого ввода stdout и stderr в файл журнала, а также на консоль. 'SystemOutputInterceptor' вызывает' setErr() 'под обложками. Некоторые из различных частей программы использовали Logger, а некоторые просто записывали информацию и ошибки в stderr и stdout. –

ответ

2

По умолчанию JRE сконфигурирован для загрузки ConsoleHandler в корневой журнал. По умолчанию ваше сообщение журнала будет перемещаться к обработчикам корневого регистратора. Обработчики корневого регистратора загружаются по требованию. В вашей текущей программе ленивая загрузка корневого регистратора ConsoleHandler захватывает ваш первый перенаправленный System.err. После этого обработчик корневого регистратора никогда не перезагружается, поэтому вы никогда не увидите сообщение журнала в журнале 2. Кроме того, 1-й перенаправленный поток закрыт, поэтому теперь root ConsoleHandler пишет в закрытый поток.

Чтобы подтвердить это, добавьте следующее в качестве первых строк основного метода тестового примера и запустите программу.

Logger.getLogger("").getHandlers(); //Force load root logger handlers. 
Logger.getLogger("").removeHandler((Handler) null); 

Вы увидите, что в настоящее время не регистрируются сообщения регистратора. Если вам интересно, почему это работает, вы можете прочитать исходный код java.util.logging.LogManager$RootLogger.

Что вам нужно сделать, это создать StreamHandler с перенаправленным потоком System.err, а затем add и remove StreamHandler из вашего регистратора. Вы также можете переключить использование parent handlers на свою конфигурацию журнала, чтобы избежать записи в исходную систему System.err.

Другим возможным решением было бы найти все экземпляры ConsoleHandler. Удалите и закройте все. Выполните перенастройку System.err. Затем создайте и присоедините новые ConsoleHandlers.

JDK мудрый, ConsoleHandler и ErrorManager должны были быть предназначены для использования java.io.FileDescriptor, который никогда не перенаправляется.

Смежные вопросы