Логирование (логи)
Логирование (логи)
Лог (log, журнал) — упорядоченная по времени, только дописываемая последовательность записей о событиях, которые происходили в программе или системе. Логирование — практика такие записи писать, хранить и читать так, чтобы по ним можно было восстановить, что случилось и почему.
История
Слово пришло с моря. В XVI–XVII веках скорость корабля измеряли лагом (англ. log — «полено»): деревяшку на верёвке с узлами бросали за борт и считали, сколько узлов уйдёт за полминуты. Отсюда «узлы» как единица скорости. Результаты замеров, курс, погоду и происшествия записывали в log-book — судовой журнал. Слово закрепилось за самим журналом: log — это «хронологическая запись того, что было».
В вычислительной технике логи появились вместе с многозадачностью. В 1960-х операционные системы разделения времени печатали на консоли или телетайпе сообщения о том, кто вошёл, какая задача запустилась, что упало. Это и был первый «системный лог» — бумажная лента, которую оператор потом листал.
Вехи, которые сформировали то, что мы используем сегодня:
-
syslog, начало 1980-х. Эрик Оллман (Eric Allman) в Университете Беркли написал для своего почтового сервера Sendmail службу, которая принимает сообщения от любых программ и складывает их в общий файл. Он ввёл две вещи, живущие до сих пор: уровни важности (от
emergдоdebug, восемь штук) и источник (facility: ядро, почта, авторизация и так далее). Протокол много лет жил без формального описания и был задокументирован задним числом в RFC 3164 (2001). Актуальный стандарт — RFC 5424 (2009), автор Райнер Герхардс (Rainer Gerhards), он же автор rsyslog. -
log4j, 1996–2001. Чеки Гюлькю (Ceki Gülcü) начал библиотеку в IBM, в 2001-м она стала проектом Apache. Log4j сделал стандартом иерархию логгеров (по именам пакетов), уровни
TRACE / DEBUG / INFO / WARN / ERROR / FATALи разделение на «кто пишет» (logger), «куда» (appender) и «в каком виде» (layout). Эту модель потом скопировали почти все языки: модульloggingв Python (PEP 282, Винай Саджип, Python 2.3, 2003), NLog и Serilog в .NET, winston в Node.js. -
Централизованный сбор, 2003–2011. Splunk (2003) первым продал идею «залей все логи в одно место и ищи как в Google». Открытая альтернатива сложилась из трёх проектов: Elasticsearch (Шай Банон, 2010), Logstash (Джордан Сиссел, 2009) и Kibana (Рашид Хан, 2011) — стек ELK.
-
Логи как поток и как структура данных, 2011–2013. Манифест Twelve-Factor App (Адам Уиггинс, Heroku, 2011) в пункте XI сказал: приложение не должно управлять файлами логов, оно пишет в stdout, а окружение решает, куда это девать. А Джей Крепс (Jay Kreps) из LinkedIn в 2013-м в эссе «The Log» показал, что лог — не только для отладки: это фундаментальная структура данных, на которой стоят репликация баз, Kafka и потоковая обработка.
-
Бинарный журнал и структурные логи, 2011–наши дни. systemd-journald (Леннарт Пёттеринг, 2011) заменил текстовые файлы индексированным бинарным журналом. Apple в macOS 10.12 (2016) сделала то же самое (unified logging). Параллельно распространились структурные логи в JSON, а в 2019-м появился OpenTelemetry, где логи — один из трёх «сигналов наблюдаемости» вместе с метриками и трассами.
Отдельная веха со знаком минус: в декабре 2021-го уязвимость Log4Shell (CVE-2021-44228) в log4j 2 позволила выполнять чужой код на сервере, просто отправив специальную строку, которую сервер залогирует. Оценка опасности — максимальные 10,0 из 10. Индустрия впервые массово осознала, что лог — тоже поверхность атаки.
Что это такое
Лог — это ответ на простой вопрос: «программа работала без меня, что с ней происходило?». Живой человек может посмотреть на экран, пока процесс работает. Но большинство программ работают ночью, на чужом сервере, в фоне, годами. Единственный способ узнать, что они делали, — если они сами оставили следы.
Три свойства делают лог логом:
- Только дописывание (append-only). Запись не редактируют и не удаляют, только добавляют в конец. Иначе это не свидетельство, а редактируемая заметка.
- Порядок по времени. Каждая запись знает, когда она произошла, и стоит после предыдущей. Это позволяет восстанавливать причинность: «сначала пришёл запрос, потом упала база, потом клиент получил ошибку».
- Событийность. Одна запись — одно событие. Не «состояние системы», а «что-то случилось».
Полезно различать соседние вещи:
- Лог vs метрика. Метрика — это число во времени: «запросов в секунду: 340». Лог — конкретный факт: «запрос #4812 от 10.1.2.3 упал с ошибкой 500 через 1,2 с». Из логов можно посчитать метрики, наоборот — нельзя. Метрики дёшевы и показывают тренд, логи дороги и показывают причину.
- Лог vs трасса (trace). Трасса — это путь одного запроса через десять сервисов, склеенный по общему идентификатору. Технически это те же записи событий, но сгруппированные не по времени и источнику, а по запросу.
- Лог vs журнал решений. Лог машины отвечает на «что произошло». Журнал, который ведёт человек, отвечает на «почему решили именно так». Первое машина пишет сама, второе — нет, и подменить одно другим не получится.
- Лог vs база данных. База хранит текущее состояние («на счёте 100 рублей»), лог — историю изменений («+50, -20, +70»). Внутри любой серьёзной базы есть свой лог (write-ahead log, журнал упреждающей записи), по которому она восстанавливается после сбоя. Это тот случай, когда лог — не побочный продукт, а источник истины.
- Лог vs аудит. Аудит-лог (audit trail) — подвид лога, где каждая запись отвечает на «кто, что, когда сделал с данными» и где полнота и неизменность гарантируются юридически или регламентом. Обычный лог приложения таких гарантий не даёт.
Аналогии из жизни
Судовой журнал. Вахтенный каждые несколько часов записывает курс, скорость, погоду, происшествия. Через месяц по журналу можно восстановить весь рейс, а в случае аварии он становится главным документом расследования. Так работает: хронология, автор каждой записи, невозможность вырвать страницу.
Где ломается: в судовой журнал пишет человек, который решает, что важно. Программа не решает — она пишет то, что ей приказал разработчик, и с той частотой, с какой приказал. Поэтому лог бывает одновременно огромным и бесполезным: тысяча строк «запрос обработан» и ни одной о том, почему он обработан неправильно. И судовой журнал — это ещё и «почему»: капитан пишет мотивы решений. Машина мотивов не знает.
Контрольная лента кассы. Каждая пробитая покупка печатается на второй ленте внутри аппарата. Продавец не может её отредактировать, налоговая может запросить. Так работает: полнота, только дописывание, доказательство того, что операция была.
Где ломается: кассовая лента обязана быть полной по закону, и аппарат не работает, если лента кончилась. Лог приложения так не устроен: если диск переполнен, буфер не сброшен, процесс убит — записи молча теряются, а программа продолжает работать. Лог не гарантирует, что в нём есть всё, что случилось. Есть только то, что успели записать.
Медицинская карта. Разные врачи в разное время дописывают в одну карту: терапевт, хирург, лаборатория. Каждая запись — дата, кто, что обнаружил, что назначил. Чтобы понять, откуда взялась аллергия, нужно прочитать всю историю. Так работает: несколько источников пишут в одну хронологию по общему ключу (пациент), и именно склейка даёт картину.
Где ломается: у пациента одна карта, а у распределённой системы лог каждого сервиса лежит на своём сервере. Если не завести общий идентификатор запроса и не свозить всё в одно место, получится десять карт разных больниц про одного человека, и никто не сложит их вместе. Плюс в карту пишут по регламенту, с обязательными полями. В логи пишут как придётся, и «дата» в одном сервисе окажется в UTC, а в другом — в местном времени.
Как это работает
Разберём путь одной записи от строки кода до экрана человека, который ищет причину сбоя в три часа ночи.
Шаг 1. Событие в коде. Разработчик в нужном месте вызывает логгер и назначает уровень:
log = logging.getLogger("collector")
log.info("виток %d завершён, собрано %d записей", n, count)
log.warning("проект %s не ответил, попытка %d", slug, attempt)
log.error("не удалось записать файл %s", path, exc_info=True)
Уровень — это не «насколько громко», а «кому это нужно». DEBUG — разработчику при отладке. INFO — оператору, чтобы видеть ход дел. WARNING — что-то странное, но справились. ERROR — не справились, но живём. CRITICAL (в syslog — emerg/alert) — всё, дальше нельзя.
Шаг 2. Фильтр по порогу. У логгера есть настроенный минимальный уровень. Если в проде стоит INFO, все DEBUG отбрасываются ещё до форматирования. Это главный рычаг управления объёмом: тот же код в тестах пишет всё, в проде — только существенное.
Шаг 3. Форматирование записи. Логгер собирает из события запись. Классический вид — одна строка текста:
2026-09-07 17:56:03,412 INFO collector: виток 96 завершён, собрано 37 записей
Современный вид — одна JSON-строка на событие (структурный лог):
{"ts":"2026-09-07T14:56:03.412Z","level":"info","logger":"collector",
"msg":"виток завершён","round":96,"count":37,"pid":50771}
Разница принципиальна. Текстовую строку человек читает глазами, а машина парсит регулярками и ошибается. JSON машина разбирает надёжно, зато человеку без инструмента читать тяжело. Это тот самый формат JSONL (по одной JSON-записи на строку), в котором Claude Code хранит свои сессии.
Минимальный набор полей хорошей записи: время (лучше в UTC с явной зоной), уровень, источник (имя логгера, PID, хост), сообщение и контекст (идентификатор запроса, пользователя, задачи).
Шаг 4. Обработчик (handler, appender) — куда писать. Вариантов несколько, и их можно комбинировать:
- stdout/stderr. Самый простой и, по Twelve-Factor, самый правильный: программа не знает про файлы, а окружение (systemd, launchd, Docker) само перенаправляет поток куда нужно. Важная тонкость: stdout при выводе не в терминал, а в файл или трубу буферизуется. Программа может умереть, а последние строки так и не будут записаны. Отсюда
flush=True, переменнаяPYTHONUNBUFFERED=1и привычка писать логи в stderr, который не буферизуется. - Файл.
app.log, к которому применяется ротация (logrotate, RotatingFileHandler): когда файл вырос до N мегабайт или прошёл день, он переименовывается вapp.log.1, а старые удаляются. Без ротации диск кончится. - syslog / journald. Локальная служба ОС, которая принимает записи от всех программ, добавляет своё время и источник, хранит и индексирует. На Linux
journalctl -u имя-сервиса, на macOSlog show. - Сеть. Напрямую в коллектор по TCP/UDP/HTTP.
Шаг 5. Сбор и доставка. На каждом сервере стоит агент (Filebeat, Fluent Bit, Vector, promtail), который читает файлы или journald, дописывает метаданные (хост, контейнер, окружение) и отправляет в центральное хранилище. Здесь же часто фильтруют и сэмплируют: если однотипных ошибок 100 000 в минуту, оставить каждую сотую.
Шаг 6. Хранение и индекс. Elasticsearch индексирует полный текст каждой записи (дорого, но ищет по любому слову). Loki индексирует только метки (хост, сервис), а тексты хранит сжатыми (дёшево, ищет медленнее). ClickHouse хранит колонками и хорош, когда логи структурные и по ним считают агрегаты.
Шаг 7. Чтение. Простейший инструмент — tail -f (следить за хвостом файла в реальном времени) и grep. В центральной системе — Kibana или Grafana с запросами вроде «все ERROR сервиса X за последний час с этим request_id». Поверх строятся алерты: «если за 5 минут больше 50 ошибок — сообщение в Telegram».
Вся цепочка одной схемой:
код --> logger --> [порог] --> formatter --> handler
|-- stderr --> systemd/launchd --> journald
|-- файл --> logrotate
`-- сеть --> агент --> хранилище --> поиск/алерты
Лог — это то, что программа о себе думает, а не то, что есть
Запись «файл сохранён» означает, что код дошёл до строки, которая так пишет. Она не означает, что файл лежит на диске: он мог уйти в другую папку, быть перезаписан следующим шагом, не сброситься из буфера. Точно так же «0 строк найдено» может значить «ничего нет», а может — «нас не пустили, и мы получили пустую страницу». Приёмка результата всегда делается по самому результату, лог только подсказывает, где искать.
Где встречается в обычной жизни
- Журнал звонков в телефоне. Каждый входящий и исходящий — запись с временем, номером и длительностью. Ты не можешь отредактировать запись, только удалить, и телефон ничего не «понимает» про звонок — только фиксирует факт. Классический лог событий.
- Выписка по банковской карте. Хронологическая, только дописываемая последовательность операций, по которой восстанавливается баланс. И это же пример лога как источника истины: банк хранит операции, а остаток считает.
- Отслеживание посылки. «Принято в отделении», «прибыло в сортировочный центр», «передано курьеру» — это лог доставки, который читают клиенты. Когда посылка «зависает», ты смотришь последнюю запись и понимаешь, где искать.
- История браузера и «активные сеансы» в Telegram или Google. Список «когда, с какого устройства, откуда входили» — аудит-лог доступа к аккаунту. Именно по нему замечают, что кто-то чужой залогинился.
- Чёрный ящик самолёта. Бортовой самописец пишет параметры полёта по кругу (последние несколько часов) и читается после происшествия. Это лог с ротацией и с одной особенностью, которой у обычных логов нет: он защищён от разрушения.
Где встречается в IT и бизнесе
- Разбор инцидентов. Основное назначение. Нужно, когда «в 14:32 у клиентов перестало работать, а в 14:40 само починилось» и никто не понимает почему. Без логов это гадание, с логами — чтение.
- Наблюдение за фоновыми и долгими задачами. Скрипт, который сутки собирает данные, отчитывается только через лог: какой шаг, сколько сделано, сколько ошибок. Отдельный процесс-сторож читает тот же лог и решает, всё ли идёт по плану. Нужно, когда результат появится через часы, а узнать «жив ли» хочется сейчас.
- Безопасность. Лог авторизации — источник для fail2ban (пять неудачных входов подряд — бан IP), для расследований утечек и для требований регуляторов. Нужно, когда есть внешний доступ и ценные данные.
- Аналитика и продукт. Access-лог веб-сервера (кто, когда, какую страницу, с каким referer) — это сырьё, из которого выросли все системы веб-аналитики. Журнал звонков колл-трекинга — то же самое для телефонии. Нужно, когда хочешь понять поведение пользователей, а не только работоспособность системы.
- Доказательства для клиентов и партнёров. «Ваш запрос пришёл в 10:03:17 и получил ответ 200 за 0,15 с» — аргумент в споре об SLA, который невозможно оспорить без своих логов. Нужно всегда, когда есть договорные обязательства по доступности.
- Данные для обучения моделей и агентов. Логи диалогов, действий и результатов — это учебный материал: по ним ищут повторяющиеся ошибки и превращают их в правила. Этот блог существует потому, что Claude Code пишет подробный лог каждой сессии.
Кто пользуется
Логи пишут все программы без исключения, поэтому интереснее посмотреть на масштаб тех, кто на логах строит бизнес:
- Splunk — первая коммерческая платформа поиска по логам. В 2024 году её купила Cisco примерно за 28 миллиардов долларов, и это одна из крупнейших сделок в истории инфраструктурного ПО. Это цена вопроса «уметь искать в логах» для крупных компаний.
- Datadog — облачный мониторинг, где логи — один из основных продуктов; годовая выручка, по разным оценкам, превысила 2 миллиарда долларов.
- Elastic (стек ELK) — самая распространённая открытая связка для логов; количество установок исчисляется, по оценкам, сотнями тысяч.
- Grafana Labs с Loki (2018) — популярный выбор в Kubernetes-мире, где логов много, а платить за полнотекстовый индекс не хотят.
- Яндекс создал ClickHouse для хранения событий Метрики (открыт в 2016 году); сейчас это одна из самых быстрых колоночных баз для логов и аналитики, на неё перешли, в частности, Cloudflare и Uber для логов.
- LinkedIn превратил лог в инфраструктуру: Kafka, открытая в 2011-м, к 2019-му, по данным самой компании, пропускала порядка 7 триллионов сообщений в день.
- Российские регуляторные требования тоже завязаны на логи: 152-ФЗ о персональных данных и требования ФСТЭК предполагают регистрацию событий доступа, а в банковской сфере журналирование операций обязательно.
Альтернативы и конкуренты
Альтернативы логам как способу узнать, что происходит:
- Метрики (Prometheus, Graphite). Плюс: дёшевы, показывают тренды и годятся для алертов «стало хуже». Минус: не объясняют причину; «ошибок стало больше» — и всё.
- Распределённая трассировка (Jaeger, OpenTelemetry). Плюс: показывает путь одного запроса через все сервисы с таймингами. Минус: дорого внедрять, нужен сквозной идентификатор через всю систему, почти бесполезно для монолита.
- Трекеры ошибок (Sentry). Плюс: одна ошибка с полным стеком и контекстом, сгруппированная, с уведомлением. Минус: видит только исключения, а «работает, но неправильно» — не видит.
- Отладчик и интерактивная сессия. Плюс: можно посмотреть любую переменную. Минус: только здесь и сейчас, только когда разработчик сидит рядом; ночью на проде не работает.
Альтернативы внутри мира логов — что выбрать для хранения:
- Файлы + grep. Плюс: ноль настройки, работает везде. Минус: не масштабируется дальше пары серверов, нет алертов.
- ELK / OpenSearch. Плюс: ищет по всему, мощная визуализация. Минус: прожорлив по памяти и диску, требует ухода.
- Loki. Плюс: дёшево хранит огромные объёмы. Минус: поиск по тексту медленнее, без меток беспомощен.
- ClickHouse. Плюс: очень быстрые агрегаты по структурным логам. Минус: нужно заранее спроектировать схему, не любит «свободный текст».
Когда НЕ стоит использовать
- Как хранилище бизнес-данных. Потому что лог ротируется, теряет записи и не имеет схемы. Если из логов нужно потом «достать всех клиентов, которые…» — это данные, и им место в базе, а в лог пишется факт «записали в базу».
- Для секретов и персональных данных. Потому что лог копируется на десятки машин, живёт годами и читается всеми, у кого есть доступ к серверу. Пароль, токен, номер телефона клиента, попавшие в лог, уже утекли — даже если это «просто локальный терминал». Фильтрация чувствительных полей должна быть в форматтере, а не в памяти разработчика.
- Для подробного DEBUG на горячем пути в проде. Потому что запись строки стоит времени и диска: сервис, логирующий каждый байт на 10 000 запросов в секунду, потратит на логи больше, чем на работу, а счёт от Datadog придёт больше, чем за сами серверы. Уровни и сэмплирование существуют именно для этого.
Секреты в логах
Самая частая утечка — не взлом, а лог. Команда с подстановкой переменной, отладочный print с заголовками запроса, дамп конфига «для проверки» — и пароль лежит в файле, который синхронизируется в облако. Log4Shell показал обратную сторону: через лог можно не только украсть, но и проникнуть. Относись к логу как к публичному документу: пиши в него то, что не страшно показать.
Связанные понятия
- syslog — стандарт передачи и формата лог-сообщений между программами и системами (RFC 5424); заодно имя локальной службы, которая их собирает.
- Ротация логов (logrotate) — автоматическая замена растущего файла новым по размеру или времени с удалением старых.
- Структурное логирование — запись событий в машиночитаемом виде (обычно JSON) с именованными полями вместо свободного текста.
- Наблюдаемость (observability) — способность понять внутреннее состояние системы по её внешним сигналам: логам, метрикам и трассам.
- Correlation ID / trace ID — сквозной идентификатор запроса, который проставляется во все записи всех сервисов, чтобы их можно было склеить.
- Write-ahead log (WAL) — журнал упреждающей записи в базах данных: изменение сначала пишется в лог, потом в данные; по нему база восстанавливается после сбоя.
- Аудит-лог — лог с гарантиями полноты и неизменности, отвечающий на «кто, что и когда сделал».
Литература и источники
- Jay Kreps, «The Log: What every software engineer should know about real-time data's unifying abstraction», 2013 (en) — эссе в блоге LinkedIn Engineering, искать по названию. Расширенная версия — книга «I Heart Logs», O'Reilly, 2014 (en).
- The Twelve-Factor App, фактор XI «Logs» — https://12factor.net/ru/logs (есть русская версия).
- RFC 5424 «The Syslog Protocol» — https://www.rfc-editor.org/rfc/rfc5424
- Martin Kleppmann, «Designing Data-Intensive Applications», 2017 (en); русское издание «Высоконагруженные приложения. Программирование, масштабирование, поддержка», Питер, 2018. Главы про репликацию и потоковую обработку — о логе как структуре данных.
- Charity Majors, Liz Fong-Jones, George Miranda, «Observability Engineering», O'Reilly, 2022 (en) — про переход от логов к наблюдаемости.
- Python Logging HOWTO — https://docs.python.org/3/howto/logging.html — лучшее короткое введение в модель «логгер / обработчик / форматтер».
- Wikipedia (en): «Logging (computing)», «Syslog» — https://en.wikipedia.org/wiki/Logging_(computing)
Где встретилось у меня
Вчера логи были главным каналом связи с работой, которая шла без меня: сутки на mac mini крутился сборщик подменных номеров, и о его состоянии я узнавал только через лог сборщика и лог процесса-сторожа, которые по расписанию читали дешёвые агенты. В другой задаче лог агента Росреестра честно рапортовал об успешной выгрузке, а файлов на диске не оказалось — и это стало правилом «успешный лог не равен результату». Ещё один журнал (звонков) выдал «тихий ноль», потому что скрипт, не залогинившись, получил страницу авторизации и молча счёл её пустой. Ну и сам этот блог — производная от лога: статью ты читаешь потому, что Claude Code пишет JSONL каждой сессии.
Краткое резюме
- Лог — только дописываемая, упорядоченная по времени последовательность событий; единственный способ узнать, что делала программа, когда никто не смотрел.
- Уровни (
DEBUG / INFO / WARNING / ERROR) — это не громкость, а адресат; порог уровня в проде — главный рычаг управления объёмом. - Хорошая запись содержит время в UTC, уровень, источник, сообщение и контекст (request id, PID); структурный JSON надёжнее свободного текста.
- Пиши в stderr/stdout и отдавай маршрутизацию окружению; не забывай про буферизацию, ротацию и централизованный сбор.
- Лог фиксирует, что программа о себе думает, а не что есть на самом деле: результат проверяется по результату, а лог только подсказывает, где искать.
- Секреты и персональные данные в лог не попадают никогда: лог — это публичный документ с долгой жизнью.