当前位置: 首页 > 后端技术 > PHP

Lumen实现SQL监控

时间:2023-03-30 03:17:57 PHP

首发于:Lumen框架从5.6升级到5.7之前我的博客。发现laravel-sql-logger包无法正常记录日志。经过排查,发现是Lumen框架没有将事件对象注入到DB类型中,导致无法对其正常进行SQL监控。那么解决方法也很简单。//文件:bootstrap/app.php$app["db"]->connection()->setEventDispatcher($app["events"]);//在注册之前添加这一行$app->register(Mnabialek\LaravelSqlLogger\Providers\ServiceProvider::class);但这也让我对如何实现SQL日志记录产生了兴趣。下面我们就来详细了解一下SQL监控是如何实现的。我们知道在Larvel上这很容易。只需要如下方法对其进行SQL监控:namespaceApp\Providers;useIlluminate\Support\Facades\DB;useIlluminate\Support\ServiceProvider;classAppServiceProviderextendsServiceProvider{/***启动应用服务**@returnvoid*/publicfunctionboot(){DB::listen(function($query){//$query->sql//$query->bindings//$query->time});}//...}但是在Lumen上是没有办法使用这个方法的。Lumen有自己的一些调试SQL的方法,但这些都不是我们想要的。所以我们只能自己写监听事件了。具体的解决方法是我们先创建一个Listener文件。//文件:app\Listeners\QueryListener.phpnamespaceApp\Listeners;useIlluminate\Database\Events\QueryExecuted;classQueryListener{/***创建事件监听器。**@returnvoid*/publicfunction__construct(){//}/***处理事件。**@paramExampleEvent$event*@returnvoid*/publicfunctionhandle(QueryExecuted$event){dd($event);//这里直接打印出来}}我们直接注册//文件:app/Providers/EventServiceProvider.phpnamespaceApp\Providers;useApp\Listeners\QueryListener;useIlluminate\Database\Events\QueryExecuted;useLaravel\Lumen\Providers\EventServiceProviderasServiceProvider;classEventServiceProviderextendsServiceProvider{/***应用程序的事件侦听器映射。**@vararray*/protected$listen=[QueryExecuted::class=>[//这一行QueryListener::class,//和这一行],];}别忘了注册ServiceProviders//文件:bootstrap/app.php'/*|--------------------------------------------------------------------------|注册服务商|----------------------------------------------------------------------||在这里我们将注册应用程序的所有服务提供商which|用于将服务绑定到容器中。服务提供商是|完全可选,所以你不需要取消注释这一行。|*///$app->register(App\Providers\AppServiceProvider::class);//$app->register(App\Providers\AuthServiceProvider::class);$app->register(App\Providers\EventServiceProvider::class);//取消对这一步的注解接下去就是实操了首先我们创建一个控制器//file:app/Http/Controllers/UserController.phpnamespaceApp\Http\Controllers;useApp\User;classUserControllerextendsController{publicfunctionone(){returnUser::where("id",1)->首先();//在控制器中执行查询方法}}注册路由//文件:routes/web.php$router->get('/one',"UserController@one");//定义访问路径最后别忘了开启DB功能,填写数据库配置(这部分大家都知道,就不贴代码了)。所以让我们尝试运行它:QueryExecuted{#65▼+sql:"select*from`users`where`id`=?limit1"+bindings:array:1[?]+time:2.06+connection:MySqlConnection{#66?}+connectionName:"mysql"}发现成功。然后可以执行日志记录。让我们修改代码://file:app/Listeners/QueryListener.phpnamespaceApp\Listeners;useIlluminate\Database\Events\QueryExecuted;useIlluminate\Support\Facades\Log;classQueryListener{/***创建事件监听器。**@returnvoid*/publicfunction__construct(){//}/***处理事件。**@paramExampleEvent$event*@returnvoid*/publicfunctionhandle(QueryExecuted$event){$query=$event->sql;//获取SQL语句foreach($event->bindingsas$bind){$query=preg_replace('/\?/',(is_numeric($bind)?$bind:'\''.$bind.'\''),$查询,1);//更换?在具有实际值的SQL中}Log::info("query:{$query}time:{$event->time}ms");//将SQL和执行时间打印到日志中}}虽然实现了SQL记录,但这不是我们想要的,因为SQL和错误日志是放在一起的。读起来很不舒服。然后我需要把它放在一个单独的文件中。//文件:app/Listeners/QueryListener.phpnamespaceApp\Listeners;useIlluminate\Database\Events\QueryExecuted;useIlluminate\Http\Request;classQueryListener{/***写入的文件路径*@varstring*/protected$写文件;/***创建事件监听器。**@returnvoid*/publicfunction__construct(){$this->writeFile=storage_path().DIRECTORY_SEPARATOR。“日志”。DIRECTORY_SEPARATOR。“sql-”。日期(“Ymd”)。“。日志”;//确定输出的日志路径}/***处理事件。**@paramQueryExecuted$event*@paramRequest$request*@returnvoid*/publicfunctionhandle(QueryExecuted$event){$query=$event->sql;foreach($event->bindingsas$bind){$query=preg_replace('/\?/',(is_numeric($bind)?$bind:'\''.$bind.'\''),$query,1);}file_put_contents($this->writeFile,"查询:{$query}时间:{$event->time}ms",FILE_A附加);//直接使用file_put_contents输入内容注意如果不加FILE_APPEND会被覆盖这个常量的作用是追加到文件中。}}继续完善,也就是说我们目前在所有环境下打印,但是我们只需要在开发环境下调试即可。所以我们可以做如下修改://file:app/Providers/EventServiceProvider.phpnamespaceApp\Providers;useApp\Listeners\QueryListener;useIlluminate\Database\Events\QueryExecuted;useLaravel\Lumen\Providers\EventServiceProviderasServiceProvider;classEventServiceProviderextendsServiceProvider{/***应用程序的事件侦听器映射。**@vararray*/protected$listen=[];publicfunctionregister(){if(env("APP_ENV")=="local"){//判断环境$events=app('events');$events->listen(QueryExecuted::class,QueryListener::class);//手动注册监听器}}}然后SQL监听功能就实现了。其实laravel-sql-logger也有一些高级的展示功能。比如在打印日志的时候,请求的URL也会一并打印出来。打印请求时间等,这里就不细说了。如果你有兴趣,你可以自己想办法实现。很简单。