Pull to refresh

Comments 89

UFO just landed and posted this here
Обратная совместимость же, не могут (в 1.2.х во всяком случае)
UFO just landed and posted this here
Обратная совместимость здесь с Java 1.4 в которой нет varargs.
UFO just landed and posted this here
А если мне надо 20 параметров передать? 20 методов делать? Нафиг нафиг. Лучше уж что-нибудь типа info(String format, Object[] args) — но всё равно неудобно.
UFO just landed and posted this here
Да тут пол статьи о том, что вышло в результате принятия неудачного API, которое вошло в стандарт и породило кошмар. Пять методов(а на самом деле это ещё надо помножить на кол-во уровней логирования) делающих одно и то же только с разным кол-вом параметров — это костыль, а не решение. И в публичной библиотеке такое недопустимо.
UFO just landed and posted this here
Спорить совсем не хочется(хотя хотелось, но литр жигулевского сделал своё дело :) ). IMHO, самое главное в библиотеке — это её интерфейс, а для библиотек которыми пользуются тысячи разработчиков по всему миру тем более. Хороший API — библиотека имеет шансы. Плохой API — библиотека плоха, независимо от её реализации. А добавление кучи методов делающих по сути одно и тоже никак нельзя назвать хорошим интерфейсом.
Вполне можно, по-моему, если таким образом использовать ее становится удобно. Не вижу проблемы. Двадцать аргументы передать — во-первых, тут уж будьте добры, воспользуйтесь массивом, а во-вторых, вам правдо случалось двадцать аргументов в лог-строку передавать? Я имею в виду, не «а что если», а вот на самом деле, по-настоящему?
кстати slf4j так и делает
Жалко, что loj4j не развивается. По мне он достаточно удобный и простой. Да и как уже было сказано antelle, его портированная версия для .NET уже достаточно хорошо развилась (а еще и NLog, как его аналог). Поэтому мне хотелось бы дальнейшего развития log4j, вместо того, чтобы переходить на что-то другое.
как ни странно, он хорошо прижился на Питоне
Логгирование — «ахилесова пята» более половины проектов на Java. Зачастую некоторые IDE — типа Netbeans при генерации блоков (try/catch и т.п.) автоматически пуляют туда логгирование с помощью JUL и так оно и остается в коде, при не внимательности.
Да бросьте вы про невнимательность, вы что код совсем не читаете который среда генерит?
А Вы в команде не работали никогда? Когда потом подчищать код по всем классам.
Я не против авто генерации разных блоков, конструкторов и т.д., но не люблю когда среда навязывает какое то поведение.
И да, я это отключаю в в шаблонах генерации.
Работаю. Самого раздражает.
Предлагаю читать предыдущий комментарий в ключе: «Руки отрывать надо тому, кто такое оставляет в своем коде»
Спасибо. Очень интересно было прочитать историю. В целом, любая компания, где разработчики не являются цельной командой эта история в миниатюре повторяется. В нашей компании в результате несколько лет назад все-таки признали log4j стандартом de-facto, и споры хотя бы относительно этой библиотеки прекратились. Да, есть масса ньюансов использования. Шишки набивались долго. Но в целом удобно и юзабельно
А я помню жуткие времена, когда все писали свои обертки. У каждой компании была своя обертка и свой log viewer. По-моему, это был где-то 2001 год.
Практически каждый разработчик участвовал в «изобретении велосипеда» :). Наиболее частые примеры — это своя реализация списка, вектора и системы логирования. На прежнем месте работы я попробовал «заменить» систему логирования разработанную и развиваемую одним из ведущих разработчиков на log4cxx.

Предложенный вариант снисходительно игнорировался и то, что в нем уже давно было реализовано и легко настраивалось через log4cxx.properties, изобреталось в собственной разработке снова и снова. Поэтому я, чтобы не создавать зоопарк разных реализаций библиотек логирования, отказался там от использования log4cxx. Но в остальных проектах где я принимаю архитектурные решения — использую log4cxx, log4j, log4net. Схожая реализация упрощает понимание применения библиотек логирования c разными языками программирования.
Ну у нас один программист попался, который писал с нуля отправку mail по спецификациям, свой http клиент по спецификациям… о системе логирования уже молчу. Есть и человек, который не признавал ничего готового а все писал сам, потому что запоминать свое проще. У него есть либа метров на 10, которая ходит по его проектам.
А вообще, любой программист, при поверхностном изучении почти любого фреймворка, выбирает ряд типовых задач, которыми он будет пользоваться и старается написать оберточку вокруг этих задач, чтобы все делалось желательно одним методом и без ошибок вылетающих дальше по стеку.
Каждый программист за свою жизнь должен написать тетрис, систему логирования и XML парсер :)
А ещё систему веб-шаблонов
0 из 3 :-) видимо, жить мне еще предстоит до-олго )
Тут бы еще упомянуть довольно корявую реализацию логгирования в Eclipse (при разработке plugins или RCP Application). C одной стороны — вроде как есть уже что-то готовое и тянуть еще-одну-либу log4j нет смылса, с другой — ILog уж больно страшен.
UFO just landed and posted this here
Думаю, что зря. Что делать, если класс не управляется Guice?
UFO just landed and posted this here
я просто хочу использовать new MyObject(), в таком случае зачем мне сдался весь этот DI?
UFO just landed and posted this here
UFO just landed and posted this here
Скорее это Factory. Описывается в документации log4j:
public class MyApp {

