ThinkPHP项目日志按级别分类

wen PHP项目 3

本文目录导读:

ThinkPHP项目日志按级别分类

  1. 使用ThinkPHP内置的日志级别
  2. 配置日志按级别分类
  3. 使用自定义日志驱动
  4. 在中间件中自动分类日志
  5. 日志级别过滤
  6. 生产环境配置建议
  7. 目录结构效果

在ThinkPHP项目中,日志按级别分类是一个非常实用的功能,以下是几种实现方法:

使用ThinkPHP内置的日志级别

ThinkPHP 6/8 默认支持以下日志级别:

  • emergency (紧急)
  • alert (警报)
  • critical (严重)
  • error (错误)
  • warning (警告)
  • notice (提示)
  • info (信息)
  • debug (调试)
  • sql (SQL查询)

配置日志按级别分类

修改配置文件

config/log.php 中配置:

<?php
return [
    // 默认日志记录通道
    'default'      => 'file',
    // 日志级别
    'level'        => [],
    // 日志类型分类
    'type_channel' => [
        // 将不同级别的日志写到不同文件
        'error' => 'error_log',
        'info'  => 'info_log',
        'sql'   => 'sql_log',
        'debug' => 'debug_log',
    ],
    // 日志通道列表
    'channels'     => [
        'file' => [
            'type'           => 'File',
            'path'           => '',
            'single'         => false,
            // 按日期和级别生成文件
            'file_name'      => 'Y-m-d',
            'max_files'      => 30,
            'json'           => false,
            // 按级别分目录
            'level_dir'      => true,
            'format'         => '[%s][%s] %s',
            'time_format'    => 'Y-m-d H:i:s',
        ],
        // 错误日志通道
        'error_log' => [
            'type'  => 'File',
            'path'  => app()->getRuntimePath() . 'log/error/',
            'level' => ['error', 'emergency', 'critical', 'alert'],
        ],
        // 信息日志通道
        'info_log' => [
            'type'  => 'File',
            'path'  => app()->getRuntimePath() . 'log/info/',
            'level' => ['info', 'notice'],
        ],
        // 调试日志通道
        'debug_log' => [
            'type'  => 'File',
            'path'  => app()->getRuntimePath() . 'log/debug/',
            'level' => ['debug'],
        ],
        // SQL日志通道
        'sql_log' => [
            'type'  => 'File',
            'path'  => app()->getRuntimePath() . 'log/sql/',
            'level' => ['sql'],
        ],
    ],
];

使用日志通道动态选择

<?php
namespace app\common\service;
use think\facade\Log;
class LogService
{
    /**
     * 记录错误日志
     */
    public function error($message, array $context = [])
    {
        Log::channel('error_log')->error($message, $context);
    }
    /**
     * 记录信息日志
     */
    public function info($message, array $context = [])
    {
        Log::channel('info_log')->info($message, $context);
    }
    /**
     * 记录调试日志
     */
    public function debug($message, array $context = [])
    {
        Log::channel('debug_log')->debug($message, $context);
    }
    /**
     * 记录SQL日志
     */
    public function sql($message, array $context = [])
    {
        Log::channel('sql_log')->sql($message, $context);
    }
}

使用自定义日志驱动

创建自定义日志驱动类:

<?php
namespace app\common\log;
use think\contract\LogHandlerInterface;
class LevelFileLog implements LogHandlerInterface
{
    protected $config = [
        'path' => '',
        'level' => [],
        'format' => '[%s][%s] %s',
    ];
    public function __construct(array $config = [])
    {
        $this->config = array_merge($this->config, $config);
    }
    /**
     * 日志写入接口
     */
    public function write(array $record): void
    {
        // 获取日志级别
        $level = $record['level'] ?? 'info';
        // 根据级别生成不同的目录
        $path = $this->config['path'] . $level . '/';
        // 确保目录存在
        if (!is_dir($path)) {
            mkdir($path, 0755, true);
        }
        // 生成文件名(按日期)
        $filename = date('Y-m-d') . '.log';
        $file = $path . $filename;
        // 格式化日志内容
        $content = sprintf(
            $this->config['format'],
            date('Y-m-d H:i:s'),
            strtoupper($level),
            $record['message'] . PHP_EOL
        );
        // 写入文件
        file_put_contents($file, $content, FILE_APPEND | LOCK_EX);
    }
}

然后在配置中使用:

'channels' => [
    'custom_level' => [
        'type' => 'app\common\log\LevelFileLog',
        'path' => app()->getRuntimePath() . 'log/', // 日志按级别自动分目录
    ],
],

在中间件中自动分类日志

<?php
namespace app\middleware;
use think\facade\Log;
class LogMiddleware
{
    public function handle($request, \Closure $next)
    {
        // 请求前记录
        Log::info('Request: ' . $request->method() . ' ' . $request->url());
        $response = $next($request);
        // 请求后记录(根据状态码判断级别)
        $statusCode = $response->getCode();
        if ($statusCode >= 500) {
            Log::error('Response Error: ' . $statusCode);
        } elseif ($statusCode >= 400) {
            Log::warning('Response Warning: ' . $statusCode);
        } else {
            Log::info('Response Success: ' . $statusCode);
        }
        return $response;
    }
}

日志级别过滤

在控制器中动态调整日志级别:

<?php
namespace app\controller;
use think\facade\Log;
class Index
{
    public function index()
    {
        // 设置当前请求的日志级别
        Log::setLevel(['error', 'info']);
        // 记录日志
        Log::debug('This will not be logged'); // 不会记录
        Log::info('This will be logged');      // 会记录
        Log::error('Error message');           // 会记录
        return 'success';
    }
}

生产环境配置建议

对于生产环境,建议:

// config/log.php
return [
    'default' => 'file',
    // 生产环境只记录重要日志
    'level' => [
        'error',
        'emergency',
        'critical',
        'alert',
        'warning',
    ],
    'channels' => [
        'file' => [
            'type'      => 'File',
            'path'      => app()->getRuntimePath() . 'log/',
            'single'    => false,
            'level'     => ['error', 'warning', 'emergency', 'critical'],
            'max_files' => 30,
            'json'      => false,
        ],
    ],
];

目录结构效果

配置完成后,日志文件会按照以下结构存储:

runtime/
├── log/
│   ├── error/
│   │   ├── 2024-01-15.log
│   │   └── 2024-01-14.log
│   ├── info/
│   │   ├── 2024-01-15.log
│   │   └── 2024-01-14.log
│   ├── sql/
│   │   ├── 2024-01-15.log
│   │   └── 2024-01-14.log
│   └── debug/
│       ├── 2024-01-15.log
│       └── 2024-01-14.log

这样配置后,不同级别的日志会自动分类存储,便于排查问题和监控系统状态。

抱歉,评论功能暂时关闭!