PHPのerror_logをsyslogに設定したら文字化け(FreeBSD固有の問題だった)

PHPでバッチ処理を書いているときの覚書。

環境: FreeBSD 14.1-RELEASE-p6, PHP 8.3.6

PHPエラーはシステムログに設定する。
# php --ini
# less /usr/local/etc/php.ini

error_log = syslog

これで「/var/log/messages」に出力されるようになる。
PHPエラー時に確認してみると文字化けしている。
# less /var/log/messages

文字コードの確認。
# less /usr/local/etc/php.ini

default_charset = "UTF-8"

UTF-8になっている。
システムの言語設定を表示。
# locale

LANG=C.UTF-8
LC_CTYPE="C.UTF-8"
LC_COLLATE="C.UTF-8"
LC_TIME="C.UTF-8"
LC_NUMERIC="C.UTF-8"
LC_MONETARY="C.UTF-8"
LC_MESSAGES="C.UTF-8"
LC_ALL=

各説明は下記サイトを参考に。
参考: ロケール環境変数について - IBM Documentation

これを日本語に設定すればいいのかな?
設定できるlocale一覧を表示。
# locale -a

FreeBSDは/etc/login.confを編集する。
参考: Chapter 25. Localization - i18n/L10n Usage and Setup | FreeBSD Documentation Portal
# less /etc/login.conf

default:\
        ...
        :charset=UTF-8:\
        :lang=ja_JP.UTF-8:

/etc/login.confを編集したときはcapability databaseを更新する必要があるみたい。
# cap_mkdb /etc/login.conf

一旦ログインしなおして確認。
# locale

LANG=ja_JP.UTF-8
LC_CTYPE="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_ALL=

ja_JP.UTF-8になった。
PHPでエラーを起こして確認。
# tail -f /var/log/messages

文字化けしている…。
syslogを再起動してみる。
サービス名を確認して再起動。
# service -l
# service restart syslogd

restart does not exist in /etc/rc.d or the local startup
directories (/usr/local/etc/rc.d), or is not executable

rc.dを直接実行する。
# /etc/rc.d/syslogd restart

PHPでエラーを起こして確認。
# tail -f /var/log/messages

文字化けしている…。


Google AI Studioで聞いてみた。
Model: Gemini 1.5 Pro

例えば下記のような文字化けになっています。
なぜこのような文字化けとなるか分かりますか?
---
Dec  9 10:10:45 vm-dev2 php[1202]: PHP   6. wp_trigger_error($function_name = '', $message = '<E9>M-^V<A2><E6>M-^U<B0>...

AIの回答。

この文字化けは、UTF-8 でエンコードされた日本語が、ISO-2022-JP として誤って解釈されているために発生しています。

すごい。
具体的な解決策も提示してくれる。


正しいかどうか疑問に思いながらも提示通りに修正してみる。
# less /etc/syslog.conf

# Add this line
!*.*                                            ;encoding(utf-8)

syslogdを再起動。
# /etc/rc.d/syslogd restart

AIの提案で知ったloggerコマンドで直接エラーを起こす。
# logger -t test 'test日本語test'

確認
# less /var/log/messages

文字化けしている…。
PHPの設定とは関係ないことは分かった。

AIの提案で知ったsyslogdをdebugモードで起動する方法を試す。
# /etc/rc.d/syslogd stop
# syslogd -d

loggerコマンドで直接エラーを起こす。
# logger -t test 'test日本語test'

そしてAIに聞いてみた。

デバッグログの出力 test�M-^W��M-^\��M-^^test から、syslogd はメッセージを UTF-8 として正しく受信しているものの、何らかの理由で表示時に文字化けが発生していることが分かります。 � は、無効なバイトシーケンスを表す置換文字です。 M-^W などは、UTF-8 のマルチバイト文字の一部が誤って解釈されていることを示唆しています。

この状況では、syslogd の出力先の設定、またはコンソール自体の設定に問題がある可能性が高いです。

UTF-8のPHPファイルをlessで表示しても問題ないので、コンソールは問題ないと思う。

出力先ファイルのエンコーディング確認。
# file /var/log/messages

/var/log/messages: ISO-8859 text, with very long lines (1708)

syslogd が UTF-8を受け取ったのをISO-2022-JPに変換している。
つまりsyslogdのバグかな?


ここでCentOS Stream 9でloggerを実行してみた。
# logger -t test 'test日本語test'
# less /var/log/messages

文字化けしてない!
ということでFreeBSDのsyslog固有の問題です。


バッチログはファイルに出力することにした。


【関連記事】