Yii 框架问题排查:无法打印日志,Yii::log() 方法无效

在开发过程中遇到非常奇怪的问题,Yii::log() 方法无效,即使发生异常时也没有任何日志输出。Yii 框架肯定不会有问题,根据经验一般问题都出现在目录权限或者框架配置上。

先说结论,这次问题在于配置文件中 'preload' => array('log'), 一行被他人错误的注释掉了,解开注释后日志打印恢复正常。

还有一种可能,当使用 tail -f application.log 查看日志时,若 application.log 文件刚好写满,也不会有日志滚动!退出重新执行 tail 以跟踪新的日志文件。


下面记录一下排查方法,顺便了解一下 Yii 框架日志记录原理:

首先说明大致原理:Yii 框架中日志在内存中有 “缓冲区” 的存在,就是说,并非每次 Yii::log() 执行都会向文件中写入。当缓冲区写入次数超过阈值、或者当一次请求完成时,从缓冲区中读取数据写入日志文件。

日志写入逻辑如下: Yii::log() => YiiBase::log() => (根据配置选择是否记录 Stack Trace)=> CLogger::log() => 写入缓冲区(CLogger::$_logs 数组)、判断写入次数阈值 => 不满足刷新条件,什么都不做;满足刷新条件,触发 onFlush 事件

onFlush 事件触发逻辑:CLogRouter::init() 注册 onFlush 处理器为 CLogRouter::collectLogs() => 获取到配置文件 log 节点下所有的 routes,遍历调用 routes 对象的 collectLogs() 方法(如 routes 下配置了 CFileLogRoute,则调用 CFileLogRoute::collectLogs(),注意此方法是由父类继承而来 )=> CLogger::getLogs 从缓冲区读取日志 => ……

onEndRequest 事件触发逻辑:CLogRouter::init() 注册 onEndRequest 处理器为 CLogRouter::processLogs() => 同样调用所有 CLogRouter::$_routes 的 collectLogs 方法。

开始我怀疑,代码中自定义的 onEndRequest 事件处理器拦截了事件,导致此处 onEndRequest 处理器无法执行,但测试后发现 CLogRouter::init() 根本没有调用!CLogRouter::init() 实现了 IApplicationComponent::init() 接口,在此处的注释中写道:

This method is invoked after the application completes configuration.

CApplication::__construct 会依次执行 preinit、initSystemHandlers、registerCoreComponents、configure、attachBehaviors、preloadComponents 等方法,所以发现 log 组件应该是在 preloadComponents 方法中加载的,检查配置文件发现 'preload' => array('log'), 被注释掉了,那就是这个原因,解开注释后 CLogRouter::init() 正常加载、日志打印正常。

你可能感兴趣的:(服务端)