利用 Laravel 中间件给后台加个操作日志

项目后台角色及人员变多,需要加下日志,方便查询,不妨利用中间件实现下。

方案:

  • 中间件判断是否需要记录,写入队列
  • 队列写入数据库

表设计

CREATE TABLE `admin_log` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `path` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `method` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL,
  `ip` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `input` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;

新建中间件AdminLogMiddleware,在后台路由中加入此中间件即可,

<?php
/**
 * Author: sai
 * Date: 2020/4/1
 * Time: 16:19
 */

namespace App\Http\Middleware;


use App\Jobs\OperationLogJob;
use Closure;
use Auth;

class AdminLogMiddleware
{
    /**
     * 处理传入的参数
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string  $role
     * @return mixed
     */
    public function handle($request, Closure $next, $role)
    {
        // 剔除GET,OPTIONS请求
        if (!in_array($method = $request->getMethod(), ['GET', 'OPTIONS'])) {
            $data = [
                'user_id' => Auth::guard('admin')->id(),
                'path' => $request->getPathInfo(),
                'method' => $method,
                'ip' => $request->getClientIp(),
                'input' => \json_encode($request->all(), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE),
            ];

            // 异步写入,提高操作流畅性
            $job = (new OperationLogJob($data));
            dispatch($job);
        }

        return $next($request);
    }

}
<?php

namespace App\Jobs;

use App\Models\AdminLog;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class OperationLogJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    // 任务可以尝试的最大次数。
    public $tries = 2;

    // 任务可以执行的最大秒数 (超时时间)。
    public $timeout = 120;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($data)
    {
        //
        $this->queue = 'adminLog';
        $this->data = $data;
    }

    private $data;

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        //
        AdminLog::create($this->data);
    }
}

执行队列:

php artisan queue:work --queue=adminLog

当然,也可以不写入数据库,写在log文件里,这里就不展开了。

另外,为了方便,也可以给后台统一加入AdminLogMiddleware中间件,把不需要做记录的路由加入配置文件,在中间件加入判断,省去在路由配置去区分是否需要记录。

本作品采用《CC 协议》,转载必须注明作者和本文链接
分享开发知识,欢迎交流。公众号:开源到
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 2

这样的中间件是不是在操作之前就执行了? 会不会有操作失败的也写入了数据库,能不能用后置中间件呢,就是在操作完成后执行中间件。

3年前 评论
已下线 (楼主) 3年前

job 必须得加上重试次数上限 retries,如果抛出异常,任务会无休止的重复运行,吃过一次大亏。

3年前 评论
已下线 (楼主) 3年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!