— А ось ти де! Ти не забув, що у нас сьогодні є ще одна лекція?

— Ні, я тебе шукав. Майже…

— Добре, тоді почнемо. Сьогодні я хочу розповісти тобі про логування.

Лог – це список подій, що відбулися. Майже як «морський журнал» чи «щоденник». Ну, або Твіттер – кому що ближче. А, відповідно, Логер — це об'єкт, за допомогою якого можна вести логування.

У програмуванні прийнято логувати практично все. А в Java - так взагалі все і навіть трохи більше. Справа в тому, що Java-програми - це дуже часто великі серверні програми без UI, консолі і т.д. Вони обробляють одночасно запити тисяч користувачів, і нерідко виникають різні помилки. Особливо, коли різні нитки починають одна одній заважати.

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

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

Чим повніше лог, тим легше відновити послідовність подій і відстежити причини виникнення збою або помилки.

Іноді логи досягають кількох гігабайт на добу. Це нормально.

— Декілька гігабайт? О_о

— Ага. Найчастіше при цьому лог-файли автоматично архівуються, із зазначенням дня – за який день це архів з логом.

— Нічого собі.

— Ага. Спочатку Java не було свого логера, що призвело до написання декількох незалежних логерів. Найпоширенішим з них став log4j.

Через кілька років, у Java все ж таки був доданий свій логер, але його функціональність була набагато бідніша і великого поширення він не отримав.

Факт, як говориться, в наявності - в Java є офіційний логер, але вся спільнота Java-програмістів воліє користуватися іншим.

Logger - 1

На основі log4j потім було написано ще кілька логерів.

А потім для них усіх був написаний спеціальний універсальний логер slf4j, який зараз використовують. Він дуже схожий на log4j, тому я розповім тобі логування на його прикладі.

Весь процес логування складається з трьох частин.

Перша частина – це збір інформації .

Друга частина – це фільтрування зібраної інформації.

Третя частина – це запис відібраної інформації.

< Почнемо зі збору. Ось типовий приклад класу, який веде лог:

Клас з логуванням
class Manager { private static final Logger logger = LoggerFactory.getLogger(< span class="text-viola">Manager.class); public boolean processTask(Task task) { logger.debug("processTask id = " + task.getId()); try {  task.start();  task.progress();  task.complete(); return true; } catch(Exception e) {logger.error("Unknown error", e); return false; } } }

Зверни увагу на слова, виділені червоним.

Рядок 3 – створення об'єкта logger. Такий статичний об'єкт створюють практично у кожному класі! Ну, хіба що крім класів, які нічого не роблять, а лише зберігають дані.

LoggerFactory – це спеціальний клас для створення логерів, а getLogger – це його статичний метод. У нього зазвичай передають поточний клас, хоча можливі різні варіанти. Ряд 7 - в логгер пишеться інформація про виклик методу. Зверни увагу – це перший рядок методу. Тільки метод зголосився – одразу пишемо інформацію в балку.

Ми викликаємо метод debug, це означає, що важливість інформації «рівня DEBUG». Цей факт використовується лише на рівні фільтрації. Про це я розповім за кілька хвилин.

Рядок 17 – ми перехопили виняток і… одразу ж записали його в лог! Саме так і потрібно робити.

Цього разу ми викликаємо метод error, що одразу надає інформації статусу «ERROR»

— Поки що все ясно. Ну, наскільки це може бути зрозумілим у середині розмови.

— Відмінно, тоді перейдемо до запису фільтрації.

Зазвичай, у кожного лог-повідомлення є свій ступінь важливості, і, використовуючи його, можна частину цих повідомлень відкидати. Ось ці ступені важливості:

< /tr>
Ступінь важливості Опис
ALL Усі повідомлення
TRACE Дрібне повідомлення при налагодженні
DEBUG Повідомлення важливі при налагодженні
INFO Просто повідомлення
WARN Попередження
ERROR Помилка
FATAL Фатальна помилка
OFF Немає повідомлення

Ці рівні використовуються ще й при відсіві повідомлень.

Скажімо, якщо виставити рівень логування в WARN , то всі повідомлення менш важливі, ніж WARN будуть відкинуті: TRACE, DEBUG, INFO.

Якщо виставити рівень фільтрації в FATAL, то будуть відкинуті навіть ERROR’ы.

Є ще два рівні важливості, які використовуються при фільтрації – це OFF – відкинути всі повідомлення та ALL – показати всі повідомлення (не відкидати нічого).

— А як налаштовувати фільтрацію і де?

— Зараз розповім.

Зазвичай налаштування логера log4j задаються у файлі log4j.properties.

У цьому файлі можна задати кілька appender'ів – об'єктів, в які будуть писатися дані. Є джерела даних, а є – апендери – протилежні за змістом об'єкти. Об'єкти, куди ніби «стікають» дані, якщо їх можна представити у вигляді води.

