Обычно библиотеки логгирования предлагают из коробки сразу несколько "уровней" важности, с которыми Вы можете записывать сообщения. В документации к ним можно найти рекомендации - как лучше этими уровнями пользоваться, примерно такие:
Info
: все ожидаемые события, учет которых запланирован.Warning
: неожиданные/подозрительные события - иначе говоря аномалии, после которых еще возможно продолжение работы приложения.Error
: событие, после которого невозможно дальнейшее выполнение программы.Fatal
: событие, требующее по-настоящему немедленного вмешательства.
Проблема в том, что это все не совсем работает без некоторых дополнительных соглашений и уточнений. Именно о них я и хотел бы поговорить ниже.
"Продолжить работу"
Трактовать “возможно продолжить работу” можно очень по разному. Скажем, на экране пользователя можно настроить любимый цвет рамки вокруг экрана: пусть будет розовый. Если по каким-то причинам хранилище, где мы держим эти настройки цвета было недоступно и мы не можем отобразить этот цвет - можно ли это считать как “возможно продолжить” или это катастрофа? К сожалению, я еще ни разу не встречал хорошего универсального формального критерия, чтобы четко можно было разделять "катастрофа-терпимо". А раз не можешь остановить - значит нужно направить. Потому я предлагаю инвертировать споры об “это неправильный уровень”: если в коде написано, что отсутствие цвета - это Error
- значит программист Вам говорит, что этот цвет чертовски важен в этом домене - возможно, именно этот цвет сигнализирует, что сейчас надо продавать акции на миллионы долларов, и наоборот. Соответственно, чтение кода немного меняется: когда видите место, где из-за какой-то на Ваш взгляд ерунды прерывается выполнение, вопрос, который должен возникать автору, “Почему ты считаешь, что это так важно?” вместо “Истинно тебе говорю - ты программируешь неправильно!”.
Схожая инверсия может помочь в вечных спорах на тему “это исключительная ситуация или нет”. Опять же, все довольно просто. Важна не техническая составляющая: “нет соединения к базе - это исключение”, а “серверу прислали неправильный id
- так это ожидаемо”. Важно то, чья это будет головная боль и как ее можно избежать или хотя бы минимизировать урон. Чьи планы на вечер пятницы пойдут к черту из-за того, что это сломалось? Если Вашим сервисом пользуются приложения, которые вне Вашего контроля, то Вам действительно плевать на то, что они присылают некорректные id
и у них там что-то идет не так. Если Ваше приложение - это инструмент для управления базой данный - наподобие Sql Server Magement Studio - очевидно, что отсутствие доступа к базе - не Ваша печаль. А если Вашим сервисом пользуются приложения, за которые Вы же и в ответе - то это Ваши неприятности в конечном счете. Вопрос лишь в том, как и когда Вы об этом узнаете - быстро из сработавшей сигнализации или от звонка злого как черт владельца бизнеса, которому Вы пишете софт. А также вопрос в том, как “дешево, надежно и сердито” эту сигнализацию наладить.
"Error"
Давайте представим себе экран, где есть кнопка “Открыть” и текстовое поле. Эта кнопка по замыслу должна открыть Вам какой-то полезный функционал, а в текстовом поле предполагается ввести имя и фамилию. После нажатия на кнопку принципиально возможны два сценария: приложение либо крэшится либо нет. Если же мы были удачливы и оно не упало, у нас опять два варианта: мы получили желанный экран или мы получили сообщение об ошибке вместо него. Сообщение об ошибке в свою очередь можно принципиально разделить еще на два класса: может ли пользователь сам исправить ситуацию в рамках программы или нет - имеется ввиду корректирование своего ввода, а не “обратиться к Вашему системному администратору”.
На практике сообщение вида “Обратитесь к администратору” это просто подслащенные крэш. Да, несомненно это лучше, чем убить весь процесс со всеми пользовательскими данными, но от этого оно не перестает фактически блокировать работу. В тоже время ошибка может быть сообщением о неправильных с точки зрения программы действиях, а именно надо было ввести имя и фамилию “Джон Иванов”, а человек ввел просто “Джон” и валидатору это не нравится. К чему это все? Что вообще у нас тут речь идет о 3-х достаточно разных сущностях, но при том на каждую из них можно сослаться как Error, что вызывает изрядную путаницу. Крэш приложения - это несомненно уровень Error
в нашей системе определений, но это очень важный Error
.
Ошибка валидации имя-фамилии - это несомненно уровень Info
- мы ждем, что пользователь будет норовить записать все что угодно, а мы - пресекать это. Ну и записывать все те разы, когда пользователь был неправ. Но от этого ошибки не перестают бесить людей, которые их видят. То, что напрямую связано с людьми и их UX - важно; и неплохо бы присматривать за этим, не допускать, чтобы сообщения об этом тонули в километрах унылых Info
записей “Пользователь такой-то залогинился”. Иными словами, чтобы устранить путаницу, хочется иметь уровни Error+
и Info+
.
Я предвижу восклицания “Так погодите, ведь крэш приложения - это недопустимо! Надо сразу действовать! Это Fatal
уровень!" На это я неспеша прикурю воображаемую сигарету, затянусь и задумчиво отвечу: “Ну… всех ведь все равно не спасти...". Ладно, я не курю, но, думаю, образ понятен. Появление сообщения Fatal
должно быть эквивалентом запуска тревоги воздушной угрозы, когда в офисе разработки врубается сирена и это жуткое красное аварийное освещение. Вот честно, Вы именно так реагируете на то, что у кого-то из бухгалтерии на экране, который раз в сто лет запускают, упало приложение? Вполне может быть нормально, что у Вас сейчас даже и нет подобной ситуации, где уровень Fatal
- согласно такой системы определений - нужен. Так вот трюк в том, чтобы не блокировать возможность добавить обработку такой потенциальной ситуации в будущем, забивая сейчас Fatal
уровень сообщениями, которым важностьError+
в самый раз.
Таким образом, мы приходим к тому, что в действительности неплохо бы иметь уровни вида
Info
Info+
Warning
Error
Error+
Fatal
“Плюсовые” уровни можно легко организовать в Вашей любимой библиотеке логгирования расширив ее существующие методы Error/Info
, которые бы просто унифицировано добавляли какой-то хэштэг в обычные сообщения, скажем #IMPORTANT.
Что ж - это все, что я хотел сказать об ошибках и их логгировании. Буду рад, если этот текст добавит разработчикам больше взаимопонимания и уменьшит споры о том, как "правильно".