Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

Урок 3 из 25 ~18 мин +20 XP

Уровни логов: Debug, Info, Warn и Error

Уровни логирования go в slog — четыре ступени важности: Debug, Info, Warn и Error с числами -4, 0, 4 и 8. От того, куда вы поставите запись, зависит, увидит ли её дежурный ночью, сработает ли алерт и можно ли включить подробный вывод без пересборки. В уроке — семантика каждого уровня, что писать на Debug и что на Error, и почему Warn без последействия превращает мониторинг в белый шум.

Содержание урока · 10 разделов

Два сервиса, одинаковый сбой. Первый логирует всё на Error: и неудачный ретрай, и сам сбой, и реакцию на сбой — за ночь алертная цепочка срабатывает сорок раз по одной причине, и дежурный перестаёт открывать уведомления. Второй логирует всё на Info: и сбой тоже — записи видны только тому, кто полез в хранилище руками, а алерт по уровню Error молчит, потому что Error в логе не появлялся ни разу. Оба сервиса честно пишут логи, но уровни выбраны без семантики — и мониторинг либо сгорел, либо слепой. Разберём, на что каждый уровень намекает дежурному и системам алертов, что писать на Debug, а что на Error, и почему уровень — это про важность для читателя, а не про тип события.

Уровни логирования go: четыре ступени важности#

В slog уровень — это число, а не строка: Debug равен -4, Info — нулю, Warn — четырём, Error — восьми. Числовая шкала не украшение: обработчик сравнивает уровень записи со своим минимумом и молча пропускает всё ниже, поэтому Debug скрыт при настройке по умолчанию — ноль против -4. Шкала сортируется: записи можно фильтровать «Warn и выше», а между ступенями разрешены промежуточные значения, например Level(-2) для болтливой отладки, которая важнее Debug, но ещё не Info. Обработчик по умолчанию берёт минимум Info, и slog debug info разделяются сами собой: Info печатается, Debug пропадает. Уровень пишется заглавными буквами в каждой строке вывода — INFO, WARN, ERROR — и по нему же хранилища строят фильтры и дашборды. Главная привычка урока: выбирая уровень, вы выбираете, кто и когда обязан увидеть запись.

Семантика уровней slog#

УровеньЧислоКогда писатьПример записи
Debug-4детали для разработчика, поиск причиныразбор запроса: заголовки, шаги, решения
Info0нормальный ход работы сервисасервис запущен, заказ принят
Warn4аномалия, сервис справился самретрай подключения, медленный запрос
Error8операция не удалась, нужен человекплатёж не прошёл, запись потеряна

Что писать на каждом уровне#

Debug — место для всего, что помогает воспроизвести путь выполнения: входящие параметры, выбранная ветка кода, содержимое ответа внешнего сервиса. Правило отбора: если при разборе инцидента вы пожалели, что этого нет в логе, — это Debug. Info — события, из которых складывается история сервиса: старт и остановка, принятые заказы, смена конфигурации. Не гоните сюда отладку — Info читают как ленту новостей. Warn — аномалии, которые сервис обработал сам: первая неудача перед ретраем, медленный запрос, приближение к лимиту. У Warn есть скрытый подписчик — человек и система, которые следят за частотой: рост Warn предсказывает Error. Error — операция не выполнила своё обещание: платёж не прошёл, письмо не ушло, запись потеряна. Пара slog debug info из практики: Debug отвечает на вопрос «как мы сюда попали», Error — на вопрос «что сломалось и что теперь».

Правила уровня простыми словами#

  • Debug: включается по необходимости, в проде по умолчанию скрыт — пишите смело.
  • Info: событие, о котором стоит узнать постфактум, без действий прямо сейчас.
  • Warn: аномалия с самоисправлением; если Warn встречается чаще Error — пересмотрите пороги.
  • Error: требуется реакция человека или системы алертов; сюда же — ошибки с потерей данных.
  • Промежуточные значения уровня разрешены: Level(-2) отделяет болтливую отладку от полезной.
  • Уровень записи не меняется от настроения автора: критерий один — кто обязан её увидеть.

Четыре вызова и их судьба

GO
func main() {
        slog.Debug("разбор запроса", "path", "/pay", "attempt", 2)
        slog.Info("сервис запущен", "port", 8080)
        slog.Warn("медленный запрос", "ms", 812)
        slog.Error("платёж не прошёл", "id", 42)
}

