美文网首页
Yii2 如何优雅的记录接口日志

Yii2 如何优雅的记录接口日志

作者: PHP的点滴 | 来源:发表于2020-05-13 11:24 被阅读0次

    最近常使用Yii2写接口,但是有时候前端反应某个接口有问题,如何能快速定位问题呢?
    特别是那种很难复现的问!每当这个时候,总是感觉有个接口日志记录就太好了;

    对接口日志有以下需求

    • 1.配置简单、使用简单
    • 2.对现有的业务代码无污染
    • 3.记录信息全面,包括接口的执行市场
    • 4.支持指定哪些接口使用哪些不使用(大部分查询接口都不需要,比如默认指定 create,update,delete)
    • 5.支持写入到数据库(MySQL、Elasticsearch),方便查询
    • 6.当程序抛异常的时候,也能记录异常信息

    于是自己写了一个小组件,支持上面需求!
    当前是基于 Yii的事件处理机制写的组件!

    配置 config/web.php

      components = [
        ...
        'apiRequestLogs' => [
                'class' => 'app\core\events\ApiRequestLogs',
                'remark' => '',//日志的备注,可以在程序中指定备注信息,方便在线调试
            ],
        ...
      ]
    

    上代码 app\core\events\ApiRequestLogs

    <?php
    /**
     * 接口请求事件
     * 1.记录接口请求信息
     * 2.接口运行时间
     * 3.支持运行中的备注信息
     * 4.记录返回的数据
     * @author  jason <jasonwang1211@gmail.com>
     */
    
    namespace app\core\events;
    
    use app\models\ApiLog;
    use Jsyqw\Utils\IPHelper;
    use Jsyqw\Utils\RuntimeHelper;
    use yii\base\Event;
    use yii\helpers\Json;
    use yii\web\Application;
    use Yii;
    
    class ApiRequestLogs extends Event
    {
        public $remark = '';
    
        /**
         * 是否需要日志
         */
        public function isStartApiLog()
        {
            //注意;要在 BaseApiController 中有配置
            $startApiLog = Yii::$app->controller->startApiLog();
            if (!$startApiLog) {
                return false;
            }
            if (in_array('*', $startApiLog)) {
                return true;
            }
            $action = Yii::$app->controller->action->id;
            if (in_array($action, $startApiLog)) {
                return true;
            }
            return false;
        }
    
    
        /**
         * 开始执行
         */
        public function run()
        {
            //1.Action 开始的时候,执行事件
            Yii::$app->on(Application::EVENT_BEFORE_ACTION, function ($event) {
                if ($this->isStartApiLog()) {
                    //计时开始
                    RuntimeHelper::instance()->start();
                }
            });
    
            //2.请求结束的时候,记录日志
            Yii::$app->on(Application::EVENT_AFTER_REQUEST, function ($event) {
                if ($this->isStartApiLog()) {
                    //计时结束
                    RuntimeHelper::instance()->stop();
                    $responseData = Yii::$app->response->data;
                    $request = Yii::$app->request;
                    $userId = Yii::$app->user->id;
                    $route = Yii::$app->controller->route;
                    $code = isset($responseData['code']) ? $responseData['code'] : null;
                    $msg = isset($responseData['msg']) ? $responseData['msg'] : null;
                    $data = isset($responseData['data']) ? $responseData['data'] : null;
                    $responseContent = is_array($responseData) ? Json::encode($responseData) : $responseData;
    
                    $log = new ApiLog();
                    $log->user_id = $userId;
                    $log->time_consuming = RuntimeHelper::instance()->consumeTime();
                    $log->type = 1;
                    $log->ip = IPHelper::remoteIp();
                    $log->token = $request->getHeaders()->get('Authorization');
                    $log->route_name = $route;
                    $log->request_method = RequestHelper::instance()->getMethod();
                    $log->request_header = Json::encode($request->getHeaders());
                    $log->request_get = Json::encode($request->get());
                    $log->request_post = Json::encode($request->post());
                    $log->response_content = $responseContent;
                    $log->code = $code;
                    $log->msg = $msg;
                    $log->data = is_string($data) ? $data : Json::encode($data);
                    $log->remark = $this->remark;
                    $log->create_time = date('Y-m-d H:i:s');
                    $log->save(false);
                }
            });
        }
    }
    

    在模块初始化的时候,开启日志监听

    <?php
    
    namespace app\modules\api;
    
    use app\models\UserIdentity;
    use yii\web\Response;
    
    /**
     * api module definition class
     */
    class Module extends \yii\base\Module
    {
        /**
         * {@inheritdoc}
         */
        public $controllerNamespace = 'app\modules\api\controllers';
    
        /**
         * {@inheritdoc}
         */
        public function init()
        {
            parent::init();
    
            //指定是 API用户模块
            \Yii::$app->user->module_user = UserIdentity::MODULE_USER_API;
            //初始化从参数
            \Yii::$app->user->enableSession = false;
            \Yii::$app->user->enableAutoLogin = false;
            \Yii::$app->user->loginUrl = '';
            \Yii::$app->response->format = Response::FORMAT_JSON;
    
            \Yii::$app->apiRequestLogs->run();
        }
    }
    
    

    在接口的 BaseApiController 中配置哪些需要记录

        /**
         * 开启接口日志,继承当前Controller的控制器,可以自定义配置
         * eg: ['*']  or ['login']
         * @return array
         */
        public function startApiLog()
        {
            return ['create', 'update', 'delete'];
        }
    

    配置 ErrorHandler (可选)主要是记录捕获异常后的日志

    
       protected function renderException($exception){
          ...
          //触发事件
          Yii::$app->trigger(Application::EVENT_AFTER_REQUEST);
      }
    

    具体UserController中应用,样例

    
    class UserController extends BaseApiController
    {
        public function ignoreCheckToken()
        {
            return ['login', 'logout'];
        }
    
        public function startApiLog()
        {
            return ['login', 'logout', 'change-pwd'];
        }
    
        public function actionLogin()
        {
            ...
            //可在请求任意节点,添加当前备注;
            Yii::$app->apiRequestLogs->remark = '备注信息' . date('Y-m-d H:i:s');
            ....
            return $this->asJson($model);
        }
    }
    

    入库的截图如下,当然同样操作,可以写入 ES 等数据库

    日志信息

    其他Yii2自带的日志

    关于框架自带的日志,在本地调试,或者测试环境还是比较方便的;但是在正式环境的时候,就不方便了!
    Yii2框架的日志配置很简单,使用也很容易,这里就不做深入讲解!

    相关文章

      网友评论

          本文标题:Yii2 如何优雅的记录接口日志

          本文链接:https://www.haomeiwen.com/subject/ozwgnhtx.html