laravel5.5 集成socketlog中的一些坑
不知道是不是socketlog在laravel的composer有点水土不服的原因,使用命令
composer require luofei614/socketlog
安装完毕,并不能调用slog类,会报错,了解了composer的一些知识后只需在composer.json的autoload->classmap里加入这么一行
"vendor/luofei614/socketlog/php"
变成:
"autoload": { "classmap": [ "database/seeds", "database/factories", "vendor/luofei614/socketlog/php" ], "psr-4": { "App\\": "app/" } },
就可以了,在代码里调用
\think\slog::config(array( 'enable'=>true,//是否打印日志的开关 'host'=>'localhost',//websocket服务器地址,默认localhost 'optimize'=>false,//是否显示利于优化的参数,如果运行时间,消耗内存等,默认为false 'show_included_files'=>false,//是否显示本次程序运行加载了哪些文件,默认为false 'error_handler'=>false,//是否接管程序错误,将程序错误显示在console中,默认为false 'force_client_id'=>'',//日志强制记录到配置的client_id,默认为空 'allow_client_ids'=>array()////限制允许读取日志的client_id,默认为空,表示所有人都可以获得日志。 )); \think\slog::log('log');
发现并没有报错,ok!
但是,本着创新(瞎捣鼓)的精神,我想把socketlog作为laravel的服务嵌入laravel中去,于是就有了下面的爬坑经历,ps:这让我理解了laravel的容器的原理和运行方式
———————————————————华丽丽的分割线————————————————————
socketlog是一种基于socket的实时在线日志调试系统,可以像java里的console那样实时打印出想要输出的数据,对于调试纯后端程序像微信支付宝这种带异步回调的程序可以说是相当方便了,thinkphp5已经支持了socketlog就不多说了,让我们来看一下在laravel下的是如何使用的:
github上的是可以直接用composer安装的,但是安装完毕之后并不能直接调用,虽然已经use了该类,ctrl追踪也能追踪到该类文件,可它还老是提示找不到类文件,没办法,只能自己新建一个service和provider,然后再利用facade直接调用,然后这里的坑就开始了:
在app目录下新建services文件夹,将slog文件拖到该文件夹下并改名为SlogService,在控制台输入命令:
php artisan make:provider SlogServiceProvider
回车执行命令,然后再app/Providers 文件夹下就生成了一个SlogServiceProvider.php文件,修改register方法如下:
public function register() { $this->app->singleton('Slog',function(){ $config = config('slog');//提取slog配置 Slog::config($config);//初始化slog return App\Services\SlogService::class;//返回该方法 }); }
provider建好了,接下来就要开始在app.php注册了
打开 config/app.php,在providers数组中添加一行:
App\Providers\SlogServiceProvider::class,
这样在laravel启动的时候就会把Slog给初始化了,使用方法,使用
$this->app->make('Slog');
获取初始化好的Slog,然后就可以直接用了:
//$slog = resolve('Slog'); 使用辅助函数resolve也可以达到同样的效果 $slog::log(123456);
可是这样每次使用都要多一步声明的过程,太麻烦了,就不能直接用么,当然可以了,使用laravel 的 facade就可以了
在app目录下新建Facade文件夹,在该文件夹下新建Slog.php文件:
namespace App\Facade; class Slog extends \Illuminate\Support\Facades\Facade{ public static function getFacadeAccessor() { return resolve('Slog'); } }
然后到 config/app.php文件中的aliases中去注册该facade,添加一行:
App\Providers\SlogProvider::class,
然后就可以了,到程序中试一下
\Slog::log(Carbon::now());
咦?报错了:
Call to undefined method App\Services\SlogService::log()
而且在浏览器console还打印了三行:
我就打印了一次啊?
这是什么鬼???
看一下源码后发现,log方法是使用了魔术方法“__callStatic”,当调用了不存在的静态方法时就去__callStatic方法去找,那怎么还能找不到呢,这就要看facade了,facade找到其返回类的方法是找的非静态方法,__callStatic是管静态方法的,所以就报错了。
facade的“__callStatic”方法如下:
public static function __callStatic($method, $args) { $instance = static::getFacadeRoot(); switch (count($args)) { case 0: return $instance->$method(); case 1: return $instance->$method($args[0]); case 2: return $instance->$method($args[0], $args[1]); case 3: return $instance->$method($args[0], $args[1], $args[2]); case 4: return $instance->$method($args[0], $args[1], $args[2], $args[3]); default: return call_user_func_array([$instance, $method], $args); } }
由此可见,它使用的是"->"而不是"::"。
那怎么办呢,再加一个魔术方法"__call"就可以了:
public function __call($name, $arguments) { // TODO: Implement __call() method. self::__callStatic($name,$arguments); }
加上之后,倒是不报错了,可还是打印三行,木办法,只好继续看源码,然后发现,发送日志给服务器的语句写在了“__destruct”里,也就是类销毁的时候才发送,由于facade的机制问题才会出现三次打印,不过没关系,我们只要把“__destruct”里的发送语句挪到record方法里就可以了,将sendLog放到record末尾就可以了:
public function record($type,$msg='',$css='') { if(!self::check()) { return ; } self::$logs[]=array( 'type'=>$type, 'msg'=>$msg, 'css'=>$css ); self::sendLog(); }
再刷新,发现:
大功告成!