   // Define a static logger variable so that it references the
   // Logger instance named "MyApp".
   static Logger logger = Logger.getLogger(MyApp.class);


и, кстати, это работает ВЕЗДЕ.
UFO just landed and posted this here
По времени log4j был создан когда уже почти загибался проект Avalon с его дурацкими Loggable/LogEnabled.

И не делайте из еды культа :) С таким подходом мне как минимум придется писать следующее:
myObj1 = new MyClass(Logger.getLogger("MyClass"));
myObj2 = new MyClass2(Logger.getLogger("MyClass2"));


Это может быть и гибко, но делать это ВО ВСЕМ приложении весьма утомительно.

Кстати, мне интересно, что нам предложит DI, если мы захотим logger в статическом методе.
UFO just landed and posted this here
>что бы было гибко и не утомительно
Правильно так: Чтобы было гибко И утомительно
UFO just landed and posted this here
я уже написал, что не все классы используют DI.
если для того, что написать строчку в лог, я должен включать мой объект в контейнер DI и перестать использовать конструктор — это называется «утомительно».
UFO just landed and posted this here
Мда. Хабр — это, оказывается, так весело ))))))))
Слушайте, ну возьмите вы исходники какой-нибудь реальной библиотеки, например, Spring или HttpClient и посмотрите, использует ли там кто-нибудь DI. А также обратите внимание на статические методы.
UFO just landed and posted this here
а зачем мне их сравнивать? у меня вот приложение содержит и низкоуровневые компоненты, и бизнес-логику, и статические методы.

вот вы бы сами попробовали написать реальную DI-конфигурацию для логгинга ну хотя бы для 5-10 классов, сами все сразу поймете
UFO just landed and posted this here
Да нет, не аномалия )

Иногда появляются утилитные бизнес-методы этак на 2-7 строчек, и их не привяжешь к какому-либо объекту, т.к. это будет противоречить принципам ООП.

Вот и выделяются в static-методы утилитных классов. Их, конечно, можно пихать в DI, но делать из утилитного класса singleton только для пропихивания logger'а — ИМХО, некрасиво.

А насчет AOP… Ну, не все используют AOP. Из разных соображвений, но иногда полномочий не хватает, чтобы внедрить технологию, приходится использовать то, что есть, с полной отдачей.
UFO just landed and posted this here
Logger.getLogger(MyApp.class);

Имеет неприятный эффект его использование под некоторыми версиями tomcat может вести к тому что у вас не будут выгружаться из памяти классы старого war при горячем редеплое. т.к. логгер будет завязан на этот класс. Лучше писать

Logger.getLogger(MyApp.class.getName());
Спасибо, побольше бы таких статей.
UFO just landed and posted this here
Статья интересная, но вот что меня интересует — а почему JUL то умирает. Успешно использовал в куче проектов ни разу проблем не было. Чем он плох? Я совершенно серьезно спрашиваю.
там целый комплекс проблем.
одна из них навскиду — очень сложно апгрейдить, ведь JUL является частью платформы. В то время как log4j апгрейдится заменой JAR-файла.
м-м-м а зачем апгрейдить? 99% он вполне покрывает.
Мне в голову приходит пожалуй только невозможность сделать
if (log.isEnabled(DEBUG))
{
String txt = composeTimeConsumingLogInfo();
log.debug(txt);
}
может быть миллион причин апгрейдить… наличие бага или уязвимости или какая-то новая фича.
это может быть и пустяк… но в целом слабую функциональность JUL мало что вылечит.