При настройках по умолчанию на экране появятся три строки: INFO, WARN и ERROR. Строка Debug пропала молча — её уровень -4 ниже минимума 0, и обработчик отбросил запись до всякого форматирования. Именно поэтому Debug можно писать щедро: в продакшене он не стоит ни памяти на вывод, ни места в хранилище, пока кто-то не поднимет минимум. Числа уровней нужны и системам алертов: правило «Error считается, Warn копится в тренд» выражается одним фильтром по полю level.

Как включить Debug и не пересобирать бинарник#

Вопрос, который приходит сразу: если Debug скрыт, как его увидеть в проде без деплоя? Для обработчика по умолчанию ответ появился в Go 1.22: функция slog.SetLogLoggerLevel меняет минимум дефолтного обработчика на ходу — один вызов из обработчика сигнала или админ-эндпоинта, и Debug начинает печататься. Для собственных обработчиков тот же эффект даёт опция Level в HandlerOptions: минимум читается из переменной окружения или конфига на старте. Схема по окружению, которую чаще всего берут за основу: в разработке минимум Debug, в продакшене Info, а Warn и Error видны везде — подробнее с переменными и безопасными дефолтами разбирается восемнадцатый урок. Проверка уровня перед сборкой полей — часть производительности горячего пути: об этом четырнадцатый урок.

SetLogLoggerLevel: Debug на ходу

GO
// до настройки: запись скрыта, минимум Info
slog.Debug("разбор запроса", "path", "/pay")

slog.SetLogLoggerLevel(slog.LevelDebug)

// теперь запись печатается
slog.Debug("разбор запроса", "path", "/pay")

Первый вызов исчезает в тишине, второй — печатает INFO-подобную строку с уровнем DEBUG. SetLogLoggerLevel действует на дефолтный обработчик, завязанный на пакет log; в проекте со своим обработчиком минимум задаётся в HandlerOptions при его создании. Заметьте, что решение о видимости принимает обработчик в момент записи: вызов slog.Debug дешёвый, и его можно оставлять в коде на постоянку.

Спорное мнение: Error в логе — не про ошибки Go#

Мнение, которое часто путает новичков: Error — это не «в коде вернулась ошибка», а «операция не выполнила обещание, и кто-то должен это починить». Функция возвращает ошибку десятки раз за запрос — упавшее подключение, пустой кэш, отмена контекста — и почти каждая из них штатно обрабатывается. Логировать каждую на Error — значит обесценить уровень за неделю. Пара критериев, по которым ошибка заслуживает Error: эффект необратим для пользователя (платёж не прошёл) или требуется действие за пределами кода (потерялась запись, кончился лимит). Всё, что обработано ретраем, фолбэком или кэшем, — Warn максимум, а чаще Debug. Проверка на ревью простая: если бы Error попал в алерт, был бы он полезен или это просто шум? Тем же вопросом стоит проверять существующий сервис: где Error без последствий — там и место будущего игнора алертов. Ошибки как значения и их оборачивание — за кадром этого курса, они разобраны в курсе по продвинутому Go.

Уровни против типизации: важность не равна виду события#

Распространённая ловушка — использовать уровни как систему типов событий: «заказы логирую на Info, оплаты на Warn, сбои на Error». Уровень говорит о важности для читателя, а не о виде события, поэтому одно и то же событие может пойти на разных уровнях: пользователь отменил заказ — Info, а отмена сорвалась из-за ошибки шлюза — Error. Тип события кодируется сообщением и полями, а не уровнем: заказ оформлен, payment.status=failed — и хранилище спокойно строит диаграммы по полям, не различая уровни. Попытка завести отдельный логгер под каждый вид событий ломает фильтрацию: дежурный ищет «всё, что случилось с заказом 42», а получает четыре ленты. Пара slog debug info показывает правильный разрез: один и тот же разбор запроса на Debug и одно и то же событие на Info — это два уровня значимости, а не два типа событий. Если видов событий становится много, придумывают словарь полей с именами событий — об этом стоит вспомнить, когда дойдёте до полей для сбора.

Проверка: видимость по умолчанию

Программа вызывает slog.Debug и slog.Info при настройках по умолчанию. Что появится в выводе?

Проверка: какой уровень выбрать

Запись в очередь не удалась, но ретрай через секунду прошёл успешно. Какой уровень?

Что выведет программа?

Прочитайте код и выберите, что он выведет:

