Обычный текстовый лог PostgreSQL - это поток строк, где нужную ошибку приходится выуживать по крупицам. Один запрос, один сбой, а вы уже тонете в каше из PID’ов, меток времени и фрагментов SQL. К счастью, начиная с 15‑й версии PostgreSQL появилась возможность сразу писать логи в структурированном виде - по‑человечески, в формате JSON. Рассказываем, как включить jsonlog, что именно попадает в такой лог и как встроить его в современный мониторинг без сюрпризов.
Зачем переходить на структурированные логи
В классических логах на stderr информация хоть и есть, но читать её машине неудобно. Каждое поле завёрнуто в общую строку, при смене локали или паттерна логов парсер ломается, а поиск конкретного сеанса превращается в регулярное шаманство.
Структурированный JSON-формат решает эти проблемы:
- Каждое событие - самостоятельный JSON-объект с фиксированными ключами.
- Инструменты сбора логов понимают JSON «из коробки», без настройки громоздких grok-шаблонов.
- Вы можете фильтровать по
error_severity,dbname,userилиstate_codeмгновенно. - Аналитика по времени сессии, количеству ошибок, проблемным запросам строится на порядок быстрее.
Проще говоря, jsonlog превращает лог PostgreSQL из чёрного ящика в прозрачный источник данных для проактивного управления базой.
Что такое jsonlog и с какой версии PostgreSQL он доступен
jsonlog - это встроенный в ядро PostgreSQL формат вывода логов. Он появился в версии PostgreSQL 15 как новый элемент параметра log_destination. Технически это третий файловый формат после привычных stderr и csvlog.
Принцип прост: коллектор логов записывает каждую запись как одну строку JSON, разделённую переводом строки. Никаких внешних расширений или обёрток - всё работает штатными средствами сервера.
Важно: jsonlog не заменяет системный stderr, а дополняет его. Вы можете оставить текстовые логи в неизменном виде и параллельно получать аккуратные JSON-файлы.
Пошаговое включение jsonlog
Настройка выполняется через знакомый postgresql.conf. При этом все привычные параметры ротации и каталогов остаются общими.
Основные параметры (log_destination, logging_collector)
Для активации нужно прописать формат в log_destination и обязательно включить коллектор логов. Без logging_collector = on файлы на диск писаться не будут.
# Основной минимум
log_destination = 'jsonlog'
logging_collector = on
Эти два параметра - фундамент. Если забудете про logging_collector, JSON‑файл просто не появится, а логи могут уйти только в stderr и потеряться при перезапуске.
Настройка каталога и имён файлов
JSON‑логи используют те же параметры, что и обычные текстовые:
log_directory = 'pg_log' # каталог относительно data-директории
log_filename = 'postgresql-%a.json' # шаблон с strftime-масками
Суффикс .json PostgreSQL добавляет автоматически, когда видит jsonlog в log_destination. В примере выше каждый день будет создаваться файл вида postgresql-Mon.json.
Комбинированное логирование (stderr + jsonlog)
Чтобы продолжать получать текстовые логи и одновременно JSON, перечислите оба направления:
log_destination = 'stderr,jsonlog'
С этим значением в log_directory окажутся два набора файлов: обычные .log (или без расширения) и параллельные .json. Такой дуплекс удобен на время перехода: вы сохраняете привычную картину, а JSON‑логи постепенно подключаете к централизованной системе.
Ротация и суффикс .json
Ротация управляется теми же знакомыми механизмами PostgreSQL. Можно задать log_rotation_age и log_rotation_size, или построить имя файла на масках %a, %d, %H - тогда новый файл будет создаваться по расписанию.
Следите, чтобы шаблон в log_filename сам по себе не содержал .json, иначе получите удвоение. Достаточно указать корень, а расширение добавится автоматически.
После изменения параметров достаточно выполнить pg_ctl reload либо SELECT pg_reload_conf(). Перезапуск сервера не требуется.
Анатомия одной JSON‑строки: все ключи и их смысл
Каждая строка JSON‑лога - это плоский объект с примерно двумя десятками ключей. Все они строго типизированы: строки, числа, иногда null для отсутствующих данных.
Вот основной костяк полей и их практическое применение:
| Ключ | Тип | Что значит |
|---|---|---|
timestamp |
string | Время события с миллисекундами, идеально для сортировки |
user |
string | Пользователь, под которым установлено соединение |
dbname |
string | База данных сессии |
pid |
number | ID серверного процесса, помогает связать с pg_stat_activity |
remote_host |
string | Адрес клиента (если есть) |
remote_port |
number | Порт клиента |
session_id |
string | Уникальный идентификатор сессии |
line_num |
number | Порядковый номер записи внутри одной сессии |
ps |
string | Отображение процесса, как в команде ps |
session_start |
string | Время старта сессии |
vxid |
string | Виртуальный ID транзакции |
txid |
string | Обычный ID транзакции (если назначен) |
error_severity |
string | Уровень сообщения: LOG, WARNING, ERROR, FATAL и т.д. |
state_code |
string | Код SQLSTATE, крайне полезен для классификации ошибок |
message |
string | Основное сообщение - то, что вы привыкли видеть в текстовом логе |
detail |
string | Детали ошибки, например нарушенное ограничение |
hint |
string | Подсказка по исправлению |
internal_query |
string | Внутренний запрос, породивший ошибку |
internal_position |
number | Позиция ошибки во внутреннем запросе |
context |
string | Контекст (трассировка) ошибки |
query |
string | Текст запроса пользователя, если включен log_statement или сработал log_min_duration_statement |
Поля из категории LOCATION (file, line, routine) также присутствуют отдельными ключами - они указывают исходный файл и функцию внутри PostgreSQL, где произошло событие.
Практический совет: для поиска ошибок чаще всего вы будете оперировать парой error_severity и state_code, для расследования сессионных проблем - session_id и session_start, а для аудита медленных запросов - query в сочетании с timestamp.
Что делать с JSON‑логами дальше: интеграция в стек мониторинга
Когда JSON‑файлы стабильно пишутся, следующий шаг - доставить их туда, где они принесут максимальную пользу.
Сбор и передача
Любой современный коллектор логов легко подхватывает файлы с расширением .json. Вы можете использовать:
- Filebeat с нативным модулем для PostgreSQL или простым вводом
filestream, - Vector - лёгкий агент, который парсит JSON прямо в источнике,
- Logstash или Promtail - как часть уже существующего пайплайна.
Никакой сложной обработки не требуется: на входе чистый JSON, достаточно направить его в нужное хранилище. При комбинированном логировании stderr,jsonlog важно следить, чтобы сборщик забирал только .json или фильтровал файлы по расширению, иначе получите дубли.
Разбор в централизованных системах
В Elasticsearch JSON‑логи индексируются без дополнительных преобразований - каждое поле автоматически становится отдельным атрибутом документа. В Grafana Loki достаточно определить в promtail метку filename, а содержимое и так останется структурированным. Если вы складываете логи в ClickHouse, то прямая вставка строк через INSERT ... FORMAT JSONEachRow или материализованные колонки на основе JSONExtract работают отлично.
Ценность здесь не в конкретной системе, а в том, что из лога сразу уходит этап сложного парсинга. Готовые поля error_severity и state_code позволяют моментально строить панели «Топ ошибок по кодам» или «Количество ERROR за последний час».
Примеры полезных запросов и дашбордов (идеи)
Не привязываясь к инструменту, вот что становится доступным:
- Срез по severity - подсчёт количества
ERROR,FATAL,WARNINGза период с группировкой поdbname. - Медленные запросы - если включён
log_min_duration_statement, можно отфильтровать строки, гдеqueryне пустой, и вывести топ по времени выполнения (полеdurationтакже доступно в JSON). - Активность пользователей - количество сессий по
userиremote_host. - Анализ сессии - по
session_idиsession_startможно построить полный трек действий клиента вплоть до ошибки.
Такие дашборды не требуют «волшебных» цифр - достаточно корректной группировки и выбора временного окна.
Типичные трудности и их решение
Логи не пишутся: забыли logging_collector = on
Самая частая причина, когда после log_destination = 'jsonlog' файлы на диске не появляются. Проверьте:
logging_collector = on
Без этой строки логи будут уходить только в stderr и останутся под управлением внешнего супервизора (systemd, pg_ctl). Включение коллектора безопасно, но потребует pg_ctl reload.
JSON‑файл не появляется или пишется в stderr
Если logging_collector активен, но файл всё равно не создаётся, проверьте log_directory - путь должен существовать и быть доступен для записи процессу PostgreSQL. Ещё одна причина: конфликт в шаблоне log_filename. Убедитесь, что в маске нет символов, недопустимых в имени файла на вашей файловой системе, и что не происходит наложения с другими процессами.
Иногда кажется, что JSON‑логи пишутся в stderr, потому что сборщик показывает и то, и другое. При комбинированном режиме всегда смотрите в log_directory - там должен лежать отдельный файл с суффиксом .json.
Слишком много данных, рост дискового пространства
JSON немного более многословен, чем stderr, но разница не критична для большинства инсталляций. Если объём становится проблемой, используйте стандартные приёмы:
- Уменьшите уровень логирования:
log_min_messages = warningилиerror- для продового мониторинга этого часто достаточно. - Исключите вывод SQL‑запросов через
log_statement = 'none'и поднимайте порогlog_min_duration_statementдо реально «тяжёлых» значений. - Настройте агрессивную ротацию по размеру и возрасту, а старые файлы архивируйте или удаляйте.
- Отправляйте логи в централизованное хранилище и освобождайте локальный диск.
Точных данных о накладных расходах jsonlog по сравнению с stderr в процентах нет - они сильно зависят от характера нагрузки. В большинстве случаев выигрыш от структурирования перевешивает небольшое увеличение объёма.
FAQ: ответы на горячие вопросы
1. С какой версии PostgreSQL можно использовать jsonlog?
Начиная с PostgreSQL 15. В более ранних версиях формат недоступен, и параметр log_destination = 'jsonlog' приведёт к ошибке.
2. Нужно ли перезагружать сервер после смены параметров?
Нет, достаточно выполнить pg_ctl reload или вызвать SELECT pg_reload_conf(). Все параметры логирования перечитываются без прерывания обслуживания.
3. Можно ли оставить старый текстовый лог и одновременно писать JSON?
Да, укажите log_destination = 'stderr,jsonlog'. В каталоге log_directory будут создаваться оба типа файлов. Это отличный способ мягкого перехода.
4. Как узнать имя текущего файла JSON‑логов?
Воспользуйтесь функцией pg_current_logfile('jsonlog'). Она вернёт полный путь к актуальному файлу, включая название. Аналогично работает pg_current_logfile('stderr') для текстового лога.
5. Попадают ли в JSON‑лог медленные запросы и ошибки уровня STATEMENT?
Да, если у вас настроен log_min_duration_statement или включён log_statement, то текст запроса окажется в поле query, а событие будет записано со severity LOG. Ошибки сервера и сообщения уровня STATEMENT также попадают в JSON с соответствующими кодами.
6. Как настроить ротацию JSON‑логов без внешних утилит?
Используйте встроенные механизмы: задайте log_rotation_age (максимальное время жизни файла) и log_rotation_size (предельный размер). Можно также задействовать маски времени в log_filename, например postgresql-%H.json - тогда новый файл будет создаваться каждый час.
7. Что делать, если лог‑файл внезапно перестал обновляться?
Сначала проверьте, не достигнут ли лимит ротации, и не смонтирован ли диск в read-only. Убедитесь, что процесс PostgreSQL не завис и что logging_collector не отключён динамически (хотя для него это нетипично). Если файл перестал расти, а новые записи не появляются, попробуйте принудительно переоткрыть логи через pg_rotate_logfile().
8. Безопасно ли хранить JSON‑логи с запросами пользователей?
Сами по себе JSON‑логи - это просто файлы, их безопасность определяется уровнем доступа каталога log_directory. Если вы пишете в лог тексты запросов (log_statement или log_min_duration_statement), они окажутся в открытом виде. Ограничьте доступ к файлам средствами ОС и следите, чтобы централизованные системы сбора также защищали передаваемые данные. При необходимости маскируйте конфиденциальную информацию до записи или исключайте детальные запросы из логов на продуктивных базах.
Заключение: чистые логи - спокойный сон DBA
jsonlog - не просто очередная «галочка» в changelog’е PostgreSQL. Это прямой путь к тому, чтобы перестать тратить время на разбор текстовой каши и начать видеть реальное состояние сервера с одного взгляда. Пара дополнительных строк в конфигурации, и ваши логи превращаются в готовый источник данных для любого мониторингового стека.
Начните с комбинированного режима, протестируйте на неProduction-окружении, а затем делайте JSON‑логи основным форматом. Когда в три часа ночи вам понадобится понять, почему упало приложение, структурированный лог скажет всё сам - быстро и без регулярных выражений.



.svg.webp)





