log::record()在自定义函数中不生效,是因为日志驱动未初始化,常见于common.php等框架启动前调用;应确保在请求生命周期内使用,并显式指定channel以实现目录隔离。

TP5里怎么在自定义函数里写日志
可以直接用 think\Log::record() 或 trace(),但要注意执行环境是否已初始化日志驱动。TP5 的日志系统依赖应用实例和配置,纯函数调用时若未进入框架生命周期(比如在 common.php 里直接写函数),Log::record() 可能静默失败或报错。
为什么 Log::record() 在某些自定义函数里不生效
常见原因是:函数被提前加载(如放在 application/common.php),此时 think\App 尚未启动,日志配置没加载,Log 类虽存在但底层驱动(如 File)未实例化。也会遇到 Driver not found 或写入空文件的情况。
- 确保函数调用发生在请求生命周期内(如控制器、模型、中间件中),而非框架初始化前
- 避免在
common.php或函数定义处直接调用Log::record();可改用延迟写入,例如封装成闭包或等App::initialized()后再触发 - 检查
config/log.php中'default' => 'file'和对应驱动配置是否存在且可写
trace() 和 Log::record() 用哪个更合适
trace() 是调试辅助函数,会把日志写进 trace 页面(仅开发环境生效),不落盘;Log::record() 才是真正写入日志文件的接口。自定义函数若需留痕排查问题,必须用后者。
-
trace('msg', 'title')→ 仅显示在页面右下角 trace 面板,生产环境默认关闭 -
think\Log::record('msg', 'error', 'admin')→ 写入runtime/log/admin/202406/xxx.log,支持 level 和 channel 分类 - 注意第三个参数
channel:不传则走默认 channel(通常是''),建议显式指定便于归类,比如'pay'、'sms'
一个安全可用的自定义日志函数写法
不要裸写 Log::record(),加一层判断和兜底:
if (!function_exists('log_custom')) {
function log_custom($msg, $level = 'info', $channel = 'custom') {
// 确保 Log 类可用且驱动就绪
if (class_exists('think\Log') && method_exists('think\Log', 'init')) {
try {
\think\Log::record($msg, $level, $channel);
} catch (\Exception $e) {
// 初始化失败时,退回到 error_log(极简兜底)
error_log(date('Y-m-d H:i:s') . " [LOG FALLBACK] {$msg}\n", 3, RUNTIME_PATH . 'log/fallback.log');
}
}
}
}
把这个函数放进 application/common.php 即可全局使用,但务必确认它只在框架启动后被调用——比如在控制器方法里调用 log_custom('order created') 是安全的,而在 common.php 文件顶层直接执行则不行。
真正容易被忽略的是 channel 的目录隔离效果:不同 channel 会自动分目录写入,但前提是 log.php 里没禁用 'single' => false;否则所有 channel 都挤进同一个文件,失去分类意义。











