相关环境:PHP7.4 + Laravel8.83.8
日志记录是项目必不可少的,他可以帮助我们排查一些问题,那这节我们就以接口请求与接口返回的记录作为重点。
项目里面的接口很多,我们不可能在每个方法里面人工的加Log::info()这种,这样太累也不好维护。所以我是使用中间件来做的:
第一步新建一个中间件
php artisan make:middleware AccessLog
便会在app\Http\Middleware下面生成AccessLog.php,代码如下:
namespace App\Http\Middleware; | |
use Closure; | |
use Illuminate\Http\Request; | |
use Illuminate\Support\Facades\Log; | |
class AccessLog | |
{ | |
/** | |
* Handle an incoming request. | |
* | |
* @param \Illuminate\Http\Request $request | |
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next | |
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse | |
*/ | |
public function handle(Request $request, Closure $next) | |
{ | |
$traceId = md5(time() . mt_rand(1, 1000000)); | |
// 记录请求信息 | |
$requestMessage = [ | |
'traceId' => $traceId, | |
'url' => $request->url(), | |
'method' => $request->method(), | |
'ip' => $request->ips(), | |
'headers' => $request->header('Authorization'), | |
'params' => $request->all() | |
]; | |
Log::info("请求信息:", $requestMessage); | |
$respone = $next($request); | |
$responeData = [ | |
'traceId' => $traceId, | |
'respone' => json_decode($respone->getContent(), true) ?? "" | |
]; | |
Log::info("返回信息:", $responeData); | |
return $respone; | |
} | |
} |
以$respone = $next($request);为界限,上面是请求下面是返回。
第二步配置全局路由
在app\Http\Kernel.php里的$middleware数组加入AccessLog:
namespace App\Http; | |
use App\Http\Middleware\AccessLog; | |
use Illuminate\Foundation\Http\Kernel as HttpKernel; | |
class Kernel extends HttpKernel | |
{ | |
/** | |
* The application's global HTTP middleware stack. | |
* | |
* These middleware are run during every request to your application. | |
* | |
* @var array<int, class-string|string> | |
*/ | |
protected $middleware = [ | |
\App\Http\Middleware\TrustProxies::class, | |
\Fruitcake\Cors\HandleCors::class, | |
\App\Http\Middleware\PreventRequestsDuringMaintenance::class, | |
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, | |
\App\Http\Middleware\TrimStrings::class, | |
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, | |
AccessLog::class, //全局请求返回日志记录 | |
]; |
这样所有请求都会进入这个AccessLog里面。
测试一下:
控制器代码:
namespace App\Http\Admin\User; | |
use App\Http\Admin\Controller; | |
class UserController extends Controller | |
{ | |
public function detail() | |
{ | |
$id = request()->input("id"); | |
$data = UserAdmin::find($id, ['id', 'mobile']); | |
return response()->json([ | |
'code' => 0, | |
'message' => "success", | |
'data' => $data | |
]); | |
} | |
} |
日志打印如下:
补充:
如果代码出现异常,我们发现日志会把这异常也记录下来,模拟一下,查个不存在的字段:
namespace App\Http\Admin\User; | |
use App\Http\Admin\Controller; | |
class UserController extends Controller | |
{ | |
public function detail() | |
{ | |
$id = request()->input("id"); | |
$data = UserAdmin::find($id, ['id', 'test']); //不存在的test字段 | |
return response()->json([ | |
'code' => 0, | |
'message' => "success", | |
'data' => $data | |
]); | |
} | |
} |
这个时候去看日志,除了请求返回日志外,还有一个很长很长的异常日志【图片只截取一小部分,返回日志在下面没有截取出来】:
那如果你不想打印这个异常日志,也可以实现,在app\Exceptions\Handler.php里面有个$dontReport数组,他就是配置不会被记录到日志文件的异常类型数组。我们看异常日志,他是通过Illuminate\Database\QueryException类抛出的,那我们在$dontReport加上他:
namespace App\Exceptions; | |
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; | |
use Throwable; | |
class Handler extends ExceptionHandler | |
{ | |
/** | |
* A list of the exception types that are not reported. | |
* 不会被记录到日志文件的异常类型数组 | |
* | |
* @var array<int, class-string<Throwable>> | |
*/ | |
protected $dontReport = [ | |
\Illuminate\Database\QueryException::class, | |
]; | |
/** | |
* A list of the inputs that are never flashed for validation exceptions. | |
* | |
* @var array<int, string> | |
*/ | |
protected $dontFlash = [ | |
'current_password', | |
'password', | |
'password_confirmation', | |
]; | |
/** | |
* Register the exception handling callbacks for the application. | |
* | |
* @return void | |
*/ | |
public function register() | |
{ | |
$this->reportable(function (Throwable $e) { | |
// | |
}); | |
} | |
public function render($request, Throwable $e) | |
{ | |
return response()->json([ | |
'code' => $e->getCode() ?? 1, | |
'file' => $e->getFile(), | |
'line' => $e->getLine(), | |
'message' => $e->getMessage() ?? "error!", | |
'data' => [] | |
]); | |
} | |
} |
再次运行接口,发现异常日志就不会记录了: