Laravel8记录请求和返回日志

Laravel框架
486
0
0
2022-10-16
标签   Laravel基础

相关环境:PHP7.4 + Laravel8.83.8

日志记录是项目必不可少的,他可以帮助我们排查一些问题,那这节我们就以接口请求与接口返回的记录作为重点。

项目里面的接口很多,我们不可能在每个方法里面人工的加Log::info()这种,这样太累也不好维护。所以我是使用中间件来做的:

第一步新建一个中间件

php artisan make:middleware AccessLog

便会在app\Http\Middleware下面生成AccessLog.php,代码如下:

<?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:

<?php

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里面。

测试一下:

控制器代码:

<?php

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
        ]);
    }
}

日志打印如下:

补充:

如果代码出现异常,我们发现日志会把这异常也记录下来,模拟一下,查个不存在的字段:

<?php

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加上他:

<?php

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' => []
        ]);
    }
}

再次运行接口,发现异常日志就不会记录了: