Java logging

вступ

Думаю, ні для кого не секрет, що таке логгер і для чого вони потрібні. За час існування java було створено чимало фреймворків логгірованія. Серед найвідоміших можна виділити:

  • JUL - java.util.logging
  • log4j
  • JCL - jakarta commons logging
  • Logback
  • SLF4J - simple logging facade for java

System.err.println

Java.util.logging

Даний фреймворк включений в стандарт і поставляється разом з JDK, тому нічого додатково завантажувати і підключати вам не треба. JUL має такі рівні логгірованія по зростанню: FINEST, FINER, FINE, CONFIG, INFO, WARNING, SEVERE, а так само ALL і OFF, що включає і відключає всі рівні відповідно.
Логгер створюється викликом одного з статичних методів класу java.util.logging.Logger:

Методи Логгер можуть приймати в якості аргументів рядкові повідомлення, шаблони повідомлень, виключення, ресурси локалізованих текстовок повідомлень, а також, починаючи з Java 8, постачальників строкових повідомлень:

Виділяється дві групи методів: назва яких відповідає рівню логгірованія і методи log, loggp, logrb, які беруть рівень логгірованія як параметр з типом Level. Перша група містить методи двох типів: приймають строкове повідомлення або постачальника строкових повідомлень:

Друга група методів має наступні варіації:

Тепер звернемося до конфігурації фреймворка. За замовчуванням JUL буде виводити повідомлення на консоль, однак можна задати конфігурацію у файлі властивостей. Для завдання способу виведення повідомлень необхідно для вашого Логгер вказати які Хендлер він буде використовувати. Існує наступні класи хендлеров: FileHandler, ConsoleHandler, StreamHandler, SocketHandler, MemoryHandler. Особливістю JUL є те, що налаштування хендлеров задаються в цілому для всього класу, а не для конкретного екземпляра, що може породжувати багато проблем, наприклад якщо вам буде потрібно повідомлення різних логгерів виводити в різні файли або з різним форматуванням. Розглянемо простий приклад конфігураційного файлу:

Для того що б JUL застосував дану конфігурацію потрібно передати параметр -Djava.util.logging.config.file = <путь до файла>, або при старті додатка виконати код:

Даний фреймворк на поточний момент має вже другу версію, яка на жаль не сумісна з першої. Оскільки перша версія 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 виглядають так:

Якщо не визначити конфігурацію, то при запуску log4j2 видасть гнівне повідомлення, про те, що конфігурація не задана і друкуватиме ваші повідомлення на консоль рівнем не нижче ERROR. Конфігурація log4j2 задається кількома варіантами: xml, json, yaml. Варто відзначити, що з другої версії немає підтримки конфігурації з property файлу. Файл з конфігурацією автоматично шукається classpath, повинен мати назву log4j2 і розташовуватися в пакеті за замовчуванням.
Конфігурація 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

Варто також зауважити, що log4j може створювати безліч розрізняються аппендеров одного і того ж класу, наприклад кілька файлових аппендеров, які пишуть в різні файли.
Розглянемо приклад конфігурації, в якій оголошено два Логгер (кореневої і для нашого класу), перший з яких пише в файл log.log, а другий пише в log2.log з використанням фільтрації по маркеру:

Commons-logging

Досить старий проект, який представляє собою обгортку над JUL і log4j, що не привносить ніякого додаткового функціоналу. Рівні логгірованія у JCL збігаються з log4j, а в разі взаємодії з JUL відбувається наступне зіставлення:

Для використання JCL підключаємо commons-logging-1.x.jar. Створюємо логгер викликом методу фабрики:

Методи JCL дуже прості, збігаються з назвою рівнів логгірованія, приймають тільки об'єкти і виключення і мають дві варіації:

Конфігурація JCL містить окремі блоки для log4j, JUL і власної реалізації. Якщо не поставити конфігурацію, то використовується власна реалізація, іменована SimpleLog, яка виводить повідомлення на консоль. Розглянемо приклад конфігураційного файлу:

Вказати файл конфігурації JCL можна наступним чином:

