Comments 26
> Выводим лог сообщения куда-то еще
Здесь еще можно добавить, что возможно логирование в syslog. Что довольно удобно в некоторых случаях.
Например вот так:
blog.dutchworks.nl/2010/01/14/logging-to-the-syslog-from-a-java-application/
Здесь еще можно добавить, что возможно логирование в syslog. Что довольно удобно в некоторых случаях.
Например вот так:
blog.dutchworks.nl/2010/01/14/logging-to-the-syslog-from-a-java-application/
0
За статью спасибо!
Я раньше такие статьи заставлял junior-ов писать :-)
Я раньше такие статьи заставлял junior-ов писать :-)
-2
Тема не раскрыта, ИМХО. Больше всего недопонимания у народа, которым я объяснял логгинг в таких фремворках — вызывает матрица логгеров и аппендеров. И это как раз самая базовая и самая мощная фича. Про это надо в первую очередь рассказывать.
Фразы java logging best practices и java.util.logging framework не сочетаются — опять ИМХО. java.util.logging framework не рекомендуется к использованию (по многим причинам), а вместо нее нужна обертка типа slf4j, и реализация поприличнее, чем JUL — тогда можно говорить о best practices. Иначе в реальной жизни оно так-же применимо, как Hello World.
Фразы java logging best practices и java.util.logging framework не сочетаются — опять ИМХО. java.util.logging framework не рекомендуется к использованию (по многим причинам), а вместо нее нужна обертка типа slf4j, и реализация поприличнее, чем JUL — тогда можно говорить о best practices. Иначе в реальной жизни оно так-же применимо, как Hello World.
+6
См начало статьи:
Весь код примеров использует java.util.logging framework. Вопрос «Какой из фреймворков логирования ниболее кошерен» я оставлю за кадром. Скажу только что до java.util.logging проще всего дотянуться ибо он уже идет вместе с JRE и на самом деле рассказанное в данной статье с минимальными
И поверьте писать код вполне можно не понимая матрицу логеров и апендеров. Достаточно чтобы хотя бы один человек в команде это понимал.
Весь код примеров использует java.util.logging framework. Вопрос «Какой из фреймворков логирования ниболее кошерен» я оставлю за кадром. Скажу только что до java.util.logging проще всего дотянуться ибо он уже идет вместе с JRE и на самом деле рассказанное в данной статье с минимальными
И поверьте писать код вполне можно не понимая матрицу логеров и апендеров. Достаточно чтобы хотя бы один человек в команде это понимал.
0
Я это видел, конечно. И код писать можно. Но на best practices оно не тянет — максимум на beginners tutorial, чтобы научиться делать хоть как-нибудь, а потом уже переучиваться делать правильно (так почему сразу не учить, как делать правильно?).
Хотя, пожалуй, я слишком придираюсь.
В общем, статья написана очень неплохо. Если добавить пару вещей — (1) ту самую матрицу логгеров/аппендеров, и (2) объяснить, что хотя для примеров используется JUL из коробки, в реальной жизни его применять не стоит по ряду причин (мешанина логгеров в сторонних библиотеках требует использования обертки над логгером и перенаправления части логгинг фреймворков в один реально используемый; ограниченность возможностей JUL; неудобство использования в ряде мест — довольно критично, на самом деле) — тогда будет ок.
Хотя, пожалуй, я слишком придираюсь.
В общем, статья написана очень неплохо. Если добавить пару вещей — (1) ту самую матрицу логгеров/аппендеров, и (2) объяснить, что хотя для примеров используется JUL из коробки, в реальной жизни его применять не стоит по ряду причин (мешанина логгеров в сторонних библиотеках требует использования обертки над логгером и перенаправления части логгинг фреймворков в один реально используемый; ограниченность возможностей JUL; неудобство использования в ряде мест — довольно критично, на самом деле) — тогда будет ок.
+1
Не флейма ради. Я достаточно давно (фактически с момента выхода 1.4) использую JUL. Вроде пока больших проблем на замечал, ну кроме иногда необходимой некоторой магии с настройкой логеров сторонних библиотек.
Тут хочется ехидно спросить «что я делаю не так». Но на самом деле действительно интересно, что я упускаю? Может быть в моих приложениях есть какая-то засада о которой я не знаю?
В принципе то и Tomcat на JUL перешел.
Тут хочется ехидно спросить «что я делаю не так». Но на самом деле действительно интересно, что я упускаю? Может быть в моих приложениях есть какая-то засада о которой я не знаю?
В принципе то и Tomcat на JUL перешел.
0
Не флейма ради, а токмо пользы для :-)
Например, с JUL мы пишем:
Но конкатенация строк при выключенных отладочных логах может убить производительность, поэтому мы пишем так:
Но если функция prepareCPUConsumingLogMessage() вернет null, всем будет плохо. Поэтому мы пишем так:
Теперь сравним с SLF4J:
Профит:
1. Значительно более компактно и понятно.
2. Проверка logLevel может быть опущена в большинстве мест, кроме самых критичных по быстродействию, и тех, где вызывается prepareCPUConsumingLogMessage().
3. Проверка нулей выполняется за вас — это очень важно, так как зачастую из-за этих нулей включение логгирования может прервать выполнение функции (которая сама по себе может и была защищена от нулей, но не в отладочном сообшении).
Например, с JUL мы пишем:
log.fine( "Let's display some object in debug: " + myObject );
Но конкатенация строк при выключенных отладочных логах может убить производительность, поэтому мы пишем так:
if( log.isLoggable( Level.FINE ) ) {
log.fine( "Let's display some object in debug: " + myObject );
}
Но если функция prepareCPUConsumingLogMessage() вернет null, всем будет плохо. Поэтому мы пишем так:
if( log.isLoggable( Level.FINE ) ) {
log.fine( "Let's display some object in debug: " + (myObject != null ? myObject.toString() : "null") );
}
Теперь сравним с SLF4J:
log.debug( "Let's display some object in debug: {}", myObject );
Профит:
1. Значительно более компактно и понятно.
2. Проверка logLevel может быть опущена в большинстве мест, кроме самых критичных по быстродействию, и тех, где вызывается prepareCPUConsumingLogMessage().
3. Проверка нулей выполняется за вас — это очень важно, так как зачастую из-за этих нулей включение логгирования может прервать выполнение функции (которая сама по себе может и была защищена от нулей, но не в отладочном сообшении).
+1
Поторопился —
Но если функция prepareCPUConsumingLogMessage() вернет null,
нужно читать как
Но если объект вернет myObject,
Но если функция prepareCPUConsumingLogMessage() вернет null,
нужно читать как
Но если объект вернет myObject,
0
вот блин… ну почему нельзя комменты редактировать?!
нужно читать как
Но если объект myObject вернет null
нужно читать как
Но если объект myObject вернет null
0
Спасибо, я понял. Это да. Перегруженных методов у стандартного логера не хватает.
Возможно то, что меня устраивает JUL является следствием приверженности бритве Оккама и моего стиля написания лог сообщений.
На конкатенацию двух-трех строк я обычно не обращаю внимания, особенно если где-то рядом есть обращение к БД или сетевой обмен.
По поводу null
выведет
В целом согласен — сочетания Formatter и логера в одном флаконе весьма удобно.
На самом деле к JUL у меня есть две серьезные претензии
1. отсутствие контекстного логирования например /псевдокод/
делаем так, а потом собираем по всем логерам срез относящийся только к данному хосту. Как мне помнится Log4J такое позволяет
2. LogBags — это когда мы выделяем одну условную единицу обработки например запроса и пишем туда все подряд с разными уровнями. Но в лог файл это попадает только если максимальный уровень в LogBag не меньше указанного, например warning. Так мы имеем не очень большой файл логов, но зато все-все сообщения включая уровень finest.
По молодости я пытался что-то такое использовать, но потом плюнул ибо заставить всю команду ровно и консистентно писать в лог не реально. А если даже один джуниор начинает писать как попало (например забьет на контекст), все эти стройные штуки ломаются нафиг. И сейчас остановился на следующей позиции. Да JUL не идеален, иногда он громоздок, но он стандартен и проще один раз научить всех им пользоваться, чем мучиться с солянкой из разных логеров в головах разработчиков.
Мне к сожалению довелось видеть проект в котором 3 разных разработчика, каждый использовали свой и только свой, единственно рассово-верный логер, периодически рефакторя код друг друга :-)
Возможно то, что меня устраивает JUL является следствием приверженности бритве Оккама и моего стиля написания лог сообщений.
На конкатенацию двух-трех строк я обычно не обращаю внимания, особенно если где-то рядом есть обращение к БД или сетевой обмен.
По поводу null
public class TestNull {
public static void main(String[] args) {
String s = null;
System.out.println("!"+s);
}
}
выведет
!null
В целом согласен — сочетания Formatter и логера в одном флаконе весьма удобно.
На самом деле к JUL у меня есть две серьезные претензии
1. отсутствие контекстного логирования например /псевдокод/
log.context(remoteHostAddress).log("Transport packet received:\n" + Util.dumpBytes(packetBytes));
делаем так, а потом собираем по всем логерам срез относящийся только к данному хосту. Как мне помнится Log4J такое позволяет
2. LogBags — это когда мы выделяем одну условную единицу обработки например запроса и пишем туда все подряд с разными уровнями. Но в лог файл это попадает только если максимальный уровень в LogBag не меньше указанного, например warning. Так мы имеем не очень большой файл логов, но зато все-все сообщения включая уровень finest.
По молодости я пытался что-то такое использовать, но потом плюнул ибо заставить всю команду ровно и консистентно писать в лог не реально. А если даже один джуниор начинает писать как попало (например забьет на контекст), все эти стройные штуки ломаются нафиг. И сейчас остановился на следующей позиции. Да JUL не идеален, иногда он громоздок, но он стандартен и проще один раз научить всех им пользоваться, чем мучиться с солянкой из разных логеров в головах разработчиков.
Мне к сожалению довелось видеть проект в котором 3 разных разработчика, каждый использовали свой и только свой, единственно рассово-верный логер, периодически рефакторя код друг друга :-)
+1
logbags на самом деле не обязательно. Если таки использовать context (по крайней мере, в критических участках), то например, logback позволяет с помощью MDCFilter-a логгировать отладочные сообщения только от одного залогиненного пользователя (или по какому другому критерию), оставляя всех остальных пользователей в INFO.
Можно даже прикрутить такую штуку без использования контекста, если есть на что опереться в thread local storage, чтобы получить ассоциацию с конкретной сессией.
В JUL (и ему подобных вещах, в свое время полу-скопированных Sun-ом «ради стандартизации»), меня раздражает то, что они не развиваются.
Спасибо за подсказку с конкатенированием строк — тут меня С/С++ бэкграунд подводит — у меня фобия насчет нулевых указателей :-).
Можно даже прикрутить такую штуку без использования контекста, если есть на что опереться в thread local storage, чтобы получить ассоциацию с конкретной сессией.
В JUL (и ему подобных вещах, в свое время полу-скопированных Sun-ом «ради стандартизации»), меня раздражает то, что они не развиваются.
Спасибо за подсказку с конкатенированием строк — тут меня С/С++ бэкграунд подводит — у меня фобия насчет нулевых указателей :-).
0
logbag нужен вот для чего — например (почти реальная ситуация) у меня приходят пакеты по сети, я их сложным образом потрошу и раздают другим частям системы. Каждый пакет может порождать скажем 500 потенциально полезных сообщений. Пакеты валятся со скоростью 10 штук в сек. Общий максимальный объем текста логов на один пакет скажем 50-100 кб.
Система mission critical и привзрыве неприятностях с одной из 200 установок у меня будут спрашивать каждую мелочь, когда получил, что было в полученном пакете, когда обработал, какой пакет (в байтах) по сети отдал и когда, когда получил подтверждение о том, что дошло и какие байты были в подтверждении.
Контекст безусловно рулит позволяет отфильтровать относящееся к конкретной установке (по позывному), но блин за сутки это ~20Гб текста, а историю надо хранить хотя бы за три месяца.
Конечно есть log rotate + gzip и все такое, но это безумство логов тоже как-то хочется ограничить
В этой ситуации очень удобна система при которой нормально пишутся только info сообщения и все-все сообщения если при обработке пакета был хотя бы один warning.
Но, надо сказать, что проект сильно не типичный, обычно такого геморроя нет и хватает обычных средств :-)
Система mission critical и при
Контекст безусловно рулит позволяет отфильтровать относящееся к конкретной установке (по позывному), но блин за сутки это ~20Гб текста, а историю надо хранить хотя бы за три месяца.
Конечно есть log rotate + gzip и все такое, но это безумство логов тоже как-то хочется ограничить
В этой ситуации очень удобна система при которой нормально пишутся только info сообщения и все-все сообщения если при обработке пакета был хотя бы один warning.
Но, надо сказать, что проект сильно не типичный, обычно такого геморроя нет и хватает обычных средств :-)
+1
Хорошая вводная статья. Хотелось бы обратить внимание на еще один, архи-важный момент: логирование в библиотеках отличается коренным образом от логирования в конечном приложении.
В идеале библиотека (коих в приложении может быть больше чем одна штука) не навязывает мне использование какой-либо конкретной реализации логирования, а пользуется нейтральным интерфейсом, оставляя выбор реализации за конечным приложением (именно эту возможность дают SLF4J и динозавр commons logging).
И уж совсем печально видеть порой библиотеки, которые не только берут ответственность в выборе реализации логирования на себя, но вдобавок еще и перенимают на себя всю конфигурацию.
Пожалуйста, избегайте подобные фокусы. Помните, каждый раз, когда вы компилируете такой код, где-то умирает маленький котенок.
В идеале библиотека (коих в приложении может быть больше чем одна штука) не навязывает мне использование какой-либо конкретной реализации логирования, а пользуется нейтральным интерфейсом, оставляя выбор реализации за конечным приложением (именно эту возможность дают SLF4J и динозавр commons logging).
И уж совсем печально видеть порой библиотеки, которые не только берут ответственность в выборе реализации логирования на себя, но вдобавок еще и перенимают на себя всю конфигурацию.
Пожалуйста, избегайте подобные фокусы. Помните, каждый раз, когда вы компилируете такой код, где-то умирает маленький котенок.
+1
Согласен, момент весьма тонкий. К счастью джуниоры (основная аудитория статьи) не часто пишут библиотеки. Да и чего уже там греха таить, в нашей коммерческой практике очень редко (к моему сожалению) приходится писать библиотеки для широкого использования. Честно говоря я вообще ни одного такого проекта не помню.
Да, делать jar для своего же проекта — это часто. А вот так чтобы «для кого-то не знаю для кого и какой у него будет логер» — даже не слышал чтобы у нас кто-то такое заказывал. Увы!
Да, делать jar для своего же проекта — это часто. А вот так чтобы «для кого-то не знаю для кого и какой у него будет логер» — даже не слышал чтобы у нас кто-то такое заказывал. Увы!
+1
Но согласитесь, даже для проектов внутри Вашей организации: сегодня вы знаете, что везде используется java.util.logging, но что будет завтра — этого не знает никто. Вот захочется вам через пару лет 10 кратного перформанса или особой реализации с учетом специфики Java EE или OSGi или что-то еще… а у вас везде JUL.
0
Ну у нас не in-home а outsoursing, так что все достаточно стабильное и относительно короткоживущее. Ну и опять же исходники всегда есть.
Опять же если смотреть правде в глаза в 50% случаев logging framework нам дан как свыше заказчиком. В оставшихся 50% продиктован религиозными предпочтениями тим лида.
Я например всегда исповедовал принцип «делай как проще, все равно рано или поздно жизнь изменится и придется переделывать, а простое переделывать проще и не так обидно».
Опять же если смотреть правде в глаза в 50% случаев logging framework нам дан как свыше заказчиком. В оставшихся 50% продиктован религиозными предпочтениями тим лида.
Я например всегда исповедовал принцип «делай как проще, все равно рано или поздно жизнь изменится и придется переделывать, а простое переделывать проще и не так обидно».
0
The Simple Logging Facade for Java or (SLF4J) -> s/SL4J/SLF4j/g
0
Статья неплохая, но увы! — в ней разбираются только простейшие практики организации и настройки логирования. При этом за кадром остались, возможно, самые принципиально важные вещи: что, когда и как логировать.
Было бы очень интересно, например, узнать опыт DataArt в части
— шаблонов строк лога (чтобы grep-апь потом было легче)
— правил, регламентирующих обязательность логирования того или иного (например, исключения должны попадать в лог всегда или только при каких-то определенных обстоятельствах)
— взаимоотношения try-catch-throw и практик ведения логов (например, логировать ли что-нибудь при перевыбросе исключений)
— подходов к разруливанию «вложенного логирования» (когда часто используемый метод-утилита что-то логирует, и это иногда помогает, а иногда мешает)
— одновременного ведения нескольких логов (разбиваемых, например, по уровню) — хорошо это или плохо, помогает или нет и т.п.
— вопросов синхронизации лога на клиентской и серверной сторонах приложения
ну и других подобных аспектов.
Было бы очень интересно, например, узнать опыт DataArt в части
— шаблонов строк лога (чтобы grep-апь потом было легче)
— правил, регламентирующих обязательность логирования того или иного (например, исключения должны попадать в лог всегда или только при каких-то определенных обстоятельствах)
— взаимоотношения try-catch-throw и практик ведения логов (например, логировать ли что-нибудь при перевыбросе исключений)
— подходов к разруливанию «вложенного логирования» (когда часто используемый метод-утилита что-то логирует, и это иногда помогает, а иногда мешает)
— одновременного ведения нескольких логов (разбиваемых, например, по уровню) — хорошо это или плохо, помогает или нет и т.п.
— вопросов синхронизации лога на клиентской и серверной сторонах приложения
ну и других подобных аспектов.
0
Таки да, это такая специальная статья в которой разбираются только основы. Ибо такой специальной статьи от других авторов я найти не смог, все норовят матрицу логеров разобрать или еще что-то такое замороченное.
Нам была нужна простая статья про простые вещи. Вот она.
Нам была нужна простая статья про простые вещи. Вот она.
0
Возможно то, о чем я упомянул, — это не самые «простые вещи», но определенно необходимые любому новичку (да и не только), потому что с ними он столкнется ровно в тот самый момент, как только начнет использовать логгер.
Понимаю, что такую готовую статью найти трудно — потому и поинтересовался опытом DataArt. :)
Понимаю, что такую готовую статью найти трудно — потому и поинтересовался опытом DataArt. :)
0
Странно что никто ещё не написал. Сообщение об ошибке всегда должно быть осмысленным. Нельзя писать
Это то же самое что писать комментарии в стиле
То что это Exception и так видно, что именно сломалось-то не понятно! Реальность такова, что в проектах всегда есть Exception'ы и когда что-то сломалось нужно уметь отделить в логе те, которые имеют отношение к поломке. Сравните, Вы видите в логе
Относится ли это к проблеме, ради которой Вас разбудили в 4 утра? И сравните с таким логом:
Сразу понятно какая из строк относится к проблеме «всё сломалось, сайт не работает», не так ли?
} catch (Exception ex) {
log.log(Level.SEVERE, "Exception: ", ex);
}
Это то же самое что писать комментарии в стиле
// Create new long varibale and assign current timestamp to it
Long time = new Long(System.currentTimeMillis());
То что это Exception и так видно, что именно сломалось-то не понятно! Реальность такова, что в проектах всегда есть Exception'ы и когда что-то сломалось нужно уметь отделить в логе те, которые имеют отношение к поломке. Сравните, Вы видите в логе
ERROR 2011-10-13 16:43:56,643 [ProxyUtils] Exception: NumberFormatException
Относится ли это к проблеме, ради которой Вас разбудили в 4 утра? И сравните с таким логом:
ERROR 2011-10-13 16:43:56,643 [ProxyUtils] Failed to parse user's input: NumberFormatException
ERROR 2011-10-13 16:43:56,648 [ProxyUtils] Failed to load proxy configuration: NullPointerException
Сразу понятно какая из строк относится к проблеме «всё сломалось, сайт не работает», не так ли?
0
Only those users with full accounts are able to leave comments. Log in, please.
Логирование в Java / quick start