Зачем управлять уровнями логирования в СУБД
Уровень логирования работает как фильтр: всё, что ниже выставленного порога, в файл не попадает. В PostgreSQL этим порогом управляет log_min_messages, в MySQL - log_error_verbosity, в MongoDB - systemLog.verbosity с уточнением по компонентам. Одно значение в конфиге решает, найдёте вы причину инцидента за минуту или будете собирать картину по косвенным признакам.
Практических задач, которые закрывает настройка уровней, три. Отладка медленных запросов требует длительностей и планов выполнения. Аудит доступа отвечает на вопросы, кто подключился, откуда и какие объекты менял. Мониторинг ошибок даёт поток событий для алертов: WARNING, ERROR, FATAL, PANIC.
Цена ошибки высока в обе стороны. log_statement = 'all' на базе с пятью тысячами транзакций в секунду пишет десятки гигабайт в сутки, и диск заканчивается быстрее, чем вы вспомните про ротацию. Обратный случай незаметнее: при log_min_messages = fatal предупреждения о нехватке места и ошибки транзакций в лог не пишутся, а первый сигнал о проблеме приходит от пользователей.
Сравним три движка по шкалам и основным параметрам.
| СУБД | Уровни | Основной параметр | По умолчанию | Куда пишет |
|---|---|---|---|---|
| PostgreSQL | DEBUG5 - DEBUG1, INFO, NOTICE, WARNING, ERROR, LOG, FATAL, PANIC | log_min_messages | warning | stderr, файл, syslog, csvlog |
| MySQL | ERROR, WARNING, NOTE | log_error_verbosity | 2 | error log, slow log, general log |
| MongoDB | verbosity 0 - 5 по компонентам | systemLog.verbosity, systemLog.component.*.verbosity | 0 | файл или syslog |
Матрица выбора под задачу выглядит так.
| Задача | PostgreSQL | MySQL | MongoDB |
|---|---|---|---|
| Медленные запросы | log_min_duration_statement = 1000 | slow_query_log = 1, long_query_time = 1 | operationProfiling.mode: slowOp, slowOpThresholdMs: 100 |
| Аудит доступа | log_connections, log_disconnections, log_statement = 'ddl' | audit_log (Enterprise), server_audit (MariaDB) | auditLog (Enterprise) |
| Мониторинг ошибок | log_min_messages = warning, log_min_error_statement = error | log_error_verbosity = 2 | systemLog.verbosity: 0, systemLog.component.accessControl.verbosity: 1 |
Какие события вообще стоит писать, а какие создают шум и риски для безопасности, разбираем в отдельном материале про критерии эффективного логирования.
Уровни логирования в PostgreSQL: от DEBUG до PANIC
В PostgreSQL все сообщения выстроены в одну шкалу серьёзности. log_min_messages задаёт минимальный уровень, который попадёт в серверный лог, и по умолчанию равен warning, поэтому INFO и NOTICE в файл не пишутся. Это значение зафиксировано в официальной документации PostgreSQL в разделе Error Reporting and Logging.
- DEBUG1 - DEBUG5: внутренние детали работы. debug1 показывает планы и ключевые шаги исполнения, debug5 добавляет разбор блокировок и работу с буферами. Объём логов растёт в разы на каждом шаге.
- INFO: сообщения, запрошенные пользователем, например вывод VACUUM VERBOSE. Всегда уходят клиенту.
- NOTICE: уведомления о полезных событиях, например об усечении длинного идентификатора до 63 символов.
- WARNING: оператор выполняется, но ситуация требует внимания.
- ERROR: ошибка оператора, текущая транзакция прерывается.
- LOG: сообщения для администратора: контрольные точки, autovacuum, переключение WAL. В шкале серьёзности LOG стоит между ERROR и FATAL.
- FATAL: сессия завершается, например при неверном пароле или исчерпании соединений.
- PANIC: сбой всего кластера, все сессии обрываются, база уходит в recovery.
Пороги доставки клиенту и в файл различаются. За лог отвечает log_min_messages, за сообщения клиенту - client_min_messages. Текст оператора, который привёл к ошибке, добавляется по порогу log_min_error_statement: значение warning означает, что в лог попадёт и SQL, вызвавший предупреждение.
Как выбрать уровень для отладки, аудита и мониторинга
Для отладки конкретной проблемы включайте debug1 и не глубже. debug4 и debug5 имеет смысл держать минутами и на тестовом стенде, потому что на нагруженной базе они добавляют сотни мегабайт в час и заметно нагружают диск. Если нужны планы выполнения медленных запросов, включите расширение auto_explain и параметр auto_explain.log_min_duration: тогда планы попадут в лог только для запросов дольше порога.
Для аудита доступа достаточно log_connections и log_disconnections, которые фиксируют факт подключения, пользователя, базу и адрес клиента. Тексты операторов добавляет log_statement: значение ddl пишет только изменения схемы, mod - ещё и INSERT, UPDATE, DELETE, all - всё подряд. Значение all оправдано на время разбора инцидента, не как постоянная конфигурация.
Для мониторинга ошибок рабочий набор: log_min_messages = warning и log_min_error_statement = error. В лог попадут предупреждения, ошибки, фатальные события и паники, то есть всё, на что стоит вешать алерты. Схему доступа к самой базе проверьте по чек-листу аудита PostgreSQL, MySQL и MongoDB.
Пример настройки log_min_messages и slow_query_log
Отдельного параметра slow_query_log в PostgreSQL нет, его роль выполняет log_min_duration_statement. Значение указывается в миллисекундах: 1000 означает запись всех операторов, которые выполнялись секунду и дольше, -1 отключает логирование, 0 пишет вообще всё.
# Уровни сообщений в серверный лог log_min_messages = warning log_min_error_statement = error # Логирование медленных запросов: 1000 мс = 1 секунда log_min_duration_statement = 1000 # Аудит подключений log_connections = on log_disconnections = on log_statement = 'ddl' # Формат строки: время, PID процесса, пользователь@база log_line_prefix = '%m [%p] %q%u@%d ' # Файлы и встроенная ротация log_destination = 'stderr' log_directory = 'log' log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' log_rotation_age = 1d log_rotation_size = 100MB log_truncate_on_rotation = on
Разберём ключевые строки. log_min_messages = warning оставляет в логе предупреждения и выше. log_min_error_statement = error добавляет текст оператора, который завершился ошибкой. log_min_duration_statement = 1000 даёт основу для анализа производительности. log_line_prefix с %m, %p, %q, %u и %d нужен, чтобы по строке можно было восстановить время, процесс, пользователя и базу; символ %q обрывает шаблон для фоновых процессов, у которых нет пользователя и базы. log_rotation_age и log_rotation_size включают встроенную ротацию, а log_truncate_on_rotation не даёт именам файлов накапливать старые данные.
Применение настроек без перезапуска и проверка результата:
SELECT pg_reload_conf();
SHOW log_min_messages;
SHOW log_min_duration_statement;
SELECT name, setting, unit
FROM pg_settings
WHERE name IN ('log_min_messages', 'log_min_duration_statement', 'log_statement', 'log_connections');
pg_reload_conf() перечитывает postgresql.conf на живой базе, рестарт для этих параметров не требуется. Значение log_min_messages = debug1 на нагруженной системе перечитайте дважды: объём логов вырастет на порядок, а вместе с ним и нагрузка на диск.
Уровни логирования в MySQL: ERROR, WARNING, NOTE
В MySQL уровней всего три, и управляет ими log_error_verbosity. Значение 1 пишет только ошибки, 2 добавляет предупреждения и применяется по умолчанию, 3 включает заметки NOTE и подробности о работе сервера. Значение по умолчанию 2 подтверждено официальной документацией MySQL Server. Параметр динамический, поэтому SET GLOBAL log_error_verbosity = 3 действует без рестарта.
Уровни привязаны к типу журнала. Slow query log и general query log собственной шкалы не имеют: они либо включены целиком, либо выключены.
| Журнал | Параметры | Что записывает | Когда включать |
|---|---|---|---|
| Error log | log_error, log_error_verbosity | Ошибки запуска, InnoDB, репликации | Постоянно |
| Slow query log | slow_query_log, long_query_time | Запросы дольше порога | Постоянно в продакшене |
| General query log | general_log, log_output | Каждый оператор от клиента | Только на время отладки |
| Audit log | audit_log (Enterprise), server_audit (MariaDB) | Подключения, DDL, доступ к таблицам | Когда нужен аудит |
| Binary log | log_bin | Изменения данных для репликации | Репликация и восстановление |
Настройка slow_query_log и long_query_time
[mysqld] log_error = /var/log/mysql/error.log log_error_verbosity = 2 slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log long_query_time = 1 log_queries_not_using_indexes = 1 log_throttle_queries_not_using_indexes = 60 # general log держим выключенным general_log = 0 general_log_file = /var/log/mysql/general.log
long_query_time по умолчанию равен 10 секундам, минимальное значение - 0; значение 1 секунда даёт заметно больше полезных данных. Оба значения зафиксированы в документации MySQL по slow query log. log_queries_not_using_indexes = 1 добавляет в slow log запросы без индексов, и именно этот параметр чаще всего забивает диск: на плохо оптимизированной схеме он превращает slow log в general log. throttling через log_throttle_queries_not_using_indexes ограничивает запись одинаковых запросов, например одной строкой в 60 секунд.
Включить и проверить на живой базе:
SET GLOBAL slow_query_log = 1; SET GLOBAL long_query_time = 1; SET SESSION long_query_time = 0.1; SHOW VARIABLES LIKE 'slow_query_log%'; SHOW VARIABLES LIKE 'long_query_time'; SHOW GLOBAL STATUS LIKE 'Slow_queries';
Анализ slow log без ручного чтения файла:
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log pt-query-digest /var/log/mysql/slow.log > /tmp/slow-report.txt
mysqldumpslow сортирует запросы по суммарному времени, pt-query-digest строит профиль нагрузки с распределением по запросам и таблицам. Порог slow_query_log имеет смысл пересматривать вместе с ростом нагрузки, а общие подходы к настройке под пиковые значения собраны в материале про производительность PostgreSQL и MySQL под нагрузкой.
Аудит доступа через general_log и audit_log
general_log пишет каждый оператор от каждого клиента. Включается одной командой на время отладки:
SET GLOBAL log_output = 'TABLE'; SET GLOBAL general_log = 'ON'; SELECT event_time, user_host, argument FROM mysql.general_log ORDER BY event_time DESC LIMIT 20;
Вывод в таблицу удобен для выборок, вывод в файл дешевле по нагрузке. В обоих случаях логи содержат литералы запросов с персональными данными, поэтому доступ к ним ограничивают и выключают сбор сразу после разбора: SET GLOBAL general_log = 'OFF'. На боевой базе general_log добавляет заметный оверхед на каждый запрос.
Для постоянного аудита используйте плагин audit_log в MySQL Enterprise или MariaDB Audit Plugin в сборках MariaDB. Плагин умеет писать только нужные события: подключения, изменения схемы, доступ к конкретным таблицам. Проверить, не осталось ли лишних прав у учётных записей, помогает руководство по аудиту безопасности баз данных.
Логирование в MongoDB: уровни и параметры
В MongoDB нет одной шкалы на весь сервер. Вместо неё используется verbosity от 0 до 5 для каждого компонента: query, command, accessControl, storage, network, replication, index, write. Уровень 0 даёт обычные информационные сообщения, 1 и выше включают отладочный вывод с растущей детализацией. systemLog.verbosity задаёт общий уровень, а блок component переопределяет его точечно. Полный список параметров приведён в справочнике конфигурационных опций MongoDB.
Настройка verbosity и profiling в mongod.conf
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
verbosity: 0
component:
query:
verbosity: 1
accessControl:
verbosity: 1
operationProfiling:
mode: slowOp
slowOpThresholdMs: 100
verbosity выше 2 резко увеличивает объём файла: на активной базе debug-вывод по компоненту query измеряется гигабайтами в сутки. Значение 1 по конкретному компоненту даёт компромисс, который можно держать включённым постоянно. destination: file пишет в path, вариант syslog отправляет события в системный журнал.
Профилировка отвечает за медленные операции и пишет результат не в файл лога, а в системную коллекцию system.profile. slowOpThresholdMs задаёт порог в миллисекундах; в приведённом примере конфигурации используется значение 100. Официальное значение по умолчанию для этого параметра в переданных материалах не подтверждено, поэтому перед изменением сверьтесь с документацией вашей версии MongoDB. Управление на живой базе:
db.setLogLevel(1, "query");
db.adminCommand({ setParameter: 1, logComponentVerbosity: { query: { verbosity: 1 } } });
db.setProfilingLevel(1, { slowms: 100 });
db.getProfilingStatus();
db.system.profile.find({ millis: { $gt: 100 } }).sort({ ts: -1 }).limit(10);
В конфиге порог называется slowOpThresholdMs, в командах setProfilingLevel исторически используется slowms: оба имени задают одно и то же. Режим all профилирует каждую операцию и подходит только для короткой диагностики. Файл лога удобно разбирать утилитой mloginfo из набора mtools:
mloginfo --queries /var/log/mongodb/mongod.log mloginfo --connections /var/log/mongodb/mongod.log
Типичные ошибки конфигурации mongod и способы их обойти разобраны в гайде про MongoDB в продакшене.
Аудит доступа в MongoDB
auditLog доступен только в MongoDB Enterprise. В Community Edition этого механизма нет, поэтому аудит доступа закрывают логированием компонента accessControl и метриками подключений. Пример блока для Enterprise:
security:
authorization: enabled
auditLog:
destination: file
format: JSON
path: /var/log/mongodb/audit.log
filter: '{ atype: { $in: [ "authenticate", "authCheck" ] } }'
Фильтр оставляет только события аутентификации и проверки прав, иначе файл аудита растёт со скоростью лога запросов. Формат JSON упрощает разбор внешними системами: строки можно отдавать в Elasticsearch или Loki без дополнительного парсинга. Включение аудита добавляет нагрузку на диск, поэтому сначала оцените поток событий на стенде.
В Community Edition контроль доступа строится на ролевой модели и мониторинге числа соединений:
db.serverStatus().connections;
db.adminCommand({ logRotate: 1 });
Сбор, ротация и анализ логов СУБД
Ротация - обязательный элемент конфигурации, а не опция. Логи без ограничения по размеру съедают диск, а вместе с ним и саму базу. Работают три подхода: встроенная ротация средствами СУБД, logrotate и централизованный сбор через syslog или journald. Выбирайте один основной и не смешивайте: встроенная ротация PostgreSQL вместе с внешним logrotate без copytruncate даёт пустые файлы и потерянные записи.
Настройка logrotate для PostgreSQL, MySQL и MongoDB
/var/log/postgresql/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 640 postgres postgres
sharedscripts
postrotate
/usr/bin/pg_ctlcluster 16 main reload > /dev/null 2>&1
endscript
}
/var/log/mysql/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 640 mysql adm
postrotate
test -x /usr/bin/mysqladmin && mysqladmin --defaults-file=/etc/mysql/debian.cnf flush-logs
endscript
}
/var/log/mongodb/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 640 mongodb mongodb
postrotate
/bin/kill -SIGUSR1 $(cat /var/run/mongodb/mongod.pid 2>/dev/null) 2>/dev/null
endscript
}
Параметры означают следующее. daily задаёт суточный интервал, rotate 14 хранит две недели истории, compress сжимает старые файлы, delaycompress откладывает сжатие на цикл, чтобы процесс не писал в только что закрытый файл. missingok и notifempty защищают от ошибок при отсутствии файлов. create 640 с указанием владельца и группы обязателен: после ротации новый файл получит права демона, иначе СУБД не сможет в него писать.
По умолчанию MongoDB использует поведение --logRotate rename: mongod или mongos переименовывает текущий лог-файл, добавляя к имени метку времени UTC, открывает новый лог-файл, закрывает старый и направляет все новые записи в новый файл. Это подтверждено официальной документацией MongoDB. Вариант reopen, при котором процесс переоткрывает тот же файл по сигналу SIGUSR1, в переданных материалах не подтверждён, поэтому при использовании SIGUSR1 в postrotate обязательно сверьтесь с документацией вашей версии и проверьте фактическое поведение на стенде. Аналогично: перечитывание конфигурации PostgreSQL по SIGHUP и переоткрытие логов MySQL через mysqladmin flush-logs в переданных материалах не подтверждены, хотя эти механизмы широко используются на практике.
Для централизованного сбора подойдут rsyslog или journald. В journald.conf ограничьте SystemMaxUse, иначе журнал вытеснит данные приложения. MongoDB умеет писать напрямую в syslog, а PostgreSQL требует смены log_destination на syslog и стиль префикса syslog. Ограничение: journald хранит записи в двоичном формате, и разбор внешними утилитами без экспорта невозможен.
Инструменты анализа логов: pgBadger, pt-query-digest, mtools
pgBadger собирает HTML-отчёт по логам PostgreSQL: топ запросов, время отклика, ошибки, подключения. Утилита разбирает только логи с подходящим log_line_prefix, потому что идентифицирует записи по времени, PID, пользователю, базе и адресу клиента.
pgbadger /var/log/postgresql/postgresql-16-main.log -o /var/www/reports/pg-report.html
pt-query-digest анализирует slow log MySQL и Percona Server, группируя запросы по подписи и показывая суммарное время, число вызовов и долю от общей нагрузки:
pt-query-digest --limit 20 /var/log/mysql/slow.log
mtools закрывает MongoDB: mloginfo собирает статистику по запросам и подключениям, mlogfilter отбирает нужные записи по времени и компоненту. Запускайте разбор по расписанию или после релиза, а не разово при инциденте.
Практические рекомендации и чек-лист
- В продакшене держите log_min_messages = warning, log_error_verbosity = 2, systemLog.verbosity: 0. Уровни DEBUG и verbosity выше 2 включайте точечно и на ограниченное время.
- Логируйте медленные запросы с явным порогом: log_min_duration_statement = 1000, long_query_time = 1, slowOpThresholdMs = 100. Начните с порога выше и снижайте по мере появления свободного места.
- Для аудита доступа используйте log_connections и log_disconnections с log_statement = 'ddl' в PostgreSQL, audit_log или server_audit в MySQL, auditLog в MongoDB Enterprise. general_log и log_statement = 'all' оставляйте только на период разбора.
- Настройте ротацию одним способом: logrotate с daily, rotate 14 и compress либо встроенные параметры log_rotation_age и log_rotation_size. Для MongoDB учитывайте, что по умолчанию используется поведение rename, а вариант reopen требует проверки на вашей версии.
- Ограничьте доступ к файлам логов правами 640 и отдельной группой. В строках встречаются литералы запросов, адреса клиентов и имена учётных записей.
- Повесьте алерты на размер каталога с логами, на события уровня FATAL и PANIC, а также на рост числа подключений через db.serverStatus().connections.
- Проверяйте конфигурацию перед применением: SELECT pg_reload_conf() в PostgreSQL действует без рестарта, в MySQL часть параметров динамические, а verbosity MongoDB меняется через db.setLogLevel без перезапуска.
Чек-лист перед тем, как считать настройку логирования завершённой:
- Уровни соответствуют задаче: DEBUG и verbosity выше 2 выключены в продакшене.
- Порог медленных запросов задан явно и записан в конфиге, а не выставлен вручную в сессии.
- Ротация настроена, старые файлы сжимаются, глубина хранения не меньше 7-14 дней.
- general_log выключен, log_queries_not_using_indexes ограничен по частоте или отключён.
- Доступ к каталогу логов ограничен, у файлов права 640 и корректный владелец.
- Алерты на размер логов и на критичные уровни настроены и проверены тестовым событием.
- Инструмент анализа (pgBadger, pt-query-digest, mtools) запускается по расписанию.
- Изменения конфигурации применены без рестарта там, где это возможно, и проверены командой SHOW или SELECT из pg_settings.
Начните с одной базы: выставьте порог медленных запросов, включите ротацию и посмотрите через неделю, сколько данных собралось. Дальше добавьте аудит доступа и алерты, опираясь на реальный объём логов, а не на предположения.