Ось тобі кілька прикладів:

Запис лога в консоль
 # Root logger option log4j.rootLogger=INFO< /span>, stdout # Direct log messages to stdout log4j.appender.stdout=org.apache.log4j .ConsoleAppender log4j.appender.stdout.Target=System. out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout< /span>.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} 

Рядки 1 і 4 – це коментарі

Рядок 2 – ми вказуємо рівень повідомлень, які залишаємо. Все менш важливі рівні будуть відкинуті (DEBUG,TRACE)

Там же, через кому, ми вказуємо ім'я об'єкта (самі вигадуємо), куди писатиметься балка. У рядках 5-8 йдуть його налаштування.

Рядок 5 – вказуємо тип апендера – консоль (ConsoleAppender).

Рядок 6 – вказуємо, куди саме писатимемо – System.out.

Рядок 7 – задаємо клас, який керуватиме шаблонами записів – PatternLayout.

А ось як вигладить запис у файл:

Запис лога у файл
# Root logger option log4j.rootLogger=INFO, file # Direct log messages to a log file log4j.appender.file=org.apache.log4j.RollingFileAppender log4j.appender.file.File=C:\\loging.log log4j.appender.file.MaxFileSize=1MB log4j.appender.file.MaxBackupIndex=1 log4j.appender. file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern= %-5p %c{1}:%L - %m%n

Рядок 2 задає рівень фільтрації повідомлень та ім'я об'єкта-апендера (стоку).

Рядок 5 – вказуємо тип апендера – файл (RollingFileAppender).

Рядок 6 – вказуємо ім'я файлу – куди писати лог.

Рядок 7 – вказуємо максимальний розмір лога. При перевищенні розміру, почне писати новий файл.

Рядок 8 – вказуємо кількість старих файлів логів, які треба зберігати. — Я не знаю, що тут відбувається, але здогадуюсь. Що не може не тішити.

— Це відмінно. Тоді ось тобі приклад, як писати лог у файл і на консоль: Запис лога на консоль і у файл

# Root logger option log4j.rootLogger=INFO, file, stdout # Direct log messages to log file log4j.appender.file= org.apache.log4j.RollingFileAppender log4j.appender.file.File=C:\\loging.log log4j.appender.file.MaxFileSize=1MB log4j.appender.file.MaxBackupIndex=1 log4j.appender. file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern= % -5p %c{1}:%L - %m%n # Direct log messages to stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender .stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j. PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss}

— Ага, виявляється, і так можна? Це ж чудово!

— Ага. Ти можеш оголосити скільки завгодно апендерів і налаштувати кожен з них по-своєму. Більше того, кожному апендеру можна дуже гнучко налаштувати фільтр його повідомлень. Ми можемо не тільки задати кожному апендеру свій рівень фільтрації повідомлень, але й відфільтрувати їх пакетами! Ось для чого треба вказувати клас при створенні логера (я про LoggerFactory.getLogger).

Приклад:

Запис логу на консоль і файл
# Root logger option log4j.rootLogger=INFO, файл, stdout # Direct log messages to log file log4j.appender.file =org.apache.log4j.RollingFileAppender log4j.appender.file.threshold=DEBUG log4j.appender.file.File=C:\\loging.log log4j.appender.file .MaxFileSize=1MB log4j.appender.file.MaxBackupIndex=1 log4j.appender.file .layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern= %-5p %c{1}:%L - %m%n # Direct log messages to stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender .stdout.threshold=ERROR log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.< span class="text-viola">stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} log4j.logger.org.springframework =ERROR log4j.logger.org.hibernate=ERROR log4j.logger.com.javarush =DEBUG log4j.logger.org.apache.cxf=ERROR

Рядки 6 та 15 – ми задаємо свій рівень фільтрації для кожного апендера.

Рядки 20-23 ми вказуємо ім'я пакета та тип фільтрації його повідомлень. "log4j.logger" — це префікс, ім'я пакета виділено помаранчевим.

— Нічого собі? Навіть так можна. Ну, круто!

— До речі, ні log4j, ні slf4j не входять до JDK, завантажувати їх треба окремо. Це можна зробити ось тут . Але є і другий спосіб:

Крок 1. Додаєш до класу імпорти:

import org.slf4j.Logger; import org.slf4j.LoggerFactory;

Крок 2. Стаєш курсором на ці рядки і натискаєш Alt+Enter в Intellij IDEA

Крок 3. Вибираєш пункт File jar on web.

Крок 4. Вибираєш – slf4j-log4j13.jar

Крок 5. Вказуєш, куди завантажити бібліотеку (jar)

Крок 6. Користуєшся потрібними тобі класами.

— Нічого собі! Та що ж сьогодні за день такий. Стільки нового та стільки класного!

— Ось тобі ще гарна стаття з логінгу: http://habrahabr.ru/post/113145/

Добре, все. Іди відпочивай, програміст.