dd,日志增强调试与测试体验
备注:本文针对tp5.0,由于tp不同版本的兼容性问题很多,以下这些内容仅供参考。
上一篇我们讲到了更换Collection组件。讲到了,有一组件奉送dd。未用过Laravel的肯定不知道dd是什么。dd实际是Debug Dump或Data Dump的简写。我想你一定清楚了,这是一个调试工具。你没用过,你一定不了解它的强大。它是基于symfony var-dumper 和 Collection来运行的。如果你不想安装Collection,那只要安装dd,怎么做?你可以安装larapack/dd,此组件是他们从同laravel框架中剥离。安装完成后,你就可以用dd进行代码调试了。
但到这里还没有结束。你还可以在application/common/exception中的文件中,把以下一行代码换dd。这样,每次出错,你都能拿到dd的结果。用过Laravel的人肯定清楚,tp出错最后显示的是一个web页,但这个页面除了浪费时间,其它基本没什么用。
为什么要dd,因为,有很多表单提交时,特别是遇到json等复杂格式时,tp只告诉你,"undefined offset 0"。遇到这类问题,本身是tp开发人员无产品意识,也许,他认为肯定不会出错,然而,就是这类复杂的多表联合更新,这个看起来亮眼的功能,最后把你折腾半死。经常有人常常几小时解决不了。并且,这个问题,害得很多小白程序员不得不去用Xdebug单步调试。但如果改用dd,则会数分钟解决。但解决后,却有程序员小哥讲,“I wanna kill him!”,明显可以看出,他对tp开发者的仇恨有多深。代码如下:
namespace app\common\exception;
use think\exception\Handle;
use think\Log;
use Exception;
/**
* 重写Handle的render方法,实现自定义异常消息
* Class ExceptionHandler
* @package app\common\library\exception
*/
class ExceptionHandler extends Handle
{
private $code;
private $message;
/**
* 输出异常信息
* @param Exception $e
* @return \think\Response|\think\response\Json
*/
public function render(Exception $e)
{
if ($e instanceof BaseException) {
$this->code = $e->code;
$this->message = $e->message;
} else {
if (config('app_debug')){
dd($e); //加上这一行,出错信息将全由dd提供!!后面一行就不执行了
return parent::render($e);
}
$this->code = 500;
$this->message = $e->getMessage() ?: '很抱歉,服务器内部错误';
$this->recordErrorLog($e);
}
return json(['msg' => $this->message, 'code' => $this->code]);
}
/**
* 将异常写入日志
* @param Exception $e
*/
private function recordErrorLog(Exception $e)
{
Loggy()::write('error',$e->getMessage() ." \r\n ". $e->getTraceAsString()); //写入自己的异常日志,不再调用tp的日志。
// Log::record($e->getTraceAsString(), 'error');
// Log::record($e->getMessage(), 'error');
}
}
上面代码中, return parent::render($e);就是tp的错误页。这个错误页有多没用,用过的人都清楚。换成dd输出,立刻神清气爽。
级联更新表格更新的出错,其实这只是tp极易出错的一个地方,原因在于它未对传入数据进行有效性检测。但是,这只是冰山一角。因为,你到github上看一下就知道了,tp的代码测试覆盖率仅有29%,完全拿用户当小白鼠。所以,还有哪些地方会出错,你是无法得知的。只有碰到了,才会发现。
怎么办,为防止意外发生,最好的办法就是全程监控。而监控最好的工具就是日志。Laravel那么牛的框架,都选了MonoLogo。我们也选它。
此外,调试不只是开发,同时还有线上运行的错误跟踪。这个最大的依赖则是日志。但tp的日志,百分之九十都是废话,并且,还不支持按通道分文件记录。怎么办,仍然是推荐使用MonoLogo这个组件。安装相当简单,直接通过composer安装即可。
composer require monolog/monolog
但是,安装之前千万小心,先把代码提交到SVN或Git,因为,你不知它何时出错,并且,出错后,thinkPHP目录就变成了topThink目录,到时,你可以手工删除与复制恢复。否则,你的项目肯定挂了。原因是什么呢?是因为tp未在composer.json中注明冲突。composer当然在你运行时给你升级到5.1。这种错误级别,对于开源行业的开发者来说,属于幼儿园大班级。但这种错直接让项目崩溃。所以,你不预防,那你就哭吧。
当然,安装好了MonoLogo,并不代表可以分通道记日志了。因为,分通道需求都是有经验的人的需求。但是,没有针对tp的分通道的组件。怎么办?幸运的是,Laravel框架有这样的组件,叫tolawho/loggy。当然,安装不了,但你可以把Loggy的源码复制过来使用,只要将stream/handler和stream/writer的代码即可。此代码中有laravel faced 和 serviceProvider相关的代码,tp没有,不需要。而config是为了检查通道的有效性的。其好处是,同一类错,可以同时写多个通道。这时,就不限于文件,同时可以有短信,邮件通道等。
这一步做好以后,你可以编写一个助手函数,获取Loggy的静态类。这样,就不必要在倒处使用use来引入Loggy了。上面的代码中:
Loggy()::write('error',$e->getMessage() ." \r\n ". $e->getTraceAsString());
就是这么实现的。
这时,你就可以把几乎没用的tp的Log关掉了。当然,如何关闭,你去逐磨吧。因为,要改tp的一些东西,很多都象《重构——改善既有代码的设计》一书中的霰弹式修改。太痛苦了。