Например, попробуйте там найти Handler для записи в syslog. Его до сих пор нет. А в log4j он присутствует где-то с 2000 года.
Ну так получилось что в syslog мне писать не надо. А если надо то я пожалуй сам могу с log4J содрать.
Я тут наоборот всех своих практикантов ругаю, говорю берите JUL
1. Он уже есть, не увеличивайте сложность сверх необходимого
2. Он простой, у вас будет меньше шансов наколбасить что-то сложное.
ну для практикантов может быть JUL действительно в чем-то лучше.
вообще то, что он «уже есть» наверное, единственный аргумент для его использования
Ну основной point (см пост ниже) в 99% случаев сложное не надо а JUL для простых случаев более чем подходит.
Самое прикольное для serverside быстрота тоже особенно не важна. т.к. на 100% загрузить процессор все равно не реально.
Из продвинутых вещей мне бы было нужен logbag но тащить его если честно не хочется ибо игра не будет стоить свеч
(http://www.theserverside.com/news/thread.tss?thread_id=42243 logBag thread)
Самое прикольное для serverside быстрота тоже особенно не важна. т.к. на 100% загрузить процессор все равно не реально.


logger.info(«x = {}», new Object[]{String.valueOf(x)});
… чё сказать то хотел...:

— Самое прикольное для serverside быстрота тоже особенно не важна. т.к. на 100% загрузить процессор все равно не реально.

использование логинга из примера
— logger.info(«x = {}», new Object[]{String.valueOf(x)});

может не только процессор на 100% но и память ВСЮ отожрать за несколько минут работы сервера, рождая миллионы обьектов.

ЗЫ ..............................+________________
*а что у меня форматирование/html-теги не работают совсем !?
* FireFox + Ubuntu >8-E
*ASCII-artom как то не круто получается
..............................+___________________

public abstract class Debug
{
  public static final void _trace ( final String text )
  {
    System.out.println ( "Trace: " + text );
  }
}
На этапе сборки релизной версии препроцессор (писанный на коленке) попросту выкидывает из кода куски от «Debug._trace (» и до соответствующей закрывающей скобки. Я не претендую на то, чтобы это было эталонным подходом к логированю, но мне этого (чуть понавороченнее, я тут только суть указал) пока хватает за глаза.
Увы при разработки логи мне например нужны в занчительно меньшей степени чем в production.
да и возможность раскидывать по нескольким файлам очень важна
Коллеги а никто не помнит как назывался логгер который умел logBags. Было это примерно так

Message msg = receiveMessage
LogBag bag = log.getBag(msg.phoneNumber);
дальше я препарирую message логируя с уровнем debug и соответственно в лог это не пишется
log.debug(bag,«message body\n»+msg.dumpBytes());
и так далее
НО если возникла ошибка
log.error(bag,«фигня случилась»);
то уже логируется все что относилось к этому bag включая debug
Большое спасибо. Замечательная статья. Жаль, нет кармы, плюсанул бы.
C SLF4J тоже не все сладко. Одно время я практиковал встраивание Jetty в собственное приложение. Приложение могло работать под управлением внешнего сервера Jetty/Resin/Tomcat, а могло и само обслуживать HTTP-запросы. Это очень удобно в некоторых случаях.

Но тут выяснилось, что если моё приложение использует SLF4J, а при этом еще из приложения запускается Jetty, который тоже использует SLF4J, то я лишаюсь журналирования. Даже если я не использую SLF4J напрямую, он может быть задействован в одной из библиотек, например Hibernate, и я таки опять лишаюсь журналирования.

Причину, помнится, я более-менее понял, но так и не понял, кого именно винить: Jetty за его ClassLoader-ы или SLF4J, который оказался недостаточно гибким. Обе точки зрения имеют право на жизнь, а я на всякий случай откатился в стан почитателей Log4J.
да, есть такое — если кто-то подложил свой implementation jar, то он перекрывает все остальное
видимо в jetty не очень разобрались с зависимостями
Там проблема в том, что Jetty строит для запускаемого контекста classpath, в который адаптер SLF4J-Log4J включён дважды. А архитектура SLF4J не позволяет такие трюки, в результате «Class path contains multiple SLF4J bindings». С одной стороный, косяк на стороне Jetty, с другой — SLF4J мог бы быть и подружественнее к такого рода проблемам.

Сегодня с удивлением наткнулся еще на одну проблему. Приложение использует Hibernate, а тот использует SLF4J. При попытке запуска приложения под Resin 4.0.14 сервер на смог подхватить SLF4J и Log4J из каталога WEB-INF. При переносе этих библиотек в [Resin]/lib все запустилось. В Resin 3.1.10 все запускается без проблем. Детально разбираться не стал. По всей видимости, косяк в Resin, в котором SLF4J то добавляют, то убирают.
jetty разве использует log4j? мне казалось, что там logback
что касается Resin, то видимо где-то в рутовых classloader-ах лежит slf4j. что вообще необычно, т.к. Resin очень любит JUL.
Что касается Jetty, я наверное не очень ясно выразился. Подробно проблема описана здесь:

www.rsdn.ru/forum/java/3934217.flat.aspx

А по поводу Resin в одном из issue, касающемся Resin 4.0.12 я нашел такой коммент:

slf4j removed from distribution, since Resin does not depend on it.

Из чего и сделал вывод, что Resin пытались скрестить c SLF4J.

Надо ли говорить, что всё это очень сильно действует на нервы. Платформа Java имеет некоторое количество проблем, из которых Logging — самая серьёзная. Так что правильная тема в статье поднята.
непонятно причем тут опенсорс сообщества, упоминаемое на каждом шагу
Упоминания относятся к Java-open source-сообществу.
статья ведется, словно опенсорсное сообщество прям пользует и определяет что хорошо, а что плохо — хотя это шокапец не верно
Это откуда такое? Там другие механизмы действуют. Но вообще это оффтопик.
Огромное спасибо за статью. Уже очень долгое время:
— использую Log4j,
— матерю java-util-logging,
— тихо ненавижу commons-logging
— побаиваюсь SLF4J.
После прочтения статьи появилось желание попробовать logback. Что и сделаю в ближайшее время.
Про logback не указана, на мой взгляд, важная особенность. Он нативно реализует SLF4J API (команда/спонсор судя по всему одна и та же — QOS.ch). А это значит, что используя «православную» связку SLF4J + logback, обёрток как бы и нет.
Согласен с WFrog, кроме того SLF4J — просто кучка интерфейсов, Logback — просто реализация (нативная), поэтому ставить их в один ряд немного неправильно. Вообще мне больше всего нравится через slf4j и его адаптеры перенаправлять все в Logback, и в своем проекте использовать slf4j. Самый народный вариант и все зависимости логируют свой злам единообразно.
бесконечный «reinvent the wheel». То есть из двух вариантов «доработать существующее» и «сделать свое» всегда выбирался второй.
«Существующее» нередко имеется в виде, уже распухшем почти до уровня мини-ОС, так что в таких случаях «сделать своё» — это ещё и тупо быстрее. К тому же «дорабатывать» — это не брать готовое, по трудозатратам вполне сопоставимо со «сделать своё», и при этом зависеть от выпуска новых версий (и изменения политики лицензирования) чужого продукта.
Ответ на вопрос «подружиться с разработчиками продукта с миллионом пользователей или писать свой, с 0 пользователями» не так однозначен и не только трудозатраты решают. Хотя ссоры в оперсорцовых командах не редкость — тот же ffmpeg распилили вдоль и поперек.
Нельзя сказать, чтобы JSR47 проигрывал в производительности. Местами он обгонял log4j за счет поддержания в памяти специального представления своей конфигурации (что, кстати, одновременно усложняло эту самую конфигурацию). Однако, как выяснилось, JSR47 в обязательном порядке собирал так называемую Caller Information, то бишь «откуда логгируется данное сообщение». Получение Caller Information — операция довольно дорогостоящая, протекает она с использованием Native-кода. Опытные дяди из log4j это знали, поэтому предоставляли эту возможность с оговоркой «лучше не включайте».

Может я не понимаю, но разве это нельзя получить через new Exception().getStackTrace()?
Может я не понимаю, но разве это нельзя получить через new Exception().getStackTrace()?

Можно. Только это метод появился в Java 1.4 :)
Раньше наиболее быстрым был вызов Reflection.getCallerClass(...), но он все равно слишком медленный для логгирования.
1. На мой взгляд наиболее важное преимущество любой сторонней библиотеки логгирования перед JUL- возможность для каждого задеплоенного модуля в контейнере иметь свой собственный лог-файл, а не валить все в одну кучу.

2. Пользую slf4j с адаптерами. При этом если модуль подтягивает зашаренную библиотеку контейнера, то эти (общие) классы или не имеют реализации slf4j- тогда весь логгинг у них теряется, либо, если подложить реализацию в общие библиотеки, будет двойной биндинг. В любом случае логгинг зашаренных классов по модулям уже корректно не растащить. Может кто подскажет решение? (не считая решением тащить все библиотеки с собой)

3. Пользую таки свою обертку с такими вспомогательными вещами как:
    public IllegalStateException getIllegalStateException(String msg, @Nullable Throwable e) {...
        logger.error(msg, e);
        return new IllegalStateException(msg, e);
    }

   public IllegalArgumentException getIllegalArgumentException(...
   ...
   public UserSecurityException getSecurityException(String msg, String user) {
Sign up to leave a comment.

Articles