需启用并配置JSON格式日志:一、File通道设json=true;二、自定义Console通道输出JSON至stdout;三、通过全局processor注入上下文字段;四、调整时间字段名与格式适配日志系统;五、过滤敏感字段保障安全。
如果您希望ThinkPHP的日志以JSON格式记录,便于日志系统(如ELK、Loki)统一采集与结构化解析,则需启用并正确配置JSON格式日志功能。以下是实现该目标的具体操作步骤:
一、启用JSON格式日志(File通道)
File类型日志支持通过
js
on参数开启结构化输出,启用后每条日志将被序列化为标准JSON对象,包含时间、级别、消息、上下文等字段,提升可读性与机器解析能力。
1、打开应用配置目录下的
文件。
2、在
配置项中,将
参数设为
。
立即学习
“
PHP免费学习笔记(深入)
”;
3、确保
为
,且
指向具有写入权限的有效目录。
4、保存配置文件,重启应用使配置生效。
5、执行一次日志写入操作(例如触发一个警告或错误),检查日志文件内容是否为合法JSON格式字符串。
二、配置自定义JSON日志通道(Console通道)
当部署于容器环境(如Kubernetes)时,日志需输出至标准输出(stdout)以便日志采集器(如Promtail)捕获。此时应创建独立的Console通道,并强制其以JSON格式输出,避免非结构化文本干扰解析。
1、在
的
数组中新增名为
的通道配置。
2、设置
为自定义驱动类路径,例如
。
3、在
中定义该类,继承
或实现
,重写
方法,在写入前调用
。
4、在
方法中使用
直接输出到控制台。
5、将
值修改为
,或在特定场景下显式调用
。
三、配置全局JSON日志处理器
通过processor机制,可在日志写入前对原始记录进行统一结构化增强,例如注入请求ID、用户信息、模块名等上下文字段,确保所有通道(包括File、Socket等)均输出一致的JSON结构。
1、在
根级配置中添加
项,值为闭包函数。
2、闭包接收
参数,向其
子数组中追加
(从
获取)、
(从Session或Token解析)等字段。
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
3、闭包返回处理后的
,该记录后续将被JSON编码写入。
4、确认各通道配置中未设置独立
,以免覆盖全局配置。
5、验证日志条目中是否包含新增的上下文字段,且整体仍为有效JSON对象。
四、配置JSON日志时间格式与字段映射
默认JSON日志的时间字段使用ISO 8601格式,但部分日志系统要求时间字段名为
或采用毫秒级Unix时间戳。可通过自定义格式化逻辑调整字段名与值类型,适配下游系统规范。
1、在
的
中,设置
为
或空字符串,禁用字符串模板格式化。
2、在自定义日志驱动(如
)的
方法内,手动构造JSON数组,将
转换为
作为
字段。
3、将原
字段重命名为
,原
重命名为
,保持与OpenTelemetry日志规范兼容。
4、使用
校验最终JSON字符串合法性,失败时回退写入原始数组并记录错误。
5、检查生成的日志行是否符合目标日志平台要求的字段命名与数据类型。
五、配置JSON日志敏感字段过滤
JSON日志若直接记录原始请求参数或响应数据,可能泄露密码、令牌、手机号等敏感信息。必须在序列化前主动剔除或脱敏关键字段,防止安全合规风险。
1、在全局
闭包中,递归遍历
和
,定位键名含
、
、
、
的字段。
2、对匹配字段值执行
或替换为
。
3、对
(常见于API返回日志)做深度扫描,若其为数组且含敏感键,则整层替换为
。
4、在
驱动的
方法开头,调用
对整个
执行脱敏逻辑。
5、验证日志文件中敏感字段是否已不可见,且其余字段结构完整、无JSON语法错误。
config/log.phpchannels['file']'json'true'type''File''path'config/log.php'channels''console_json''type''app\service\JsonConsole'app/service/JsonConsole.php hinklogdriverFile hinklogDriverInterfacewritejson_encode($record, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)writefile_put_contents('php://stdout', $json_line . "
", FILE_APPEND)'default''console_json'Log::channel('console_json')->info(...)config/log.php'processor'$record'context''request_id'thinkRequest'user_id'$record'processor'@timestampconfig/log.phpchannels['file']'format'nullJsonConsolewrite$record['time']strtotime($record['time']) * 1000@timestamp'level''severity''msg''message'json_last_error()'processor'$record['context']$record['extra']'password''token''auth''id_card'str_repeat('*', strlen($value))'[FILTERED]'$record['context']['data']['filtered' => true]JsonConsolewritearray_walk_recursive$record