slog.SetLogLoggerLevel(slog.LevelWarn)

slog.Info("готово")
slog.Warn("медленно", "ms", 812)
slog.Error("упало", "id", 42)

Расставьте уровни по смыслу

Допишите вызовы так, чтобы уровень соответствовал содержанию записи.

slog.("сервис запущен", "port", 8080) slog.("медленный запрос", "ms", 812) slog.("платёж не прошёл", "id", 42)

Соберите программу с отладкой

Расставьте строки в порядке выполнения: пакет, импорт, точка входа, включение Debug, отладочная запись, закрывающая скобка.

Строки

Ваша программа

Нажимайте на строки слева, чтобы собрать программу

Карточки: уровни логов

Термин

Debug (-4)

нажмите, чтобы перевернуть
Определение

Детали для разработчика: параметры, ветки кода, ответы сервисов. Скрыт по умолчанию, включается без пересборки.

1 / 6

Уровни разобраны: четыре ступени с числовой шкалой, минимум задаётся обработчиком, Debug скрыт, но доступен на ходу, а Warn работает только при честной семантике. Дальше логично спуститься в сами записи: в четвёртом уроке разберём атрибуты — типизированные конструкторы, порядок полей и цену Any; в одиннадцатом — как честно класть err в запись уровня Error; в двадцать третьем — антипаттерны, включая спам уровнями. Алерты по уровню — это уже зона метрик: у нас есть отдельный курс по Prometheus. Домашнее задание ниже — ревизия уровней в вашем собственном коде.

Песочница урока

Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.

Вывод

Запустите код, чтобы увидеть вывод.

Коротко: что запомнить

  • Уровень slog — число: Debug -4, Info 0, Warn 4, Error 8; обработчик пропускает записи не ниже своего минимума.
  • По умолчанию видим Info: Debug скрыт, Warn и Error — сигналы для человека и алертов.
  • Debug — как мы сюда попали, Info — нормальный ход, Warn — аномалия с самоисправлением, Error — нужна реакция.
  • Warn без последействия превращает поток аномалий в шум: рост Warn предсказывает Error, а не заменяет его.
  • Уровень — про важность для читателя, тип события кодируются сообщением и полями.
  • Минимум настраивается по окружению: SetLogLoggerLevel для дефолтного обработчика, Level в HandlerOptions для своего.

Домашнее задание

Проведите ревизию уровней в своём проекте: найдите пять записей на Error и ответьте на каждую — требовалась ли реакция человека или хватало Warn. Затем включите Debug в тестовом контуре через slog.SetLogLoggerLevel, повторите один запрос и напишите три поля, которых вам не хватило в Debug-записях для полного разбора.

Личные заметкиПусто
Хранятся только в вашем браузере (Slog · Уровни логов: Debug, Info, Warn и Error)

Вопросы и ответы по уроку

Можно ли придумать свой уровень между Warn и Error?

Да: slog.Level — числовой тип, значения вроде Level(6) и Level(-2) легальны, и обработчик сравнивает их обычным числом. На практике это редко нужно: между ступенями обычно достаточно промежуточного Level(-2) для болтливой отладки, а для алертов важнее чистые Warn и Error.

Куда логировать обработанную ошибку — на Warn или Debug?

Зависит от того, насколько она предсказуема: единичный сбой с успешным ретраем — Warn, штатная механика вроде проверки кэша мимо которого — Debug. Критерий один: рост частоты этих записей должен быть сигналом, а не фоном.

Нужен ли отдельный уровень Fatal?

В slog его нет, и это осознанно: фатальный сбой — это Error и решение о завершении процесса, которое принимает код, а не логгер. Логируйте slog.Error, затем os.Exit или панику; связка уровней с завершением процесса вредит тестам и библиотечному коду.

Термины урока

Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.

Следующая ступень учебного пути

pgx25 уроков~12 чпрактика25 уроков уже доступны

PostgreSQL в Go: драйвер pgx с нуля до продакшена

Курс pgx для Go: подключение к PostgreSQL, pgxpool, сканирование структур, транзакции, Batch, COPY, JSONB, LISTEN/NOTIFY и тесты. 25 уроков.

  • Подключаться к PostgreSQL через pgx и pgxpool
  • Сканировать строки в структуры и справляться с NULL
  • Работать с типами Postgres: UUID, JSONB, массивы, timestamptz
  • Проводить транзакции и массовые вставки через Batch и COPY