
はじめに
WordPress から外部のログ集約サービスへエラーを送る仕組みを運用していると、「ある日を境に記録が止まった」という場面に出会います。
このとき最初に疑いたくなるのは送信側の故障ですが、実際に点検してみると、原因は別のところにありました。
実運用しているサービスで点検したところ、「送る条件に当たる事象そのものが止まった」可能性が高いと分かりました。
一方で、点検の過程で Fatal を取りこぼす本物の欠陥も見つかっています。
この記事では、その点検の型と、見つかった欠陥の直し方、本番で安全に疎通確認する WP-CLI コマンドの作り方をまとめます。
こんな人におすすめ
- WordPress のエラーを外部サービスへ送る仕組みを自作・運用している方
register_shutdown_functionとerror_get_last()で Fatal を拾っている方- 「通知が止まった」ときの切り分けの順番を整理したい方
- 本番で安全に使える点検用の WP-CLI コマンドを作りたい方
「止まった」は「壊れた」とは限らない
記録が止まったとき、仮説を立てる順番で調査の速さが変わります。
目安として、次の順で確認すると早く絞り込めました。
- 送信条件を一覧にする(例:Fatal、特定の名前空間の 5xx)
- 受け手側の集計を見て、実際に届いていた記録の種類を確認する
- 届いていた記録が 1 種類のエラーだけなら、その事象が消えた可能性を先に疑う
今回は、届いていた記録が 1 種類のエラーだけでした。
「送信の故障」より先に「送る対象の事象が消えた」を疑うと、無駄な調査を減らせます。
ただし、コードを突き合わせる過程で、送信側にも別の欠陥が見つかりました。次の節で説明します。
error_get_last() は後続のエラーで上書きされる
register_shutdown_function で登録した関数は、WordPress の shutdown アクションや他プラグインの shutdown 処理より後に動きます。
その間に Notice が 1 つ出るだけで、error_get_last() の中身は Notice に置き換わり、Fatal の情報が消えます。
WP_DEBUG が無効の環境ではログにも残らないため、気づくのが難しい欠陥です。
対策は、取れる一番早い時点で Fatal を控えておくことです。
shutdown アクションを最優先で実行し、wp_php_error_args フィルターでも控えます。
// 自分の shutdown 関数は、他の shutdown 処理より後に動く。
// 非致命エラーで error_get_last() が上書きされるので、Fatal は早い時点で控える。
\add_action( 'shutdown', [ __CLASS__, 'capture_last_error' ], PHP_INT_MIN );
\add_filter( 'wp_php_error_args', [ __CLASS__, 'on_php_error_args' ], PHP_INT_MIN, 2 );
public static function capture_fatal( ?array $error ): void {
if ( null === $error || null !== self::$captured_fatal ) {
return; // 最初の1件を優先し、後から上書きしない
}
if ( 0 === ( ( $error['type'] ?? 0 ) & self::FATAL_MASK ) ) {
return;
}
self::$captured_fatal = $error;
}
ポイントは 2 つあります。
- 致命的エラーの型判定を
capture_fatalの 1 か所にまとめ、フック経由でも shutdown 経由でも同じ経路で控える - 最初の 1 件を優先し、後から置き換えない
失敗ログには例外メッセージを出さない
送信に失敗したときのログにも注意が必要です。
getMessage() や WP_Error の全文には、URL などが混ざることがあります。
ログに秘匿したい情報が漏れないよう、例外は型(クラス名)だけを残します。
} catch ( \Throwable $e ) {
// メッセージには URL 等が入りうるので、型だけを残す
error_log( '[Reporter] on_shutdown failed: ' . get_class( $e ) );
}
WP_Error の場合も、エラーコードと cURL 番号だけに絞ると安全です。
受け手のスキーマ検査を送信側のテストに写す
点検では、受け手のスキーマ検査で弾かれる payload の欠陥も見つかりました。
たとえば request.url が空だと、相手側が 400 を返す、といった条件です。
こうした欠陥は、送信側だけをテストしていても見つかりません。
相手のスキーマを PHP のテストヘルパに写し、payload が通ることをテストで固定しておくと、再発を防げます。
写し元のコミット SHA をコメントに明記しておくと、相手側の変更に追従するときに差分を追いやすくなります。
本番で安全に使える点検用 WP-CLI コマンド
運用者が本番で疎通確認できるよう、status と test の 2 つの WP-CLI コマンドを用意しました。
設計で意識したのは、「出すものを絞る」ことです。
- 出す:ホスト名、設定の有無(yes/no)、ステータス、応答コード
- 出さない:URL 全体、秘密鍵、応答本文
本番へ実送信する test には、次の安全策を入れています。
- 確認プロンプトを付ける
- ERROR 形の送信は
--dry-runなしでは拒否する(Issue の起票や通知が走るため)
# 設定の状態を確認する(送信はしない)
wp <command> log-hub status
# 疎通確認(ERROR 形は --dry-run が必須)
wp <command> log-hub test --dry-run
<command> の部分は、お使いのプラグインの名前空間に置き換えてください。
つまづきやすいポイント
statusは CLI の環境しか見ていません。wp_get_environment_type()は定数より先に環境変数を読むため、Web と CLI で本番判定が食い違うことがあります。定数・getenv・SAPI のどこから判定したかも表示すると、読み違いを防げます。- 副作用のある修正は、挙動の変化を明記しましょう。 今まで捨てられていた Fatal が届くようになると、通知や起票が増えます。PR にその旨を書いておくと、運用側が驚きません。
- 1 回の失敗で、直接送信とフック経由の 2 件が送られることがあります。 重複は別途解消が必要です。
- 停止期間中に本当にエラーが起きていなかったかは、別の情報源で確認しましょう。 Web サーバや CDN のログとの突き合わせが有効です。
まとめ
「記録が止まった」ときは、送信の故障を疑う前に、送信条件の一覧と受け手の集計を見るのが近道でした。
一方で、error_get_last() が後続の Notice で上書きされる欠陥は、shutdown アクションの最優先実行と wp_php_error_args で早めに控えることで防げます。
受け手のスキーマはテストに写し、失敗ログには型だけを出し、点検用 CLI は出す情報を絞る。
この 3 点を押さえておくと、次に記録が止まったときの点検がかなり楽になります。

