У меня rsyslog 4.6.4 настроен для записи журналов почты в базу данных PostgreSQL. Все работает нормально, пока сообщение журнала не будет содержать обратную косую черту, как в этом примере:
12 июня, 11:37:46 dc5 postfix / smtp [26475]: Vk0nYDKdH3sI: to = <-----@----.--->, relay = ----.--- [--- . ---. --- .---]: 25, задержка = 1.5, задержки = 0.77 / 0.07 / 0.3 / 0.35, dsn = 4.3.0, статус = отложено (хост ----.--- [ ---. ---. --- .---] сказал: 451 4.3.0 Ошибка записи в файл d: \ pmta \ spool \ B \ 00000414, status = ERROR_DISK_FULL в "DATA" (в ответ на конец Команда DATA))
Выше приведена запись журнала, записанная в /var/log/mail.log. Это правильно. Проблема в том, что символы обратной косой черты в имени файла интерпретируются как escape-символы при отправке по следующему рецепту SQL:
$template dcdb, "SELECT rsyslog_insert(('%timereported:::date-rfc3339%'::TIMESTAMPTZ)::TIMESTAMP,'%msg:::escape-cc%'::TEXT,'%syslogtag%'::VARCHAR)",STDSQL
:syslogtag, startswith, "postfix" :ompgsql:/var/run/postgresql,dc,root,;dcdb
В результате rsyslog_insert()
хранимая процедура получает следующее значение для as msg
:
Vk0nYDKdH3sI: to = <-----@----.--->, relay = ----.--- [---. ---. --- .---]: 25 , delay = 1.5, delay = 0.77 / 0.07 / 0.3 / 0.35, dsn = 4.3.0, status = deferred (хост ----.--- [199.85.216.241] сказал: 451 4.3.0 Ошибка записи в файл d : pmtaspoolB
В \p
, \s
, \B
и \0
в имени файла интерпретируются PostgreSQL как буквальные p
, s
, и B
за которым следует символ NULL, что приводит к раннему завершению строки. Это поведение легко подтвердить с помощью:
dc=# SELECT 'd:\pmta\spool\B\00000414';
?column?
--------------
d:pmtaspoolB
(1 row)
dc=#
Есть ли способ исправить эту проблему? Есть ли способ, которым я не нахожу в документах rsyslog, чтобы включить \
в \\
?
Во-первых, вам следует ДЕЙСТВИТЕЛЬНО использовать параметризованные запросы и подготовленные операторы при передаче произвольных строк.
(Вероятно, это не ваша вина - rsyslog почти наверняка виноват в этом ужасе).
Если вы не можете переключиться на лучшую структуру запроса, Postgres encode
функция, вероятно, может вам помочь (см. документацию здесь) - укажите кодировку escape
и Postgres удобно удвоит все ваши обратные косые черты в строке, которую вы ему передаете.
Обратите внимание: если вы чувствуете себя особенно педантично, вы можете включить standard_conforming_strings
, что заставляет Postgres обрабатывать \
символ в строке как буквальная обратная косая черта, а не его историческое (unix-y) поведение, когда он рассматривается как escape-символ.
Жизнеспособность такого изменения в вашей среде зависит от множества факторов ...