アクセスログ
OxPHP は、すべての HTTP リクエストに対して構造化された JSON アクセスログを出力し、stdout に書き込みます。ログ出力は非同期で行われるため、リクエスト処理をブロックすることはありません。
仕組み
ACCESS_LOG が設定されている場合、OxPHP は完了した各リクエストの後に 1 行の JSON を stdout に書き込みます。これらの書き込みはバックグラウンドのライタースレッドでバッファリングされるため、ログ出力がリクエストパイプラインをブロックすることはありません。
モードによって記録される内容が制御されます。ACCESS_LOG=all はすべてのリクエストをログに記録し、ACCESS_LOG=error はステータス 400 以上のレスポンスのみをログに記録します。
すべてのログ行には request_id フィールドが含まれており、アクセスログのエントリとアプリケーションログを関連付けます。W3C Trace Context の伝播が有効な場合、エントリには trace_id および span_id フィールドも含まれます。
設定
| 変数 | デフォルト | 説明 |
|---|---|---|
ACCESS_LOG |
(未設定) | アクセスログのモード。all はすべてのリクエストを、error は 4xx および 5xx のレスポンスのみをログに記録します。無効にするには未設定または空のままにします |
有効な値は all と error のみです。認識されない値を設定すると警告がログに記録され、アクセスログが無効になります。
ログ形式
すべてのアクセスログエントリは、stdout に書き込まれる 1 行の JSON です。
{
"timestamp": "2026-02-11T12:34:56.789012Z",
"level": "INFO",
"fields": {
"request_id": "67890abc12341a2b0042",
"method": "GET",
"path": "/api/users",
"status": 200,
"duration_us": 1234,
"remote_ip": "10.0.0.1",
"message": "request completed"
}
}W3C Trace Context が有効な場合、標準フィールドに加えて trace_id と span_id が含まれます。
{
"timestamp": "2026-02-11T12:34:56.789012Z",
"level": "INFO",
"fields": {
"request_id": "67890abc12341a2b0042",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"method": "POST",
"path": "/api/orders",
"status": 201,
"duration_us": 8421,
"remote_ip": "10.0.0.1",
"message": "request completed"
}
}フィールド
| フィールド | 型 | 説明 |
|---|---|---|
request_id |
string | 一意のリクエスト識別子。リクエストID を参照してください |
method |
string | HTTP メソッド(GET、POST など) |
path |
string | リクエスト URI のパス |
status |
number | HTTP レスポンスのステータスコード |
duration_us |
number | リクエスト処理の合計時間(マイクロ秒単位) |
remote_ip |
string | クライアントの IP アドレス(ポートなし)。TRUSTED_PROXIES が設定されている場合、プロキシの IP ではなく、転送ヘッダーから抽出された実際のクライアント IP を表示します |
trace_id |
string | W3C トレース ID(TRACE_CONTEXT=true の場合のみ存在します) |
span_id |
string | W3C スパン ID(TRACE_CONTEXT=true の場合のみ存在します) |
きめ細かなフィルタリング
OxPHP はアクセスログのエントリに内部の access_log ロギングターゲットを使用します。RUST_LOG 変数を使うと、アクセスログを他のログ出力とは独立してフィルタリングできます。
# Suppress general info messages, keep access logs
RUST_LOG=warn,access_log=infoaccess_log ターゲットは RUST_LOG のフィルタリングに使用されますが、JSON 出力には含まれません。下流のシステムでアクセスログのエントリを識別するには、"message": "request completed" フィールドと特徴的なフィールドの組み合わせ(method、path、status、duration_us)を利用してください。
トラブルシューティング
アクセスログのエントリが表示されない
ACCESS_LOG が未設定または空の場合、アクセスログは無効になります。
対処法: 変数を all または error に設定します。
ACCESS_LOG=allアクセスログが `error` モードだが成功したリクエストが記録されない
ACCESS_LOG=error はステータス 400 以上のレスポンスのみをログに記録します。これは仕様です。値を確認し、すべてのリクエストをログに記録する必要がある場合は all に切り替えてください。
確認: 現在有効な設定を確認します。
curl -s http://localhost:9090/config | jq '.access_log'ログエントリに `trace_id` と `span_id` が含まれていない
トレースコンテキストのフィールドは、W3C Trace Context の伝播が有効な場合にのみ存在します。
対処法: 以下で有効にします。
TRACE_CONTEXT=trueさらに、上流のクライアントまたはロードバランサーがリクエストに traceparent ヘッダーを送信していることを確認してください。
Docker の例
services:
app:
image: ghcr.io/oxphp/oxphp:0.10.0
ports:
- "80:80"
- "9090:9090"
volumes:
- ./src:/var/www/html:ro
environment:
ACCESS_LOG: "all"
ENTRY_FILE: "index.php"
INTERNAL_ADDR: "0.0.0.0:9090"ベストプラクティス
- 本番環境では
ACCESS_LOG=errorを使用することで、失敗したすべてのリクエストを捕捉しつつログの量を削減できます。成功したリクエストはログに記録されませんが、ステータス 400 以上のエラーは常に捕捉されます。 oxphp_request_id()を使ってアプリケーションログにリクエストID を含めることで、PHP レベルのログエントリとアクセスログのエントリを関連付けられます。- Elasticsearch、Loki、Datadog などの構造化ログアグリゲーターを使用すると、JSON ログ行を効率的にクエリしフィルタリングできます。
連携
ログは stdout 上の JSON 行であるため、コンテナのログドライバーや集約ツールと直接連携します。
- Docker — コンテナのログドライバー(json-file、fluentd など)を介して自動的に収集されます
- Kubernetes — ノードのログエージェント(Fluentd、Fluent Bit、Filebeat など)によって取得されます
- systemd — journald 経由の stdout ロギングを備えた systemd サービスとして実行される場合に捕捉されます
サイドカーやファイルベースのログ転送は不要です。