Yii2框架设置错误日志输出到日志或数据库
更新:HHH   时间:2023-1-7


设置Yii的错误日志,可按照设置错误级别输入到日志或数据库中。
对yii\log\FileTarget做了重写。

1、设置common/config/main.php
$db = require(__DIR__ . '/db.php');
return [
    'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
    'bootstrap' => ['log'],
    'components' => [
        'cache' => [
            'class' => 'yii\caching\FileCache',
        ],
        'db' => $db,
        'log' => [
            'targets' => [
                [
                    'class' => 'yii\log\FileTarget',
                    'levels' => ['error', 'warning', 'info'],
                ],
                [
//                    'class' => 'yii\log\FileTarget',
                    'class' => 'app\common\components\FileTarget',
                    'levels' => ['error'],
                    'logFile' => '@runtime/logs/error.log',
                ],//日志入库
            ],
        ],
    ],
    'timeZone' => 'Asia/Shanghai',
];

2、app\common\components\FileTarget

<?php
 namespace app\common\components;

 use yii\helpers\VarDumper;
 use yii\log;

 class FileTarget extends log\FileTarget
 {
     public function export()
     {
        parent::export(); // TODO: Change the autogenerated stub
         //调用接口将数据入库  默认是收集错误日志
         if (empty(\Yii::$app->params['errorLog']['switch'])) {//设置参数是否收集错误日志

            $flag = false;
            if (empty($_SERVER['DOCUMENT_ROOT'])) {
                $projectName = '';
                $entrance = 'console';
                $flag = true;
            } else {
                $document_root = explode('/', $_SERVER['DOCUMENT_ROOT']);
                $projectName = $document_root[count($document_root) - 3];//项目名称
                $entrance = $document_root[count($document_root) - 2];//项目入口
            }

            $params = $_POST ?: $_GET;
            $errList = [];
            foreach ($this->messages as $message) {
                list($text, $level, $category, $timestamp) = $message;
                if ($level <> 4) {
                    if (!is_string($text)) {
                        // exceptions may not be serializable if in the call stack somewhere is a Closure
                        if ($text instanceof \Throwable || $text instanceof \Exception) {
                            $text = (string)$text;
                        } else {
                            $text = VarDumper::export($text);
                        }
                    }

                    if ($flag) {
                        $dir1 = '/var/www/html/';
                        $start = strpos($text, $dir1);
                        if (!$start) {
                            $dir1 = '/disk/html/';
                            $start = strpos($text, $dir1);
                            $project = substr($text, $start + strlen($dir1), 50);
                            $project = explode('/', $project);
                            $projectName = $project[0];

                        } else {
                            $project = substr($text, $start + strlen($dir1), 50);
                            $project = explode('/', $project);
                            $projectName = $project[0];
                        }
                    }

                    $text = $text . "\n" . "params:" . json_encode($params);
                    $errType = 'error';
                    if (stripos($category, 'db')) {
                        $errType = 'db';
                    } else if (stripos($text, 'Redis')) {
                        $errType = 'redis';
                    }
                    $item = [];
                    $item[] = empty($projectName) ? '0' : $projectName;//项目
                    $item[] = empty($entrance) ? '0' : $entrance;//入口
                    $item[] = empty($_SERVER['SERVER_NAME']) ? '0' : $_SERVER['SERVER_NAME'];
                    $item[] = $level;
                    $item[] = $category;
                    $item[] = $timestamp;
                    $item[] = $this->getMessagePrefix($message);
                    $item[] = IPUtils::get_local_ip();
                    $item[] = empty($_SERVER['REQUEST_URI']) ? '0' : $_SERVER['REQUEST_URI'];
                    $item[] = $errType;
                    $item[] = $text;//错误信息
                    $errList[] = $item;
                }
            }
            //请求接口入库
            $this->collectErrorLog($errList);
        }
    }

    /**
     * @param $data
     * @return mixed
     * 错误日志入库
     */
    private function collectErrorLog($data)
    {
        if (empty(\Yii::$app->params['errorLog']['logApiDomain'])) {
            if (YII_ENV == 'local' || YII_ENV == 'dev') {
                $url = 'http://dev.api.log.3ttech.cn/inner/collect-error-log?';
            } else {
                $url = 'http://api.log.3ttech.cn/inner/collect-error-log?';
            }
        } else {
            $url = \Yii::$app->params['errorLog']['logApiDomain'] . '/inner/collect-error-log?';
        }
        $requestBody = [
            'data' => $data,
        ];
        $url .= http_build_query($requestBody);
        $response = json_decode(AHelper::curl_get($url), true);
        return $response;
    }
}

3、数据表的结构如下:
表字段可按照yii2框架中的字段调整设置。

CREATE TABLE `t_user_logs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `project` varchar(100) NOT NULL DEFAULT '' COMMENT '项目名称',
  `entrance` varchar(20) NOT NULL DEFAULT '' COMMENT '入口',
  `address` varchar(50) NOT NULL DEFAULT '' COMMENT '访问域名',
  `level` varchar(200) NOT NULL DEFAULT '' COMMENT '错误级别',
  `category` varchar(200) NOT NULL DEFAULT '' COMMENT '类别',
  `log_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '日志时间',
  `prefix` varchar(200) NOT NULL DEFAULT '' COMMENT '前缀',
  `suffix` varchar(200) NOT NULL DEFAULT '' COMMENT '报错服务器ip',
  `request_uri` varchar(100) NOT NULL DEFAULT '' COMMENT '请求路由',
  `errType` varchar(20) NOT NULL DEFAULT '4' COMMENT '错误类型',
  `message` text NOT NULL COMMENT '消息',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100001 DEFAULT CHARSET=utf8;
返回web开发教程...