转载:https://www.firstphp.com/archives/250.html
项目的持久运行过程中,随着数据的积累或陡增,时长伴随着一些性能问题、接口响应慢等用户体验问题,当然也不排除一些写法不合理的慢查询SQL所导致。我们在排查问题时,通常都会开启慢日志查询,来通过慢查询的SQL语句来推导出业务功能,但是这里面可能存在一个问题,即在大型项目上纷繁的功能模块,产生的各种形形色色的SQL语句,而且有些业务模块功能强关联的,很难一下通过一条SQL直接定位功能所在。
在思考这个问题的时候一直在想能否有一些辅助方法,来方便快速、便捷的排查慢查询语句,查询愈慢则与之最直接的就是API响应时间愈长,于是思路顿开,通过记录每个API调用的接口访问情况,譬如客户端client_ip、rui、route、path及相应时间等等,其次还可以通过汇总统计API的调用频率,用以评估功能受众如何,岂不妙哉?而后通过laravel的前置/后置中间件的使用场景实现了整个过程,详述如下:
CREATE TABLE `access_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `enterprise_id` int(11) DEFAULT NULL, `method` char(6) DEFAULT NULL, `route` varchar(255) DEFAULT NULL, `client_ip` varchar(45) DEFAULT NULL, `params` varchar(300) DEFAULT NULL, `user_agent` varchar(100) DEFAULT NULL, `time` char(30) DEFAULT NULL, `created_at` datetime DEFAULT NULL, `updated_at` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=177 DEFAULT CHARSET=utf8mb4;
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class AccessLog extends Model
{
protected $table = 'access_log';
protected $guarded = ['id'];
}
<?php
namespace App\Http\Middleware;
use Closure;
define('START', microtime(true));
class BeforeMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
return $next($request);
}
}
<?php
namespace App\Http\Middleware;
use App\Models\AccessLog;
use Closure;
use Illuminate\Support\Facades\DB;
class AfterMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$params = $request->all();
$data = [
'method' => $request->method(),
'route' => $request->getPathInfo(),
'client_ip' => $request->ip(),
'params' => $params ? json_encode($params) : '',
'user_agent' => $request->userAgent(),
'time' => round(microtime(true) - START, 3)
];
$authToken = $request->bearerToken();
if ($authToken) {
$object = \Tymon\JWTAuth\Facades\JWTAuth::setToken($authToken)->getPayload()->get('sub');
$authInfo = object_to_array($object);
if (isset($authInfo['enterprise_id'])) {
$data['enterprise_id'] = $authInfo['enterprise_id'];
}
}
DB::beginTransaction();
try {
AccessLog::query()->create($data);
DB::commit();
} catch (\Exception $e){
DB::rollback();
}
return $response;
}
}$middleware里面添加中间件:
protected $middleware = [ \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, \App\Http\Middleware\TrustProxies::class, \App\Http\Middleware\EnableCrossRequestMiddleware::class, \App\Http\Middleware\AfterMiddleware::class, \App\Http\Middleware\BeforeMiddleware::class, ];
