was successfully added to your cart.

Корзина

Чеклист: «Бытие логгера»

Небольшая заметка + чеклист о том, чего нельзя забывать при работе с логгером.

Вот вам чеклист, копируйте в Trello, Jira, Notion и куда угодно

  1. Все пункты (ссылка)
  2. Запросы. Middleware
  3. Запросы. Request
  4. Запросы. Response (optional)
  5. Запросы. Time profiler
  6. Запросы. Statuses
  7. Запросы. Error as Logger.error
  8. Логируйте в отдельном процессе
  9. Не стесняйтесь логировать все
  10. Настройте Skipper
  11. Добавьте кастомные статусы
  12. Используйте DI
  13. Всегда используйте внешние системы
  14. Docker + stdout
  15. Синхронизируйте время
  16. Настройте оповещения
  17. UserID
  18. TraceID
  19. Frontend

Запросы

Не важно откуда и как (HTTP, MQTT, WS, GQL, etc.) вы всегда должны логгировать запрос на входе и итоговый ответ.

Запросы. Middleware – Лучше всего выносить логику логирования в срез AOP (в более человеческом варианте «выносить в middleware»).

Запросы. Request – Обязательно фиксируйте что вам прислали

Запросы. Response (optional) – Ответ необязательно фиксировать (он может быть слишком большим)

Запросы. Time profiler – Фиксируйте время, которое занял запрос

Запросы. Statuses – Логируйте все статусы

Запросы. Error as Logger.error – Логируйте ошибку как тип «Ошибка»

Логируйте в отдельном процессе

Всегда убеждайтесь, что ваш логгер или библиотека делают логи в отдельном процессе, чтобы не срать в основной процесс.

Не стесняйтесь логировать все

Разработчики слишком часто переживают: «Что можно логгировать а что нельзя? В каких слоях ставить логи, а в каких нет?» – я считаю, что можно логировать все и всегда, и впринципе, чем больше тем лучше.

Главное соблюдать «уровни логов» так, чтобы логи, которые могут быть не нужны на проде, в него и не попадали.

Настройте Skipper

Это функция, которая по определенному правилу (например содержанию запроса) будет пропускать входное или выходное логирование или какие-то отдельные поля.

Скорее всего, вы не захотите, чтобы в ваших логах лежали пароли пользователей, которые были залогинены из запросов на регистрацию и аутентификацию.

Добавьте кастомные статусы

Как у HTTP есть STATUS_CODE, так и вам советую создать отдельное поле со статус кодами и для логгера.

Описание статус кодов держите в Wiki.

Используйте DI

Очень распространенная тактика – логировать глобальным логгером.

Впринципе, не помню, чтобы это было большой проблемой, но для тестирование (как и все глобальное) это может создать некоторые неудобства.

Лучше использовать DI там, где это возможно.

Всегда используйте внешние системы

Сейчас существует миллиард систем для отправки логов.

Самая моя любимая – ELK (Elastic Search, Logstash, Kibana).

Моментально раскрывается в Docker и дает из коробки огромный и удобный функционал.

(22.06.20) Буду тестить ELK в Heroku, посмотрим как получится.

Если у вас Kube8, тогда вам нужен DataDog. Там еще и мониторинг, и баг-трекинг и трэйсинг в комплекте.

(22.06.20) Но еще мне советовали DataDog и для обычного Docker, чекну и напишу.

P.S. Впринципе stdout Google App Engine уже идет с мониторингом из коробки (Cloud Logging), но мне дико не заходит интерфейс и функционал.

Docker + stdout

Если уж заговорили про внешние системы логирования, то достаточно оптимальным будет следующий вариант:

Совмещаете stdout вашего приложения с Docker контейнером, а на stdout Docker контейнера навешиваете слушателя (FileBeats), который уже будет отправлять логи в ELK.

Вот здесь это неплохо описано.

Основные преимущества: (1) вам не нужно делать HTTP запроса из приложения, (2) приложение больше не отвечает за способы логирования, а значит при изменении логики логгирования (смена сервера / системы логирования / транспорта / т.д.) не придется трогать приложение.

Синхронизируйте время

Логи всегда привязаны ко времени, поэтому запомните:

(1) Указывайте время и сервера, и клиентов.

(2) Если пишете в fs, то проверьте правильность времени сервера.

(3) Если пишите во внешнюю систему проверьте, что там правильно указано время (сколько же мы однажды намучались из-за рассинхрона)

(4) Проверьте, в самом timestamp не должно быть поправки на локальное время.

Настройте оповещения

Slack, Email, SMS на крайний случай.

Без оповещений, логгирование бесполезно.

Правило оповещения «> Х запросов с 1-го IP»

Есть малюсенький шанс успеть отловить DDoS атаку до первых потерь, если поставить правило, которое сделает предупреждение слишком большого кол-ва запросов с 1-го IP.

Всегда используйте библиотеку для логгирования

Есть случаи, когда люди предпочитают писать свои логгеры, ссылаюсь на «легкость» реализации и считая использование библиотеки overkill.

Если вы почитаете что делает нормальная библиотека логирования, а еще лучше, посмотрите ее код, вы поймете, что ничего легкого в логгерах нет.

Поэтому упаси вас здравый смысл писать свое. Просто не надо. Сначала попробуйте библиотеку, потом уже решите что и как вы хотите «переписать».

Для Golang посоветую Logrus или Zap.

Для Nodejs – Winston.

Вот для пара удобных фич логгеров:

Во-первых, они идут с очень удобной переключалкой между транспортами логгирования, типа stdout / fs / внешними API (ELK, Sentry, Graylog и так далее) и при этом менять форматирование под нужный транспорт.

Во-вторых, если это поддерживает язык, то они будут логировать в отдельном треде / рутине / цикле и так далее, чтобы не срать в основной процесс + она сама освободит дескрипторы.

В-третьих, они могут автоматически добавлять timestamp к логам, брать данные из запроса и переформатировать их, форматировать

UserID

В 90% случаев запросы будут инициализированы юзерами, 90% важных запросов идут от аутентифицированных юзеров, обязательно логируйте их UserID.

Мы так очень часто выручали чат-поддержку и клиентов, когда знали кто конкретно какие запросы делает.

TraceID

Трассировка – утрированно, это способ прослеживания всего пути запроса через все система от инициатора запроса, в систему и все ее подсистемы и обратно к инициатору.

Начиная с самого источника действия (в случае с вебом, это запрос от клиента на сервер) добавляйте в метаданные поле «TraceID», значением которого будет uuid строка

Пример: в HTTP запрос добавляем headers: {"X-Trace-Id": "..."}, а значением будет uuid строка headers: {"X-Trace-Id": "d6891392-e2a2-4139-bf15-7c0a3d8233b"}.

И дальше абсолютно не важно через сколько миллиардов микросервисов пройдет запрос от клиента и обратно к нему, важно, что этот TraceID должен быть везде и всегда, чтобы в будущем, вы могли по нему отследить как запрос прошел от клиента, в вашу систему, поварился внутри и вернулся обратно.

Лайфхак. Чаще всего будет происходить ситуация при которой на внутреннии запросы захочется поставить свой TraceID, но при этом надо как-то связать его с TraceID из клиентского запроса. Для этого во все meta / headers всех запросов всегда добавляйте необязательное поле «OriginTraceID», куда вы будете добавлять TraceID оригинального запроса.

Frontend

Все тоже самое, что написано сверху, продублировать и для Frontend.

Люди почему-то очень стесняются делать логи на фронте, но в большинстве продуктов, в этом нет никакой проблемы.

Гораздо больше контента и развлечений в Telegram-канале