访问日志

OxPHP 为每个 HTTP 请求输出结构化的 JSON 访问日志,写入 stdout。日志记录是异步的,因此绝不会阻塞请求处理。

工作原理

设置 ACCESS_LOG 后,OxPHP 会在每个请求完成后向 stdout 写入一行 JSON。这些写入操作会在一个后台写入线程中缓冲,因此日志记录绝不会阻塞请求流水线。

模式决定了记录哪些内容。ACCESS_LOG=all 记录每个请求;ACCESS_LOG=error 只记录状态码为 400 或更高的响应。

每一行日志都带有一个 request_id 字段,用于将访问日志条目与你的应用日志关联起来。当启用 W3C Trace Context 传播时,日志条目还会包含 trace_idspan_id 字段。

配置

变量 默认值 说明
ACCESS_LOG (未设置) 访问日志模式。all 记录每个请求;error 只记录 4xx 和 5xx 响应。留空或不设置则禁用
Note

唯一接受的值是 allerror。设置无法识别的值会记录一条警告并禁用访问日志。

日志格式

每条访问日志条目都是写入 stdout 的一行 JSON:

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_idspan_id 会与标准字段一同包含在内:

json
{ "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 方法(GETPOST 等)
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 span ID(仅当 TRACE_CONTEXT=true 时存在)

细粒度过滤

OxPHP 使用内部的 access_log 日志目标来记录访问日志条目。使用 RUST_LOG 变量可以将访问日志与其他日志输出独立开来进行过滤:

bash
# 抑制常规 info 消息,保留访问日志 RUST_LOG=warn,access_log=info
Note

access_log 目标用于 RUST_LOG 过滤,但不会包含在 JSON 输出中。要在下游系统中识别访问日志条目,请使用 "message": "request completed" 字段以及其特有的字段集合(methodpathstatusduration_us)。

故障排查

没有出现任何访问日志条目

ACCESS_LOG 未设置或为空时,访问日志处于禁用状态。

修复方法: 将变量设置为 allerror

bash
ACCESS_LOG=all
访问日志显示为 `error` 模式,但缺少成功的请求

ACCESS_LOG=error 只记录状态码为 400 或更高的响应。这是设计使然——请检查该值,如果你需要记录所有请求,请切换为 all

检查方法: 确认当前生效的设置:

bash
curl -s http://localhost:9090/config | jq '.access_log'
日志条目出现,但没有 `trace_id` 和 `span_id`

只有在启用 W3C Trace Context 传播时才会存在追踪上下文字段。

修复方法: 通过以下方式启用它:

bash
TRACE_CONTEXT=true

并确保你的上游客户端或负载均衡器在请求上发送 traceparent 头。

Docker 示例

compose.yaml
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 —— 当作为 systemd 服务运行并通过 journald 记录 stdout 时被捕获

无需 sidecar 或基于文件的日志转发。

另请参阅

  • 请求 ID —— 每条日志条目都包含一个用于追踪的 request_id
  • 配置参考 —— 完整的环境变量参考