Даний фреймворк використовується тільки в зв'язці з обгорткою SLF4J, яку ми будемо розглядати пізніше. Для початку роботи вам необхідні logback-core-1.x.jar і logback-classic-1.x.x.jar. а також slf4j-api-1.x.x.jar.
Взаємодія з логгером ми будемо здійснювати через API надається обгорткою SLF4J. Рівні логгірованія збігаються з log4j. Створення Логгер в такому випадку виглядає наступним чином:

API дозволяє виводити рядкові повідомлення, шаблони строкових повідомлень, виключення, а також використовувати маркери:

Назви методів збігаються з рівнями логгірованія і мають вигляд:

Тепер розглянемо безпосередні функціонал logback. Конфігурація шукається в classpath в наступному порядку:

  1. Намагається знайти logback.groovy
  2. Інакше намагається знайти logback-test.xml
  3. Інакше намагається знайти logback.xml
  4. Інакше використовує базову конфігурацію - виводимо повідомлення на консоль

Основними елементами конфігурації є логгер, аппендери, лайаути, і фільтри.
Є такі фільтри:

  • Regular filters
  • LevelFilter
  • ThresholdFilter
  • EvaluatorFilter
  • Matchers
  • TurboFilters
  • CountingFilter

Є такі аппендери:

  • OutputStreamAppender
  • ConsoleAppender
  • FileAppender
  • RollingFileAppender
  • SocketAppender and SSLSocketAppender
  • ServerSocketAppender and SSLServerSocketAppender
  • SMTPAppender
  • SyslogAppender
  • SiftingAppender
  • AsyncAppender

Про те що таке Layouts і Encoders в logback пропоную прочитати докладно в документації, а зараз лише наведу простий приклад файлу logback.xml:

Як вже говорилося раніше SLF4J є обгорткою над logback, а також над JUL, log4j, або JCL, а також над будь-яким логгером, який реалізує її інтерфейс. Для роботи з SLF4J потрібні бібліотека slf4j-api-1.x.x.jar і реалізація одного з логгерів або заглушка. Як правило реалізації всіх логгерів (крім logback) поставляються разом з SLF4J і мають назви типу slf4j-jcl-1.x.jar, slf4j-log4j12-1.x.jar, slf4j-nop-1.x.jar і т. п. Якщо в classpath не приймете реалізація Логгер (або заглушка nop) SLF4J гнівно ругнется і працювати відмовиться. Конфігурація відповідно буде шукатися в залежності від покладеної в classpath реалізації.
API SLF4J ми розглянули в попередньому пункті, тому давайте розглянемо ще одну можливість обгортки. В ідеальному світі ми повинні виводити повідомлення через інтерфейс обгортки, і тоді у нас все буде добре, але реальний жорстокий світ говорить про те, що всім нам доводиться взаємодіяти зі сторонніми бібліотеками або кодом, в яких використовуються інші логгер і які знати не знають про SLF4J . Що б не підлаштовуватися під кожен логгер, а пустити всі повідомлення через одну реалізацію інтерфейсу SLF4J, можна використовувати bridging. У постачання обгортки міститися бібліотеки jcl-over-slf4j.jar, log4j-over-slf4j.jar і jul-to-slf4j.jar, які скасовують поведінку відповідних логгерів і перенаправляють повідомлення в обгортку.
Що б стало зрозуміліше вище сказане, розглянемо приклад. Припустимо у нас є такі логгер:

Ми хочемо, що б повідомлення від JUL записувалися в один файл, від log4j в інший, а від slf4j виводилися на консоль. Як реалізації обгортки будемо використовувати logback, конфігурація цього неподобства буде виглядати наступним чином:

Для того, що б міст запрацював необхідно виконати код:

Хочу дізнатися більше

висновок

На закінчення хотілося б вам сказати, що кінцевий вибір фреймворку логгірованія залишається завжди за вами, але до цього треба підходити розсудливо. Вибір повинен обумовлюватися задоволенням багатьох критеріїв, як висока продуктивність, зручний API, наявність потрібних способів зберігання логгіруемих даних, так і специфікою ваших проектів, наприклад, якщо ваш продукт буде використовуватися в інших проектах, то не варто вирішувати за користувача яким логгером йому доведеться користуватися, а в місце цього віддати перевагу обгортці.

Схожі статті