▪ 前言
Yii2 详细的日志使用参见 官方教程,这里我们仅对 Yii2 日志相关的疑难问题做些笔记以及在人性化方面做一点点的小改造。
▪ 消息跟踪级别
在官方教程中有个 消息跟踪级别 的配置:
'components' => [
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [...],
],
],
官方的说明是:上面的应用配置设置了 yii\log\Dispatcher::traceLevel
的层级,假如 YII_DEBUG 开启则是3,否则是0。 这意味着,假如 YII_DEBUG 开启,每个日志消息在日志消息被记录的时候, 将被追加最多3个调用堆栈层级;假如 YII_DEBUG 关闭, 那么将没有调用堆栈信息被包含。
但是在实际测试中发现无论 traceLevel
设置为什么值,错误日志的 Stack trace 还是全部输出,而并非只有3条:
==================================================
2017-06-17 06:37:56 [IP:127.0.0.1] [UID:-] [SID:-]
==================================================
[error][yii\base\ErrorException:4] exception 'yii\base\ErrorException' with message 'syntax error, unexpected 'return' (T_RETURN)' in D:\Development\wamp\www\lengdo.new\frontend\modules\kernel\controllers\IndexController.php:37
Stack trace:
#0 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Module.php(633): ::spl_autoload_call()
#1 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Module.php(633): ::class_exists()
#2 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Module.php(591): yii\base\Module->createControllerByID()
#3 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Module.php(583): yii\base\Module->createController()
#4 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Module.php(517): yii\base\Module->createController()
#5 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\web\Application.php(102): yii\base\Module->runAction()
#6 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Application.php(380): yii\web\Application->handleRequest()
#7 D:\Development\wamp\www\lengdo.new\frontend\web\index.php(17): yii\base\Application->run()
#8 {main}
一直没解决,知道的朋友分享下这个 traceLevel
究竟是指什么?
▪ 美化日志格式
默认,我们一般配置日志的输出目标为 FileTarget:
# main.php
'components' => [
'log' => [
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
]
],
],
],
yii\log\FileTarget
默认将日志信息记录在 Yii::$app->getRuntimePath().'/logs/app.log'
文件里,内容大概如下:
2017-06-15 09:29:28 [-][1][9sc6291lqmftgo2pnjgfu69h44][error][yii\base\UnknownPropertyException] exception 'yii\base\UnknownPropertyException' with message 'Getting unknown property: frontend\modules\kernel\controllers\IndexController::aa' in D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Component.php:147
Stack trace:
#0 D:\Development\wamp\www\lengdo.new\frontend\modules\kernel\controllers\IndexController.php(37): yii\base\Component->__get('aa')
#1 [internal function]: frontend\modules\kernel\controllers\IndexController->actionIndex()
#2 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\InlineAction.php(57): call_user_func_array(Array, Array)
#3 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Controller.php(156): yii\base\InlineAction->runWithParams(Array)
#4 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Module.php(523): yii\base\Controller->runAction('index', Array)
#5 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\web\Application.php(102): yii\base\Module->runAction('kernel/index/in...', Array)
#6 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Application.php(380): yii\web\Application->handleRequest(Object(yii\web\Request))
#7 D:\Development\wamp\www\lengdo.new\frontend\web\index.php(17): yii\base\Application->run()
#8 {main}
2017-06-15 09:29:28 [-][1][9sc6291lqmftgo2pnjgfu69h44][info][application] $_GET = [
'r' => 'kernel/index/index'
]
......
上述的内容里显示了两条错误的详细信息,第一眼真的很难区分哪几个信息是属于一条错误的、哪行开始是另一条错误的。尤其在很多条错误的的时候就更难区分了。
出于上述的考虑,需要基于 FileTarget 重新美化日志信息的输出格式,美化后效果如下:
===========================================================================
2017-06-15 09:29:28 [IP:127.0.0.1] [UID:1] [SID:9sc6291lqmftgo2pnjgfu69h44]
===========================================================================
[error][yii\base\UnknownPropertyException] exception 'yii\base\UnknownPropertyException' with message 'Getting unknown property: frontend\modules\kernel\controllers\IndexController::aa' in D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Component.php:147
Stack trace:
#0 D:\Development\wamp\www\lengdo.new\frontend\modules\kernel\controllers\IndexController.php(36): yii\base\Component->__get('aa')
#1 [internal function]: frontend\modules\kernel\controllers\IndexController->actionIndex()
#2 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\InlineAction.php(57): call_user_func_array(Array, Array)
#3 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Controller.php(156): yii\base\InlineAction->runWithParams(Array)
#4 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Module.php(523): yii\base\Controller->runAction('index', Array)
#5 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\web\Application.php(102): yii\base\Module->runAction('kernel/index/in...', Array)
#6 D:\Development\wamp\www\lengdo.new\vendor\yiisoft\yii2\base\Application.php(380): yii\web\Application->handleRequest(Object(yii\web\Request))
#7 D:\Development\wamp\www\lengdo.new\frontend\web\index.php(17): yii\base\Application->run()
#8 {main}
===========================================================================
2017-06-15 09:29:28 [IP:127.0.0.1] [UID:1] [SID:9sc6291lqmftgo2pnjgfu69h44]
===========================================================================
[info][application] $_GET = [
.....
美化的核心代码:
# main.php
'components' => [
'log' => [
'targets' => [
[
'class' => 'common\log\FileTargetExtend',
'levels' => ['error', 'warning'],
]
],
],
],
# common\log\FileTargetExtend.php
<?php
namespace common\log;
use Yii;
use yii\web\Request;
use yii\log\FileTarget;
/**
* FileTarget 扩展
* 由于 Yii2 的 FileTarget 在记录日志时其输出信息格式不是很便于阅读
* 所以此处基于 FileTarget 类创建一个扩展类,主要功能就是重新格式化输出的信息,便于阅读
*/
class FileTargetExtend extends FileTarget
{
/**
* 格式化消息
*
* @param array $message 原始消息
* @return string
*/
public function formatMessage( $message )
{
// 重构消息
$message = explode("\n", parent::formatMessage($message));
$message[0] = str_pad('',strlen($message[0]),'=')."\n".$message[0]."\n".str_pad('',strlen($message[0]),'=');
// 返回消息
return implode($message,"\n")."\n\n";
}
/**
* 构建消息的前戳
*
* @param array $message 原始消息
* @return string
*/
public function getMessagePrefix( $message )
{
if( $this->prefix !== null ) return call_user_func($this->prefix, $message);
if( Yii::$app === null ) return '';
$request = Yii::$app->getRequest();
$ip = $request instanceof Request ? $request->getUserIP() : '-';
/* @var $user \yii\web\User */
$user = Yii::$app->has('user', true) ? Yii::$app->get('user') : null;
$userID = $user && ($identity = $user->getIdentity(false)) ? $identity->getId() : '-';
/* @var $session \yii\web\Session */
$session = Yii::$app->has('session', true) ? Yii::$app->get('session') : null;
$sessionID = $session && $session->getIsActive() ? $session->getId() : '-';
return "[IP:$ip] [UID:$userID] [SID:$sessionID]\n";
}
}