Не используйте System.out.println в коде на стороне сервера
Я слышал, что использование System.out.println
для ведения журнала - очень плохая практика, и это может привести к сбою сервера.
Я не использую этот подход, но мне очень интересно знать, почему System.out.println может сделать так мусорные вещи, когда они используются во внутреннем коде.
Ответы
Ответ 1
System.out.println - это операция ввода-вывода, и поэтому требуется много времени.
Проблема с его использованием в вашем коде заключается в том, что ваша программа будет ждать завершения println. Это может быть не проблема с небольшими сайтами, но как только вы получите нагрузку или много итераций, вы почувствуете боль.
Лучший подход - использовать структуру ведения журнала.
Они используют очередь сообщений и записывают только в том случае, если другой вывод не выполняется.
И еще одно преимущество заключается в том, что вы можете настраивать отдельные файлы журналов для разных целей.
Что-то ваша команда Ops будет вас любить.
Подробнее здесь:
Ответ 2
Это плохая практика, потому что, когда ваше приложение входит в Production, вы не можете отделять журналы приложений от журналов сервера.
Команды Prod хотят, чтобы вы отделили журналы, созданные вашим приложением, от тех, которые были с сервера приложений (tomcat, websphere и т.д.): они хотят иметь возможность контролировать сервер приложений по-разному из самого приложения.
Кроме того, используя System.out, вы не можете определить уровень журнала: в разделе "Производство" вы не хотите печатать отладочную информацию.
Ответ 3
Посмотрите статью Адама Биенса в выпуске журнала Java Magazine Ноябрь/Дезембер о стресс-тестировании приложений JEE6 - бесплатно онлайн, вам нужно только подписаться на него.
На стр. 43 он показывает, что серверные приложения, которым удается обрабатывать 1700 транзакций в секунду, падает до 800 при вставке одного System.out.println
с фиксированной строкой в каждом.
Ответ 4
Считается, что это плохо, потому что System.out.println();
потребляет больше процессора и, следовательно, выход медленный, значит, вредит производительности. (Фактически каждая операция ввода-вывода ест процессор).
Ответ 5
Причина не в том, что сервер может выйти из строя, но может быть трудно найти такой вывод на сервере. Вы всегда должны использовать какую-то структуру ведения журнала с определенным поведением и выходным файлом.
Ответ 6
Во-первых, наличие нескольких запросов, поражающих ваш сервер, и печать журнала на System.out
не является хорошей практикой.
- Все журналы печатаются на экране (дескриптор файла). Нет способа прокрутить назад и прочитать журнал.
-
System.out
не синхронизируется. Для управления печатью с помощью System.out
должно быть управление concurrency
- Вы не можете определить уровни журнала через
System.out
. Вы не можете самостоятельно отделять уровни журнала для разделения выходов на лету.
Надеюсь, это поможет.
Ответ 7
- Программа будет ждать завершения println.
Журналы используют очередь сообщений и записывают только в том случае, если другой выход не выполняется.
- System.out.println(SOP) не являются потокобезопасными (например, асинхронными)
Регистраторы являются потокобезопасными (то есть синхронными)
- Регистраторы могут быть легко конфигурируемы
a.
Форматирование, ограничение содержимого журнала, доступного регистраторам
b.
Несколько файлов журнала регистрации конечных пользователей, консоли, DB
- SOP записывают журналы в файлы журнала сервера.
Нам нужно, чтобы журналы приложений были отделены от журналов сервера, так как это может привести к сбою сервера.
- Серверные приложения, которым удается обрабатывать 1700 транзакций в секунду, падает до 800 при вставке одного SOP с фиксированной строкой в каждом
Ответ 8
Еще одна причина заключается в том, что System.out и err являются PrintStreams, которые потребляют все основные IOExceptions. См. Следующие методы PrintStreams:
/**
* Writes the specified byte to this stream. If the byte is a newline and
* automatic flushing is enabled then the <code>flush</code> method will be
* invoked.
*
* <p> Note that the byte is written as given; to write a character that
* will be translated according to the platform default character
* encoding, use the <code>print(char)</code> or <code>println(char)</code>
* methods.
*
* @param b The byte to be written
* @see #print(char)
* @see #println(char)
*/
public void write(int b) {
try {
synchronized (this) {
ensureOpen();
out.write(b);
if ((b == '\n') && autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
/**
* Flushes the stream and checks its error state. The internal error state
* is set to <code>true</code> when the underlying output stream throws an
* <code>IOException</code> other than <code>InterruptedIOException</code>,
* and when the <code>setError</code> method is invoked. If an operation
* on the underlying output stream throws an
* <code>InterruptedIOException</code>, then the <code>PrintStream</code>
* converts the exception back into an interrupt by doing:
* <pre>
* Thread.currentThread().interrupt();
* </pre>
* or the equivalent.
*
* @return <code>true</code> if and only if this stream has encountered an
* <code>IOException</code> other than
* <code>InterruptedIOException</code>, or the
* <code>setError</code> method has been invoked
*/
public boolean checkError() {
if (out != null)
flush();
if (out instanceof java.io.PrintStream) {
PrintStream ps = (PrintStream) out;
return ps.checkError();
}
return trouble;
}
Таким образом, исключение IOException из основного потока ВСЕГДА потребляется, и обычно люди никогда не вызывают checkError для System out, поэтому они даже не знают, что что-то произошло.
Ответ 9
Использование стандартного изложения - плохая практика. Однако, если у вас есть библиотека или код, который использует System.out и System.err, вы можете написать собственный PrintStream, который вместо этого записывает имя потока и info() и ошибку(). Как только вы это сделаете, вы можете быть более спокойным в использовании System.out, поскольку он будет записывать в журналы, например. log4j.
В идеале вы будете использовать соответствующие журналы непосредственно esp для регистрации уровня отладки. IMHO его не имеет большого значения, если вы не используете встроенный System.out/err! (По общему мнению, большое допущение)
Если вы используете System.out, который перенаправляется в файл или использует log4j или Java Logger для записи в файл, производительность почти точно такая же.