1. Список рівнів подій
Логування – це запис будь-яких подій, які відбуваються під час роботи програми. Ваш обов'язок як програміста — запротоколювати все важливе
, тому що потім, коли на production
будуть дивні та/або серйозні помилки, окрім цих логів у вас більше нічого не буде.
Будь-яку помилку буде усунено в рази швидше, якщо у вас буде вся інформація про неї та всі передісторії викликів. Але звідси випливає простий висновок – логувати взагалі все: виклики всіх методів, значення всіх параметрів.
Це теж не вихід: забагато інформації – так само погано, як і замало. Нам потрібне розумне логування. Зроблене людиною для людини. І тут ми підходимо до першого факту про логування – всі записи в лог ще під час їх створення діляться на категорії.
Програміст, коли пише якусь подію в лог, повинен сам вирішити, наскільки важлива ця інформація. Рівень важливості події обирає автор повідомлення. Існує log4j
5 рівнів важливості логованої інформації:
DEBUG
INFO
WARN
ERROR
FATAL
Нижче розповімо про них докладніше.
2. DEBUG
Рівень DEBUG
вважається найменш важливим. Інформація, яка пишеться в лог з таким рівнем важливості, потрібна лише під час дебагу програми. Щоб записати в лог інформацію, потрібну під час дебагу, використовується метод debug()
.
Приклад:
class Manager {
private static final Logger logger = LoggerFactory.getLogger(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;
}
}
}
Зверніть увагу: метод debug
знаходиться на самому початку методу (метод ще не встиг нічого зробити) і пише в лог значення змінної, яка передається до методу. Це найчастіший сценарій використання методу debug()
.
3. INFO та WARN
Наступні два рівні – це INFO
і WARN
. Для них існує два методи – info()
і warn()
.
Рівень INFO
використовується просто для інформаційних повідомлень: відбувається і те, й інше. Коли починаєш розбір помилки в лозі, буває дуже корисно почитати її передісторію. Для цього відмінно підходить метод info()
.
Рівень WARN
використовується для запису попереджень (від слова warning). Зазвичай з таким рівнем важливості пишеться інформація про те, що щось пішло не так, але програма знає, як діяти в цій ситуації.
Наприклад, у процесі запису файлу на диск з'ясувалося, що такий файл вже існує. Тут програма може записати в лог попередження (warning), але показати користувачеві діалогове вікно та запропонувати обрати інше ім'я файлу.
Приклад:
class FileManager {
private static final Logger logger = LoggerFactory.getLogger(FileManager.class);
public boolean saveFile(FileData file) {
logger.info(“зберігаємо файл ” + file.getName());
boolean resultOK = SaveUtils.save(file);
if (resultOK) return true;
logger.warn(“проблема із записом файла ” + file.getName());
String filename = Dialog.selectFile();
boolean result = SaveUtils.save(file, filename);
return result;
}
4. ERROR та FATAL
І нарешті, два найважливіших рівня логування – ERROR
і FATAL
. Для них теж є спеціальні методи з однойменними назвами: error()
і fatal()
.
Помилки теж вирішили розділити на дві категорії – звичайні помилки та фатальні помилки. Фатальна помилка найчастіше призводить до аварійного закриття програми (для десктопних програм) або падіння вебсервісу (для вебзастосунків).
Ще один хороший приклад – операційна система Windows. Якщо в тебе просто впала програма, з точки зору операційної системи це Error
. А якщо впала сама операційна система і ти бачиш синій екран смерті від Windows, це вже Fatal error
.
У Java-застосунках найчастіше події Error
і Fatal
пов'язані з винятками, що виникають. Приклад:
class Manager {
private static final Logger logger = LoggerFactory.getLogger(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;
}
}
}
5. Що потрібно логувати
Ясна річ, логувати все одразу не варто. Це може різко погіршити читабельність лога, а він пишеться насамперед для того, щоб його читали.
До того ж, не можна писати в лог різну особисту та фінансову інформацію. Зараз із цим все строго, і можна нарватися на штрафи чи судові процеси. Рано чи пізно такий лог може потрапити в сторонні руки, а це велика проблема.
То що ж треба логувати?
По-перше, потрібно логувати початок роботи програми. Після того, як програма запустилася, рекомендується вивести в лог його режим роботи і різні важливі налаштування – так буде простіше читати лог в майбутньому.
По-друге, потрібно логувати стан усіх третьосторонніх сервісів, з якими твоя програма працює: системи розсилок, будь-які зовнішні сервіси. Як мінімум, потрібно залогувати момент підключення до них, щоб переконатися, що вони штатно працюють.
По-третє, логувати потрібно всі винятки. Якщо вони очікувані, інформацію про них можна записати компактно. Повна інформація про винятки дає 50-80% важливої інформації під час пошуку помилки.
Також потрібно логувати завершення роботи програми. Додаток повинен завершуватися штатно і при цьому не сипати в лог десятки помилок. Часто в цьому місці можна знайти завдання, які підвисли, проблеми з пулом потоків або проблеми з видаленням тимчасових файлів.
Обов'язково логуй те, що пов'язане з безпекою та авторизацією користувача. Якщо користувач 10 разів поспіль намагається залогінитись або скинути пароль, цю інформацію потрібно відобразити в логах.
Логуй максимум інформації про асинхронні завдання – часто винятки в таких потоках губляться. За асинхронним завданням обов'язково логуй її старт та завершення. Успішне завершення потрібно логувати так само, як і проблемне.
Що ще? Запуск завдань, що виконуються за таймером, запуск збережених даних SQL-процедур
, синхронізацію даних та все, що стосується розподілених транзакцій. Думаю, для початку цього вистачить. У майбутньому ти самотужки доповниш цей перелік.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