您现在的位置是:网站首页>>PHP>>Yii

Yii使用DbTarget实现日志功能

发布时间:2020-07-21 09:05:02作者:wangjian浏览量:192点赞量:0

    一:在配置文件的log组件中配置DbTarget

    image.png

    'log' => [
        'traceLevel' => YII_DEBUG ? 3 : 0,
        'targets' => [
            [
                'class' => 'yii\log\FileTarget',
                'levels' => ['error', 'warning'],
            ],
            'test' => [
                'class' => 'yii\log\DbTarget',//DaTarget类
                'logTable' => '{{%test_log}}',//日志表
                'levels' => ['error', 'info', 'warning'],//日志等级
            ],
        ],
    ],

    二:生成日志表

    在项目目录下执行如下命令生成日志表

    php yii migrate --migrationPath=@yii/log/migrations/

    三:使用日志

    在需要使用日志的地方使用

    Yii::info()

    四:自定义DbTarget日志

    1:首先创建一个自定义的日志表

    (1)在项目目录下执行

    php yii migrate/create create_test_log

    (2):在创建的migrate文件下编写创建数据库的迁移脚本

    <?php
    use yii\db\Migration;
    /**
     * Class m200720_091126_create_test_log
     */
    class m200720_091126_create_test_log extends Migration
    {
        /**
         * {@inheritdoc}
         */
        public function safeUp()
        {
            $this->createTable('{{%test_log}}', [
                'id' => $this->bigPrimaryKey(),
                'level' => $this->integer()->notNull()->comment('日志等级'),
                'category' => $this->string(100)->notNull()->comment('分类名称'),
                'prefix' => $this->text(),
                'route' => $this->string(100)->notNull()->comment('路由'),
                'method' => $this->string(20)->notNull()->comment('请求方式'),
                'app' => $this->string(20)->comment('请求应用'),
                'module' => $this->string(20)->comment('请求模块'),
                'request' => $this->text()->comment('请求参数'),
                'status' => $this->string(10)->notNull()->comment('状态码'),
                'message' => $this->text()->comment('日志内容'),
                'request_at' => $this->double()->notNull()->comment('请求时间'),
                'ip' => $this->string(63)->comment('请求IP'),
            ], 'CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE=InnoDB COMMENT=\'请求日志表\'');
            //增加索引
            $this->createIndex('idx_log_level', '{{%test_log}}', 'level');
            $this->createIndex('idx_log_category', '{{%test_log}}', 'category');
            $this->createIndex('idx_log_route', '{{%test_log}}', 'route');
            $this->createIndex('idx_log_method', '{{%test_log}}', 'method');
            $this->createIndex('idx_log_status', '{{%test_log}}', 'status');
        }
        /**
         * @inheritdoc
         */
        public function safeDown()
        {
            $this->dropTable('{{%test_log}}');
        }
    }

    (3):执行如下命令生成DbTarget日志表

    php yii migrate

    2:编写一个DbTarget类来继承yii\log\DbTarget类

    <?php
    namespace app\components;
    use Yii;
    use yii\helpers\VarDumper;
    use yii\log\LogRuntimeException;
    use yii\web\HttpException;
    use yii\web\Request;
    /**
     * DbTarget stores log messages in a database table.
     *
     * @see yii\log\DbTarget
     *
     * @author wangjian
     * @since 1.0
     */
    class DbTarget extends \yii\log\DbTarget
    {
        /**
         * @inheritdoc
         */
        public $categories = [
            'application',
            'yii\web\HttpException:*',
        ];
        /**
         * @inheritdoc
         */
        public $except = [
            // 'yii\web\HttpException:404',
        ];
        /**
         * @inheritdoc
         */
        public $logVars = ['_GET', '_POST'];
        /**
         * @var string 用户组件ID
         */
        public $userComponentId = 'user';
        /**
         * @inheritdoc
         */
        public function collect($messages, $final)
        {
            $this->messages = array_merge($this->messages, static::filterMessages($messages, $this->getLevels(), $this->categories, $this->except));
            $count = count($this->messages);
            if ($count > 0 && ($final || $this->exportInterval > 0 && $count >= $this->exportInterval)) {
                $oldExportInterval = $this->exportInterval;
                $this->exportInterval = 0;
                $this->export();
                $this->exportInterval = $oldExportInterval;
                $this->messages = [];
            }
        }
        /**
         * @inheritdoc
         */
        public function getMessagePrefix($message)
        {
            if ($this->prefix !== null) {
                return call_user_func($this->prefix, $message);
            }
            if (Yii::$app === null) {
                return '';
            }
            $ip = $this->getIp();
            $ip = empty($ip) ? '-' : $ip;
            return "[$ip]";
        }
        /**
         * @inheritdoc
         */
        public function export()
        {
            if ($this->db->getTransaction()) {
                $this->db = clone $this->db;
            }
            $tableName = $this->db->quoteTableName($this->logTable);
            $sql = "INSERT INTO $tableName ([[level]], [[category]], [[prefix]], [[route]], [[method]], [[app]], [[module]], [[request]], [[status]], [[message]], [[request_at]], [[ip]])
                    VALUES (:level, :category, :prefix, :route, :method, :app, :module, :request, :status, :message, :request_at, :ip)";
            $command = $this->db->createCommand($sql);
            $request = Yii::$app->getRequest();
            list($route, $params) = $request->resolve();
            $method = $request->getMethod();
            $module = Yii::$app->controller->module->id;
            $route = str_replace("{$module}/", '', $route);
            foreach ($this->messages as $message) {
                list($text, $level, $category, $timestamp) = $message;
                $statusCode = 200;
                if (!is_string($text)) {
                    if ($text instanceof \Throwable || $text instanceof \Exception) {
                        $statusCode = $text instanceof HttpException ? $text->statusCode : 500;
                        $text = $text->getMessage();
                    } else {
                        $text = VarDumper::export($text);
                    }
                }
                if ($command->bindValues([
                        ':level' => $level,
                        ':category' => $category,
                        ':prefix' => $this->getMessagePrefix($message),
                        ':route' => $route,
                        ':method' => $method,
                        ':app' => Yii::$app->id,
                        ':module' => $module,
                        ':request' => $this->getContextMessage(),
                        ':status' => $statusCode,
                        ':message' => $text,
                        ':request_at' => $timestamp,
                        ':ip' => $this->getIp(),
                    ])->execute() > 0) {
                    continue;
                }
                throw new LogRuntimeException('Unable to export log through database!');
            }
        }
        /**
         * 获取当前IP
         */
        protected function getIp()
        {
            $request = Yii::$app->getRequest();
            return $request instanceof Request ? $request->getUserIP() : '';
        }
    }

    3:在配置文件中将yii\log\DbTarget类改成我们自定义的类

    'log' => [
        'traceLevel' => YII_DEBUG ? 3 : 0,
        'targets' => [
            [
                'class' => 'yii\log\FileTarget',
                'levels' => ['error', 'warning'],
            ],
            'test' => [
                'class' => 'app\components\DbTarget',
                'logTable' => '{{%test_log}}',
                'levels' => ['error', 'info', 'warning'],
            ],
        ],
    ],

    4:使用DbTarget日志

    同样的使用Yii::info来记录日志

0 +1