Log4j не пишет в файл
Все выглядит правильно для меня, так что происходит? Должен ли порог DEBUG также записывать INFO logging?
Хорошо, поэтому я заработал, изменив это
Очевидно, вам нужно сначала указать уровень ведения журнала на rootLogger ? Прошу прощения, если я потратил впустую любое время.
Кроме того, я решил ответить на собственный вопрос, потому что это не проблема с classpath.
Это происходит, когда файлы конфигурации по умолчанию log4j.properties и log4j.xml не могут быть найдены, и приложение не выполняет явной конфигурации. log4j использует Thread.getContextClassLoader(). getResource() для поиска файлов конфигурации по умолчанию и напрямую не проверяет файловую систему. Знание соответствующего места для размещения log4j.properties или log4j.xml требует понимания стратегии поиска используемого загрузчика классов. log4j не предоставляет конфигурацию по умолчанию, поскольку вывод в консоль или файловая система может быть запрещен в некоторых средах. Также см. Часто задаваемые вопросы. Почему log4j не может найти мои свойства в приложении J2EE или WAR?
Файл конфигурации не найден. Вы используете xml или файл свойств?
Кроме того, используйте logback!
Если вы столкнулись с ошибкой/предупреждением при запуске программы, использующей log4j, решение должно добавить log4j.properties, который можно увидеть загрузчиком классов. Обычно это в папке “src” вашего Java-проекта:
Добавьте в файл следующее содержимое
Попробуйте сделать что-то вроде следующего в основном:
вам нужно указать log4j, какой должна быть его конфигурация.
в вашем статическом основном классе, как показано ниже.
Примечание:
добавьте “\ hadoop-2.7.1\share\hadoop\common\lib\commons-logging-1.1.3.jar и
\ hadoop-2.7.1\share\hadoop\common\lib\log4j-1.2.17.jar ”
как внешние ссылки
Чтобы добавить к @Gevorg, если у вас есть аналогичная ситуация, выполняющая Spark локально, поместите файл log4j.properties в папку с именами ресурсов в основной папке.
Что сработало для меня, так это создать файл свойств log4j (вы можете найти много примеров по сети) и поместить его в папку свойств в каталоге проекта (создайте эту папку, если не exicts). Щелкните правой кнопкой мыши папку и Build Path->Use as Source Folder .
Надеюсь, что это поможет!
Исправление для меня заключалось в том, чтобы поместить “log4j.properties” в папку “src”. Он не работал в моей папке пакета, и он должен быть одним из корней источника. Добавление его в путь сборки, который затем перемещает его в “Справочные библиотеки”, также не сработало.
Повторить: поместите log4j.properties в корень вашей папки src.
Мои файлы log4j.properties имеют следующий контент, который работает с последней версией Spring Tool Suite, основанной на Eclipse.
Я думаю, практически в каждой программе есть логгирование. Более того, в ряде уже неновых приложений (а значит с морем нетривиальных условий) зачастую логи становятся жизненно важными на боевом сервере.
Самая распространенная ошибка (по моим наблюдениям) — это небрежность по отношению к мелким выделениям памяти возле места вызова функции log.Debug(. ) .
Мне во многом встречались только библиотеки log4net и NLog, а потому я буду использовать в примерах именно них.
- В каких строчках будет выделяться память даже если Debug выключен?
- Если память выделяется, то насколько легко обнаружить в том же dotTrace, что конкретно логгеры виной этому самому выделению памяти?
Однако, давайте пройдемся по техническим деталям, чтобы понять, где именно у нас будет влияние на производительность.
Итак, первый пункт:
На деле компилятор преобразует её в:
То есть первое выражение по сути будет заставлять процессор создавать строку, передавать её в логгер. Он же быстро проверит, что логгировать не надо, а потому строка просто создалась в памяти. И, что важно, если побольше раскопировать такой код, то строки будут создаваться в кучи мест программы, то есть программа будет работать просто немного медленнее. Везде.
Второй пример чуть более эффективный, так как в нем строка не создается:
Однако память здесь всё равно выделяется, так как будет происходить boxing. Напомню сигнатуру метода DebugFormat:
Как видно, на вход требуется ссылочный тип. Однако мы пытаемся передать значимый тип int . В итоге каждый вызов будет приводить к вынесению параметра id в кучу, чтобы передать его в метод. И напомню, в самом методе параметр не нужен, так как Debug у нас выключен по условию задачи.
Следующий пример нагруженный и простой:
Я уверен, что вы уже поняли, что опять строка будет выделяться в куче и так далее. Потому сразу пропустим этот пример. Следующий способ вызова выглядит более эффективным:
И это так, однако давайте подсчитаем, сколько раз надо выделить по кусочку памяти:
В итоге довольно типичный вызов операции логгирования приведет к созданию кучи объектов в памяти. Что довольно обидно, так как само логгирование-то зачастую выключается. Однако перейдем к NLog.
Эта строка спровоцирует выделение объекта в куче:
Здесь всё очевидно, однако строка ниже уже не обладает таким недостатком:
А причина в том, что NLog имеет специальную сигнатуру для int'ов: void Debug(string message, int argument) . Более того, даже если передать другую структуру, то вызовется метод void Debug([Localizable(false)] string message, TArgument argument) . И вот этот метод не требует уже боксинга, так как после JIT будет создаваться отдельная функция для каждого типа (конечно, это не совсем так, однако важна суть: боксинга не будет).
Я пропустим простой в понимании сценарий с большой строкой на входе и перейдем сразу к:
Как ни странно, в NLog не увеличивали число Generic параметров для методов, а потому будет использована сигнатура: void Debug([Localizable(false)] string message, params object[] args) . И она опять приведет к созданию объектов в кучи и так далее.
Пример из Kotlin
И он будет преобразован компилятором в подобие такого:
Здесь важно: всё, что внутри фигурных скобок возле debug — это лябмда. Однако она будет встроена в ваш метод, то есть в кучи не будет создан объект-функция. Таким образом, можно прятать большие операции внутри, которые будут вызван только если требуется сделать вывод результата в debug . Например:
В дополнении к предыдущему примеру. Я уверен, что многие знаю, что в .Net/JVM есть понятие "Large Object Heap". Точнее, в Java нет специального определения, однако аллокаторы зачастую будут создавать большие объекты сразу в последнем поколении (чтобы минимизировать перемещение объектов и нивелировать проблему быстрого пробития памяти для потокового аллокатора).
Вернемся к примеру:
Как Вы понимаете, если объект id имеет реализацию ToString , которая создает строку размером в мегабайт, то на лицо следующие попадания в LOH:
- Сам вызов ToString
- Форматирование $"Id="
- А если разработчики логгера не отловили все подобные вещи (а крайне сложно написать тест на отсутствие объектов в LOH), то логгер еще добавит проблем.
И здесь можно пользоваться тремя способами логгирования подобных вещей:
Как-то раз в одной программе я заметил, что во время нагруженных операций порядка половины времени ожидания UI приходилось на операции логгирования. Еще раз: половина времени работы программы уходило на вызов logger.Debug или что-то в этом духе. А причина в этом проста: мы использовали log4net, который умеет писать файлы только синхронно.
Отсюда я вывел правило 1: логгер всегда должен работать в другом потоке. Вы не должны блокировать код приложения ради трейсов, ибо это невероятно странно. Другими словами — используя NLog — всегда необходимо проставлять async=true в теге nlog (он главный). Или, как сказано в примере:
Если Вы используете log4net — то или сделайте перенаправление с него на NLog, или же сделайте AsyncFileAppender.
Для Java мира: и Logback и Log4J2 имеют возможности делать асинхронное логгирование. Вот сравнение с официального сайта:
Однако когда у вас всё пишется асинхронно, то возникает другая проблема — а что делать в случае критических ошибок? Ведь бывает такое, что программа завершает работу не потому, что вышли из потока Main (например, программа может завершиться путем вызова Application.Exit или Environment.FailFast , что не очень красиво, однако встречается). В этом случае необходимо всегда вызывать Flush перед тем, как убить свой процесс. Иначе при падении на боевом сервере самая ценная информация будет упущена.
Я надеюсь, эта статья поможет писать быстрые программы с удобным логгированием. Я подсветил только часть проблем, которые я часть вижу в коде. Все они не самые очевидные, однако и не самые сложные.
В любом случае, как я уже говорил в начале, работа с логгерами есть практически каждом приложении. Более того, по моим заметкам, порядка половины классов сами выводят что-то в лог. Таким образом, правильная работа с этими функциями влияет практически на всё приложение целиком.
Думаю, ни для кого не секрет, что такое логгеры и для чего они нужны. За время существования java было создано немало фреймворков логгирования. Среди самых известных можно выделить:
- JUL — java.util.logging
- log4j
- JCL — jakarta commons logging
- Logback
- SLF4J — simple logging facade for java
System.err.println
Первым и самым примитивным способом логгирования был метод System.err.println. Думаю, комментарии излишние, достаточно взглянуть на приведенный ниже код:
Commons-logging
Довольно старый проект, который представляет собой обертку над JUL и log4j, не привносящая никакого дополнительного функционала. Уровни логгирования у JCL совпадают с log4j, а в случае взаимодействия с JUL происходит следующее сопоставление:
Для использования JCL подключаем commons-logging-1.x.jar. Создаем логгер вызовом метода фабрики:
Методы JCL очень простые, совпадают с названием уровней логгирования, принимают только объекты и исключения и имеют две вариации:
Указать файл конфигурации JCL можно следующим образом:
Log4j
Данный фреймворк на текущий момент имеет уже вторую версию, которая увы не совместима с первой. Поскольку первая версия log4j существует достаточно давно и, в виду ее большой популярности, существует не мало статей на просторах интернета, сегодня мы рассмотрим вторую. Для использования log4j2 вам необходимо подключить библиотеки log4j-api-2.x и log4j-core-2.x. Log4j имеет несколько отличное от JUL именование уровней логгирования: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, а так же ALL и OFF включающий и отключающий все уровни соответственно.
Логгер создается вызовом статического метода класса org.apache.logging.log4j.Logger:
Логгер умеет принимать помимо привычных нам String, Object и Throwable еще два новых типа — MapMessage и Marker:
В классическом для логгеров стиле методы делятся на два типа: совпадающие с названием уровня логгирования и методы log, принимающие уровень логгирования в качестве параметра. Первые имеют вид:
Методы log в log4j2 выглядят так:
- BurstFilter
- CompositeFilter
- DynamicThresholdFilter
- MapFilter
- MarkerFilter
- RegexFilter
- StructuredDataFilter
- ThreadContextMapFilter
- ThresholdFilter
- TimeFilter
- AsyncAppender
- ConsoleAppender
- FailoverAppender
- FileAppender
- FlumeAppender
- JDBCAppender
- JMSAppender
- JPAAppender
- MemoryMappedFileAppender
- NoSQLAppender
- OutputStreamAppender
- RandomAccessFileAppender
- RewriteAppender
- RollingFileAppender
- RollingRandomAccessFileAppender
- RoutingAppender
- SMTPAppender
- SocketAppender
- SyslogAppender
Ответы 2
Хорошо, спасибо. К сожалению, не получилось. Я уже пробовал некоторые другие настройки, но безуспешно
Единственное, что я могу предложить, это включить -Dlog4j2.debug . Там может быть что-то, что может помочь.
Есть несколько проблем со свойствами, которые вы определили. Я постараюсь объяснить каждый из них один за другим. Тем не менее, вы должны вернуться к руководство log4j2 по настройке свойств и сделать свой собственный исследовательская работа, чтобы найти примеры, в которых используются свойства log4j2, или другие вопросы, касающиеся свойств log4j2, которые помогут вам, когда вы застряли, и включить эту информацию в свой вопрос.
Вы сказали, что в консоли отображаются только уровни ошибок и фатальных ошибок. Это связано с тем, что вы не определили корневой регистратор. Как в руководстве log4j2 состояния:
Every configuration must have a root logger. If one is not configured the default root LoggerConfig, which has a level of ERROR and has a Console appender attached, will be used.
Поскольку аддитивность по умолчанию имеет значение true , и вы не отключили его, все события журнала отправляются в корневой регистратор по умолчанию, как указано выше. В результате на консоли регистрируются только те события, которые являются ошибками или фатальными, поскольку уровень корневого регистратора по умолчанию — ERROR .
Теперь, что касается конфигурации ваших свойств, вот проблемы:
Ваши файловые приложения имеют недопустимые атрибуты «MaxBackupIndex», «MaxFileSize». Следующие две строки неприменимы к файловому приложению:
Если вы используете log4j2 версии 2.6 или выше, вам не нужны эти строки:
appenders = console, user, system
Вы не указали, какую версию вы используете, поэтому я предположил, что вы используете последнюю версию, и в этом случае эти строки не нужны. Я прокомментировал и эти строки.
Оба ваших приложения используют одно и то же имя «LOGFILE». Я изменил имя пользовательского приложения на «userLog», а имя системного приложения на «systemLog». (см. полные свойства позже в ответе)
Вы определили только один регистратор, и его имя не соответствует имени, которое вы используете для его извлечения. Вот почему все ваши события журнала отправляются в корневой регистратор по умолчанию. У вас есть logger.file.name = de.pares.int_plan , но de.pares.int_plan не является одним из имен, которые вы использовали в своем Java-коде для получения регистратора. Вы использовали user и system . Я исправил их в свойствах (см. полные свойства позже в ответе).
Вам не хватает «%» перед c в шаблоне обоих файловых приложений.
У вас есть дополнительная строка в определении регистратора logger.file.appenderRefs = file , которая кажется ненужной, исходя из примера в руководство log4j2.
Объединив все эти исправления, я пришел к следующим свойствам:
Чтобы протестировать эту конфигурацию, я использовал следующий код:
Результатом являются два лог-файла:
системный журнал
user.log
и вывод консоли:
Чтобы полностью понять вывод консоли, обратитесь к руководству по log4j2 — раздел под названием Аддитивность.
Тебе прям по ссылке написано
This occurs when the default configuration files log4j.properties and log4j.xml can not be found and the application performs no explicit configuration. log4j uses Thread.getContextClassLoader().getResource() to locate the default configuration files and does not directly check the file system. Knowing the appropriate location to place log4j.properties or log4j.xml requires understanding the search strategy of the class loader in use. log4j does not provide a default configuration since output to the console or to the file system may be prohibited in some environments.
Такие вещи надо настраивать по документации, а не по ссаным бложикам
Нутак ёпрст, конечно читал! Но тут попробуй пойми: Это происходит, когда файлы конфигурации по умолчанию log4j.properties и log4j.xml не могут быть найдены, и приложение не выполняет явной конфигурации. log4j использует Thread.getContextClassLoader (). getResource () для поиска файлов конфигурации по умолчанию и напрямую не проверяет файловую систему. Где эти Thread.getContextClassLoader (). getResource () в томкат? К тому же в ..tomcat/conf/catalina.properties где:
common.loader=«$/lib»,«$/lib/*.jar»,«$/lib»,«$/lib/*.jar»
И так папка где лежит log4j.properties используется как место подгрузки данных из находящихся там файлов.
Не, ну может я не там вычитал это, подправь если знаешь как правильно. Я с tomcat пока на ВЫ и в поиске у всех «ссаных бложников» :)))))))))))))) - наверное работает сразу если ничего не пишут такого.
Я подозреваю, что это решение подходит для java программистов, для tomcat нигде не нашёл как решать!
Обычно больше интересуют приложения, которые развернуты в томкате, которые лежат в webapps. Томкат сам использует модифицированные логи на основе apache-logging.
Я могу предположить, что интересуют логи приложения, которое использует log4j. Положи свой конфиг в webapps//WEB-INF/classes и перезапусти томкат. Если папки classes нет, то создай её.
Вот, кстати, да — именно WEB-INF/classes.
Но поскольку сайт вообще-то про Linux, то я бы посоветовал ещё очевидное strace 2>&1 | grep log4j | grep ENOENT
Хочу узнать больше
- JUL — читать Java Logging: Logger и Java Logging: Configuration
- Log4j2 — читать Welcome to Log4j 2
- JCL- читать How to use Commons Logging
- Logback- читать The logback manual
- SLF4J — читать SLF4J documentation и Bridging legacy APIs
Выводы и улучшения
Главный вывод: если у вас в программе есть много вызовов методов логгирования, которые не приводят к физической записи в файл, то Вы можете на ровном месте начать выделять немало ненужных объектов в куче. И тем самым затормаживая работу программы.
Вывод 2: Если Вы передаете не так много объектов в метод, то используйте NLog. За счет того, что в нем позаботились о Generic параметрах, можно быть более спокойным о производительности.
Однако, чтобы уж совсем обезопаситься, логичнее делать так:
Здесь метод логгирования не будет вызываться, если это не надо. Однако, если всё-таки придется сбросить данные в лог, то тогда будет использован удобный String Interpolation. Внутри логгеры (по крайне мере тот же NLog) имеют оптимизацию, чтобы записывать строку в логи напрямую (т.е. форматирование будет происходить сразу в Stream , вместо создания строки в памяти). Однако эта оптимизация NLog'а меркнет с тем, что придется делать сброс данных в файл.
Заключение
В заключение хотелось бы вам сказать, что конечный выбор фреймворка логгирования остается всегда за вами, но к этому надо подходить здраво. Выбор должен обуславливаться удовлетворением многих критериев, как высокая производительность, удобный API, наличие нужных способов хранения логгируемых данных, так и спецификой ваших проектов, например, если ваш продукт будет использоваться в других проектах, то не стоит решать за пользователя каким логгером ему придется пользоваться, а в место этого отдать предпочтение обертке.
Я хочу хранить журналы в двух разных файлах. С одной стороны у меня логи не пишутся в файлы, а файлы создаются а с другой стороны в консоли отображаются только "ошибка" и "фатальные" -уровни. файл свойств:
Вот как я создаю регистраторы:
Используйте их так:
что я делаю не так?
JavaScript (Js) - это язык программирования, объединяющий HTML и CSS с одной из основных технологий Всемирной паутины. Более 97% веб-сайтов используют.
Java.util.logging
Данный фреймворк включен в стандарт и поставляется вместе с JDK, поэтому ничего дополнительно скачивать и подключать вам не надо. JUL имеет следующие уровни логгирования по возрастанию: FINEST, FINER, FINE, CONFIG, INFO, WARNING, SEVERE, а так же ALL и OFF, включающий и отключающий все уровни соответственно.
Логгер создается вызовом одного из статических методов класса java.util.logging.Logger:
Вторая группа методов имеет следующие вариации:
Для того что бы JUL применил данную конфигурацию нужно передать параметр -Djava.util.logging.config.file = , либо при старте приложения выполнить код:
SLF4J
Для того, что бы мост заработал необходимо выполнить код:
Logback
Данный фреймворк используется только в связке с оберткой SLF4J, которую мы будем рассматривать позднее. Для начала работы вам необходимы logback-core-1.x.jar и logback-classic-1.x.x.jar, а также slf4j-api-1.x.x.jar.
Взаимодействие с логгером мы будем осуществлять через API предоставляемый оберткой SLF4J. Уровни логгирования совпадают с log4j. Создание логгера в таком случае выглядит следующим образом:
Названия методов совпадают с уровнями логгирования и имеют вид:
Читайте также: