— А ось ти де! Ти не забув, що у нас сьогодні є ще одна лекція?
— Ні, я тебе шукав. Майже…
— Добре, тоді почнемо. Сьогодні я хочу розповісти тобі про логування.
Лог – це список подій, що відбулися. Майже як «морський журнал» чи «щоденник». Ну, або Твіттер – кому що ближче. А, відповідно, Логер — це об'єкт, за допомогою якого можна вести логування.
У програмуванні прийнято логувати практично все. А в Java - так взагалі все і навіть трохи більше. Справа в тому, що Java-програми - це дуже часто великі серверні програми без UI, консолі і т.д. Вони обробляють одночасно запити тисяч користувачів, і нерідко виникають різні помилки. Особливо, коли різні нитки починають одна одній заважати.
І, фактично, єдиним способом пошуку помилок і збоїв, що рідко відтворюються, в такій ситуації є запис у лог/файл всього, що відбувається в кожній нитці.
Найчастіше в лог пишеться інформація про параметри методу, з якими він був викликаний, всі перехоплені помилки, і ще багато проміжної інформації.
Чим повніше лог, тим легше відновити послідовність подій і відстежити причини виникнення збою або помилки.
Іноді логи досягають кількох гігабайт на добу. Це нормально.
— Декілька гігабайт? О_о
— Ага. Найчастіше при цьому лог-файли автоматично архівуються, із зазначенням дня – за який день це архів з логом.
— Нічого собі.
— Ага. Спочатку Java не було свого логера, що призвело до написання декількох незалежних логерів. Найпоширенішим з них став log4j.
Через кілька років, у Java все ж таки був доданий свій логер, але його функціональність була набагато бідніша і великого поширення він не отримав.
Факт, як говориться, в наявності - в Java є офіційний логер, але вся спільнота Java-програмістів воліє користуватися іншим.
На основі 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»
— Поки що все ясно. Ну, наскільки це може бути зрозумілим у середині розмови.
— Відмінно, тоді перейдемо до запису фільтрації.
Зазвичай, у кожного лог-повідомлення є свій ступінь важливості, і, використовуючи його, можна частину цих повідомлень відкидати. Ось ці ступені важливості:
Ступінь важливості | Опис |
---|---|
ALL | Усі повідомлення |
TRACE | Дрібне повідомлення при налагодженні |
DEBUG | Повідомлення важливі при налагодженні |
INFO | Просто повідомлення |
WARN | Попередження |
ERROR | Помилка | < /tr>
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/
Добре, все. Іди відпочивай, програміст.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