本文目录导读:

- 基础信息(黄金三要素)
- 定位上下文(Where & Who)
- 技术环境信息(How)
- 业务与请求上下文(核心数据)
- 异常与堆栈(Why)
- 结构化上下文(Context)
- 强烈推荐的日志结构示例(JSON 格式)
- 最后:绝对不能记录的信息(安全红线)
- 实战建议
在 PHP 项目中,完善的日志记录是调试问题、监控系统健康、审计安全事件以及优化性能的基础,一个规范的日志条目应该遵循“5W + 1H”原则(Who, When, Where, What, Why, How),并辅以必要的上下文。
以下是 PHP 项目日志记录应该包含的核心信息清单,按重要性分层:
基础信息(黄金三要素)
这是定位问题的首要线索,必须包含。
- 时间戳(When):精确到毫秒(
Y-m-d H:i:s.u),时区统一为 UTC 或服务器本地时区,并明确标注,在分布式系统中,建议记录 ISO 8601 格式。 - 日志级别(Severity):
DEBUG(调试)、INFO(信息)、NOTICE(提示)、WARNING(警告)、ERROR(错误)、CRITICAL(严重)、ALERT(警报)、EMERGENCY(紧急),这是过滤海量日志的第一道门槛。 - 消息(Message):人类可读的、具体的描述。避免使用“Error occurred”这种废话,应写“Failed to connect to Redis at 127.0.0.1:6379 (Connection refused)”。
定位上下文(Where & Who)
帮助快速还原问题发生的现场。
- 文件路径与行号(Where):
/var/www/html/app/Http/Controllers/UserController.php:45,虽然堆栈跟踪里有,但在单条日志中直接记录能极大缩短检索时间。 - 请求 ID / 追踪 ID(Trace ID):PHP 项目最常用的选项,利用
Monolog的Processor自动生成 UUID 或从 HTTP Header 中提取,用于贯穿整个请求链路(Nginx -> PHP -> MySQL)。 - 用户身份(Who):如果是 Web 应用,记录登录用户的
user_id或用户名;如果是 CLI,记录执行脚本的操作系统用户。 - 来源 IP 地址:客户端 IP(注意反代情况下需读取
X-Forwarded-For),用于安全审计。
技术环境信息(How)
这部分通常由日志库的 Processor 自动附加,无需手动写入。
- PHP 版本:
PHP 8.3.1. - 运行模式:
FPM、CLI、Worker。 - 服务器环境:
production、staging、development。 - 内存占用峰值:
memory_get_peak_usage(true),用于排查内存泄漏。 - 执行耗时:该请求或脚本的总执行时间(毫秒)。
业务与请求上下文(核心数据)
这是排查业务逻辑错误的重中之重。
- 请求参数:
$_GET、$_POST、$_FILES(注意:必须过滤掉password、token、credit_card等敏感字段)。 - 请求路由:
GET /api/users/123或php artisan migrate。 - 请求头:关键的
User-Agent、Referer、Accept-Language(非必需,按需记录)。 - Session ID(脱敏后)。
异常与堆栈(Why)
当发生异常时,绝不只记录 $e->getMessage(),必须包含完整堆栈。
- 异常类名:
RuntimeException、PDOException等。 - 错误码:HTTP 状态码(如 500, 422)或 PHP 错误码(如 E_WARNING)。
- 异常消息:与第 1 点的 Message 区分,这里保存原始异常文本。
- 完整堆栈跟踪(Stack Trace):记录
$e->getTraceAsString(),但建议按行展开并缩进,以便阅读。 - 前因后果:链式异常(
getPrevious())也应递归记录。
结构化上下文(Context)
现代日志推荐使用结构化日志(如 JSON 格式),便于机器读取和 ELK 日志分析。
- 业务对象 ID:如
order_id: 12345,product_sku: "ABC-123"。 - 外部服务响应:调用第三方 API 失败时,记录对方的 HTTP 状态码和响应体摘要。
- 数据库查询:记录导致失败的 SQL 语句(不包含绑定参数值中的敏感信息)。
强烈推荐的日志结构示例(JSON 格式)
使用 PHP 的 Monolog 库时,一个完美的结构化日志长这样:
{
"datetime": "2024-05-20T14:33:26.083144+08:00",
"level": "ERROR",
"channel": "app",
"message": "创建订单失败:库存不足",
"context": {
"user_id": "U12345",
"order_id": "",
"product_sku": "PHONE-X",
"request_id": "a1b2c3d4-5678-9abc-def0-123456789abc",
"route": "POST /api/v1/orders",
"input": {
"product_sku": "PHONE-X",
"quantity": 10
},
"exception": {
"class": "App\\Exceptions\\InsufficientStockException",
"code": 422,
"message": "Only 5 items available in stock",
"file": "/var/www/app/Services/OrderService.php",
"line": 88,
"trace_string": "#0 /var/www/app/Http/Controllers/OrderController.php(77): ..."
}
},
"extra": {
"server_ip": "172.17.0.2",
"php_version": "8.2.12",
"memory_peak_usage": 10485760,
"execution_time_ms": 452.3
}
}
绝对不能记录的信息(安全红线)
- 明文密码、支付卡号、CVV。
- 会话令牌(Session Token) 的完整值。
- API 密钥和数据库密码的真实值。
- 完整的 GDPR/HIPAA 相关个人隐私数据(除非脱敏并加密)。
实战建议
- 使用库:优先用
Monolog或Laravel自带的 Log 门面,避免手写file_put_contents。 - 环境区分:生产环境禁止记录
DEBUG级别日志,但完整记录ERROR及以上级别。 - 多通道:错误日志写入
error.log,业务日志写入business.log,安全审计日志独立存放audit.log。 - 异步化:对于高并发项目,使用
Redis队列异步写入日志,避免日志 I/O 阻塞业务线程。