简介
本文件为 DouPHP 构建“应用日志分析系统”的完整设计文档,聚焦以下目标:
- 错误日志收集机制:异常捕获、错误堆栈记录、错误分类统计。
- 性能日志分析方法:请求处理时间、数据库查询耗时、外部服务调用延迟。
- 用户行为追踪方案:用户操作路径、页面访问统计、用户会话跟踪。
- 日志聚合与存储策略:基于 ELK Stack、Splunk 等方案的采集、索引与归档。
- 日志分析与可视化:使用 Kibana 进行查询、报表与告警。
- 日志告警机制:基于日志模式匹配的智能告警规则。
项目结构
DouPHP 在基础设施层提供了统一的日志能力,并在业务模块中多处接入;同时存在第三方 SDK 的独立日志实现。整体结构如下:
- 统一日志门面:core/infra/log/Log.php(主站)、_/.api/lib/Log.php(API 子站)。
- 异常处理:Whoops PrettyPageHandler 提供堆栈展示与文本转储。
- 业务日志写入:售后状态机、云安装流程、登录失败/成功审计等。
- 中间件与安全头:安全响应头中间件位于前端与基础层。
- 第三方 SDK 日志:微信支付 SDK 自带日志类。
graph TB
A["应用入口<br/>front/api/admin"] --> B["中间件管道<br/>安全头/鉴权/限流"]
B --> C["控制器/服务<br/>业务逻辑"]
C --> D["统一日志门面<br/>Dou\\Core\\Infra\\Log\\Log"]
C --> E["第三方SDK日志<br/>wxpay log"]
C --> F["数据库/缓存/外部服务"]
D --> G["日志文件<br/>storage/log/log_YYYY-MM-DD.log"]
E --> H["SDK日志文件"]
核心组件
- 统一日志门面(主站)
- 分级日志:emergency/alert/critical/error/warning/notice/info/debug。
- 自动上下文:request_id、scene、ip、route、module、action、user_id、admin_id、work_id。
- 敏感信息脱敏:对 password/token/secret 等键名及 URL 查询串中的敏感参数进行掩码。
- 采样与限流:支持按采样率丢弃与每分钟同 key 最大条数限制。
- 输出格式:[时间] LEVEL: 消息 + JSON 上下文,写入 storage/log/log_YYYY-MM-DD.log。
- API 子站日志
- 与主站同形 API,独立部署于 _local_api,默认写入 API_ROOT/data/log/。
- 异常处理
- Whoops PrettyPageHandler:生成友好错误页并附带纯文本堆栈作为注释,便于抓取堆栈。
- 业务日志写入点
- 售后状态机:写 aftersale_log 表,并通过 Log::error 记录异常。
- 云安装流程:将步骤日志推入 session 并返回给前端。
- 登录审计:登录成功/失败通过 audit()->writeUserLog 写入用户日志表。
- 第三方 SDK 日志
- 微信支付 SDK 提供 INFO/WARN/ERROR 级别日志,ERROR 包含堆栈片段。
架构总览
下图展示了从请求进入、中间件处理、业务逻辑到日志落盘与异常处理的完整链路,以及第三方 SDK 日志的并行写入。
sequenceDiagram
participant Client as "客户端"
participant MW as "中间件<br/>安全头/鉴权"
participant Ctrl as "控制器/服务"
participant Log as "统一日志门面"
participant DB as "数据库"
participant SDK as "第三方SDK日志"
participant Whoops as "Whoops处理器"
Client->>MW : HTTP 请求
MW->>Ctrl : 路由分发
Ctrl->>DB : 业务数据读写
Ctrl->>Log : error/warning/info...
Ctrl->>SDK : 调用外部服务(可选)
SDK-->>Ctrl : 结果/错误
Ctrl-->>Client : 响应
Note over Ctrl,Log : 自动上下文注入(request_id, route, ip...)
alt 发生未捕获异常
Ctrl-->>Whoops : 抛出异常
Whoops-->>Client : 错误页(含纯文本堆栈)
Whoops-->>Log : 可记录关键错误上下文
end
详细组件分析
错误日志收集机制
- 异常捕获与堆栈记录
- Whoops PrettyPageHandler 在异常时渲染错误页,并将纯文本堆栈以 HTML 注释形式嵌入,便于抓取与分析。
- 可通过配置 application paths 过滤无关框架帧,突出应用代码堆栈。
- 结构化错误日志
- 业务侧通过 Log::error 记录错误,自动附加 request_id、route、module、action、ip、user_id 等上下文。
- 敏感字段自动脱敏,URL 查询串中的敏感参数值被替换为占位符。
- 错误分类统计
- 利用 channel/module/action 等上下文字段,结合日志级别进行分类统计。
- 可在 Kibana 中按 level、channel、module、action 维度聚合错误数量与趋势。
flowchart TD
Start(["异常发生"]) --> Capture["Whoops捕获异常"]
Capture --> Render["渲染错误页<br/>嵌入纯文本堆栈"]
Render --> Context["自动上下文注入<br/>request_id/route/ip/user_id"]
Context --> Redact["敏感信息脱敏"]
Redact --> Write["写入日志文件<br/>log_YYYY-MM-DD.log"]
Write --> End(["完成"])
性能日志分析方法
- 请求处理时间
- 在中间件或控制器中记录请求开始与结束时间,计算差值并写入日志上下文(如 duration_ms)。
- 建议结合 route/module/action 维度统计各接口 P95/P99 耗时。
- 数据库查询耗时
- 在 ORM/DB 层封装执行前后计时,记录 SQL 与耗时,注意对大 SQL 做截断与敏感字段脱敏。
- 外部服务调用延迟
- 在调用第三方 SDK 或服务前记录 start_time,返回后记录 elapsed_ms,并记录 channel/module/action。
- 对于异步任务(如 AI 任务轮询),记录超时阈值与最终状态,便于定位慢调用。
sequenceDiagram
participant MW as "中间件"
participant Svc as "服务/控制器"
participant DB as "数据库"
participant Ext as "外部服务"
participant Log as "日志门面"
MW->>Svc : 进入请求
Svc->>Log : info("request_start", {route,module,action})
Svc->>DB : 执行查询
DB-->>Svc : 结果
Svc->>Ext : 调用外部服务
Ext-->>Svc : 响应
Svc->>Log : info("request_end", {duration_ms,...})
用户行为追踪方案
- 用户操作路径
- 通过日志上下文中的 route/module/action 重建用户访问路径;结合 user_id 串联同一用户的多次访问。
- 页面访问统计
- 统计各 route/module/action 的访问量、UV、PV,按小时/天聚合。
- 用户会话跟踪
- 使用 request_id 关联单次请求内的所有日志;结合 session 中的 user_id/admin_id/work_id 识别身份。
- 登录成功/失败通过审计日志表记录,可用于安全分析与风控。
flowchart TD
A["用户访问"] --> B["中间件/路由解析"]
B --> C{"是否已登录"}
C --> |是| D["记录user_id, admin_id, work_id"]
C --> |否| E["匿名访问"]
D --> F["记录route/module/action"]
E --> F
F --> G["写入日志(带request_id)"]
G --> H["Kibana聚合分析<br/>路径/统计/会话"]
日志聚合与存储策略
- 本地存储
- 主站:storage/log/log_YYYY-MM-DD.log(按日滚动)。
- API 子站:API_ROOT/data/log/(独立部署)。
- 第三方 SDK:各自目录下的日志文件。
- 集中化采集
- 使用 Filebeat/Fluent Bit 采集多端日志文件,转发至 Elasticsearch。
- 对日志字段进行解析(timestamp、level、message、context JSON),建立索引模板。
- 归档与保留
- 设置 ILM(Index Lifecycle Management)策略,热数据保留 7-30 天,温冷数据迁移至低成本存储。
- 定期清理本地旧日志文件(Log::clean 可辅助管理)。
日志分析与可视化(Kibana)
- 常用查询
- 错误率:filter by level=error 并按 module/action 聚合。
- 慢请求:filter by duration_ms > 阈值,按 route 排序。
- 登录失败:filter by action=login_fail 或 details=LOGIN_FAIL。
- 报表与看板
- 创建错误趋势图、接口耗时分布、用户登录成功率看板。
- 使用分面(Facets)分析不同渠道(channel)的错误占比。
- 告警规则
- 基于日志模式匹配设置告警:如 5xx 比例突增、特定错误频发、登录失败率超过阈值。
- 告警通道:邮件、企业微信、钉钉等。
日志告警机制
- 模式匹配规则
- 错误级别:error/critical/alert/emergency。
- 业务关键字:如 “http_fail”、“LOGIN_FAIL”、“captcha_expired”。
- 性能指标:duration_ms、query_time_ms、external_call_elapsed_ms。
- 智能告警
- 动态阈值:基于历史基线检测异常波动。
- 去重与抑制:避免告警风暴,合并同类事件。
- 通知与处置
- 多渠道通知,附带上下文(request_id、route、module、action、user_id)。
- 与工单系统集成,自动创建问题单。
依赖关系分析
- 组件耦合
- 业务模块依赖统一日志门面,降低耦合度;第三方 SDK 日志独立,互不影响。
- 中间件与安全头中间件位于 HTTP 边界,不直接依赖日志,但可与日志联动(如记录请求头)。
- 外部依赖
- Elasticsearch/Kibana/Filebeat 用于集中化存储与可视化。
- 告警系统(如 Alertmanager、企业微信机器人)用于通知。
- 潜在循环依赖
- 日志门面不反向依赖业务模块,避免循环依赖。
graph LR
Biz["业务模块"] --> Log["统一日志门面"]
Biz --> SDKLog["第三方SDK日志"]
Log --> FS["文件系统(storage/log)"]
SDKLog --> FS2["SDK日志目录"]
FS --> EB["Filebeat/Fluent Bit"]
FS2 --> EB
EB --> ES["Elasticsearch"]
ES --> Kibana["Kibana"]
性能考虑
- 采样与限流
- 在高并发场景下,启用采样率与每分钟同 key 最大条数限制,避免日志风暴。
- 敏感信息脱敏
- 对密码、token、签名等字段进行脱敏,减少日志体积与安全风险。
- 异步与批处理
- 可将日志写入改为异步队列(如 RabbitMQ/Kafka),提升主流程性能。
- 存储优化
- 使用压缩与分片策略,合理设置索引生命周期,降低成本。
故障排查指南
- 常见问题
- 日志未写入:检查 storage/log 目录权限与磁盘空间。
- 敏感信息泄露:确认敏感键名单与 URL 查询串脱敏逻辑生效。
- 错误分类不准确:检查 channel/module/action 上下文是否正确注入。
- 快速定位
- 使用 request_id 关联一次请求的所有日志。
- 在 Kibana 中按 level、module、action 过滤,快速定位问题模块。
- 恢复措施
- 临时提高采样率或关闭限流以获取更多上下文。
- 对频繁错误进行根因分析并修复。
结论
DouPHP 已具备完善的日志基础设施与业务接入点,结合 ELK Stack 可实现端到端的日志采集、存储、分析与可视化。通过结构化日志、敏感信息脱敏、采样限流等手段,既能保障性能与安全,又能支撑高效的故障排查与运维监控。建议在现有基础上进一步完善性能埋点与告警规则,形成闭环的日志分析体系。
附录
- 推荐实践
- 统一日志格式:时间戳、级别、消息、JSON 上下文。
- 标准化上下文:request_id、route、module、action、user_id、ip。
- 告警规则库:错误率、慢请求、登录失败、外部服务超时。
- 参考文件
- 统一日志门面:core/infra/log/Log.php
- API 子站日志:_/.api/lib/Log.php
- 异常处理:core/library/whoops/src/Whoops/Handler/PrettyPageHandler.php
- 业务日志写入:core/service/aftersale/AftersaleStatusTransition.php、admin/controller/cloud/CloudController.php、front/service/user/LoginService.php
- 第三方 SDK 日志:plugin/wxpay/sdk/class/log.php