3.1 Список уровней событий
Логирование – это процесс записи каких-либо событий, которые происходят во время работы программы. Ваша обязанность как программиста — запротоколировать все важное
, потому что потом, когда на production
будут странные и/или серьезные ошибки, кроме этих логов у вас больше ничего не будет.
Любая ошибка будет устранена в разы быстрее, если у вас будет вся информация о ней и обо всех предысториях вызовов. Но отсюда следует простой вывод – логировать вообще все: вызовы всех методов, значения всех параметров.
Это тоже не выход – слишком много информации так же плохо, как и слишком мало. Нам нужно умное логирование. Сделанное человеком для человека. И тут мы подходим к первому факту про логирование – все записи в лог еще во время их создания делятся на категории.
Программист, когда пишет какое-нибудь событие в лог, должен сам решить, насколько это важная информация. Уровень важности события выбирает автор сообщения. В log4j
существует 5 уровней важности логируемой информации:
DEBUG
INFO
WARN
ERROR
FATAL
Ниже расскажем о них подробнее.
3.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.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;
}
3.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;
}
}
}
3.5 Что нужно логировать
Разумеется, логировать все подряд не стоит. В большинстве случаев это резко ухудшает читабельность лога, а ведь лог пишется в первую очередь для того, чтобы его читали.
Кроме того, нельзя писать в лог различную личную и финансовую информацию. Сейчас с этим строго и легко можно нарваться на штрафы или судебные процессы. Рано или поздно такой лог утечет на сторону и тогда проблем на оберешься.
Так что же нужно логировать?
Во-первых, нужно логировать начало работы приложения. После того как приложение запустилось, рекомендуется вывести в лог его режим работы и различные важные настройки – так будет проще в будущем читать лог.
Во-вторых, нужно логировать состояние всех третьесторонних сервисов, с которыми твое приложение работает: системы рассылок, любые внешние сервисы. Как минимум нужно залогировать момент подключения к ним, чтобы убедиться, что они штатно работают.
В-третьих, логировать нужно все исключения. Если они ожидаемые, то информацию по ним можно записать компактно. Полная информация об исключениях дает 50%-80% важной информации при поиске ошибки.
Также нужно логировать завершение работы приложения. Приложение должно завершаться штатно и не сыпать при этом в лог десятки ошибок. Часто в этом месте можно найти подвисшие задачи, проблемы с пулом потоков или проблемы с удалением временных файлов.
Обязательно логируй то, что связано с безопасностью и авторизацией пользователя. Если пользователь 10 раз подряд пробует залогиниться или сбросить пароль, эта информация должна быть отражена в логах.
Логируй максимум информации об асинхронных задачах – часто исключения в таких потоках теряются. По асинхронной задаче обязательно логируй ее старт и завершение. Успешное завершение нужно логировать так же, как и проблемное.
Что еще? Запуск задач, выполняемых по таймеру, запуск хранимых SQL-процедур
, синхронизацию данных, все, что касается распределенных транзакций. Думаю, для начала хватит. В будущем ты сам дополнишь этот список.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