Service层可直接调用Log::info(),因ThinkPHP的Facade是静态代理,底层绑定容器中已注册的\think\Log实例,且请求生命周期启动后全局可用;推荐用Log::info()而非Log::record(),注意配置、路径、并发及异常兜底。

Service 层可以直接用 think\facade\Log,和 Controller 一样,无需额外初始化
为什么 Service 里能直接调用 Log::info()
ThinkPHP 的 Facade 是静态代理,think\facade\Log 底层绑定的是容器中已注册的 \think\Log 实例。只要请求生命周期已启动(即 App 已初始化),Service 层无论在哪被调用(Controller、Command、Middleware 或队列任务),都能安全使用。
- 不用
use think\Log(这是旧版 TP5 的写法,TP6+ 推荐 facade) - 不需要传参或依赖注入,
Log是全局可用的 Facade - 日志写入仍遵循配置:比如
config/log.php中'level' => ['info']才会真正落盘
Log::record() 和 Log::info() 在 Service 里怎么选
Log::record() 是底层入队方法,不触发格式化、不走 channel 配置;Log::info() 是语义化封装,自动带时间、级别、上下文,推荐优先用后者。
-
Log::info('user_id:'.$userId.' updated profile')—— 标准写法,可读性强 -
Log::record('raw msg', 'info')—— 仅在需要绕过默认格式(如自定义 JSON 结构)时用 - 避免在循环里高频调用
Log::info(),可能拖慢性能;批量操作建议聚合后单次记录
Service 调用 Log 后没生成文件?重点查这三处
Service 层本身不会导致日志失效,问题一定出在环境配置或调用时机上。
立即学习“PHP免费学习笔记(深入)”;
-
APP_DEBUG = false且config/log.php中'level'为空数组 → 日志被框架主动跳过 - Service 被用在命令行(
php think command)或队列中,但log.channels.file.path是相对路径(如''),实际写入到了 CLI 当前工作目录而非runtime/log - 调用了
Log::close()或配置了'close' => true,整个通道被禁用
想在 Service 里写结构化操作日志?别直接 Log::info($array)
ThinkPHP 默认 File 驱动对数组做 var_export() 处理,结果是难解析的字符串。要 JSON 行式日志,得自己控制输出。
- 错误示范:
Log::info(['user_id' => 123, 'action' => 'pay'])→ 文件里出现多行乱码文本 - 正确做法:
file_put_contents(runtime_path('log/operation/'.date('Y-m-d').'.log'), json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)."\n", FILE_APPEND | LOCK_EX) - 注意:手动写文件必须加
LOCK_EX,否则高并发下会丢行;敏感字段(如password)必须在$data构造前就 unset
真正容易被忽略的是:Service 层日志往往混在业务逻辑深处,一旦某次异常提前 return 或 throw,后续的 Log::info() 就永远不会执行。需要日志兜底的地方,得确保它在 try/catch 的 finally 块里,或者改用 Log::save() 强制刷盘——但别滥用,它会阻塞主线程。



















