日志系统

最后更新: 2026-01-27 11:02:47

日志系统

Unicode Framework 提供了灵活的日志系统,支持多通道、自定义格式化器和日志级别。

日志基础

基本使用

use Unicode\Framework\Log\LogManager;
use Unicode\Framework\Config\Config;

$config = Config::getInstance(); $logManager = new LogManager($config);

// 获取默认通道 $logger = $logManager->channel();

// 记录日志 $logger->info('User logged in', ['user_id' => 1]); $logger->error('Database error', ['error' => $e->getMessage()]);

日志级别

$logger->debug('Debug message');
$logger->info('Info message');
$logger->notice('Notice message');
$logger->warning('Warning message');
$logger->error('Error message');
$logger->critical('Critical message');
$logger->alert('Alert message');
$logger->emergency('Emergency message');

日志通道

单文件通道

// 配置
return [
    'log' => [
        'default' => 'single',
        'channels' => [
            'single' => [
                'driver' => 'file',
                'path' => storage_path('logs/app.log'),
            ],
        ],
    ],
];

// 使用 $logger = $logManager->channel('single'); $logger->info('Message');

按日期分割通道

// 配置
return [
    'log' => [
        'default' => 'daily',
        'channels' => [
            'daily' => [
                'driver' => 'daily',
                'path' => storage_path('logs/app.log'),
                'days' => 14,  // 保留14天的日志
            ],
        ],
    ],
];

// 使用 $logger = $logManager->channel('daily'); $logger->info('Message');

多通道配置

// 配置
return [
    'log' => [
        'default' => 'single',
        'channels' => [
            'single' => [
                'driver' => 'file',
                'path' => storage_path('logs/app.log'),
            ],
            'daily' => [
                'driver' => 'daily',
                'path' => storage_path('logs/app.log'),
            ],
            'error' => [
                'driver' => 'file',
                'path' => storage_path('logs/error.log'),
                'level' => 'error',  // 只记录错误级别及以上的日志
            ],
        ],
    ],
];

// 使用不同通道 $appLogger = $logManager->channel('single'); $errorLogger = $logManager->channel('error');

日志级别

设置日志级别

// 配置中设置
return [
    'log' => [
        'channels' => [
            'single' => [
                'driver' => 'file',
                'level' => 'info',  // 只记录 info 及以上级别
            ],
        ],
    ],
];

日志级别说明

  • debug: 详细的调试信息
  • info: 一般信息
  • notice: 正常但重要的事件
  • warning: 警告信息
  • error: 错误信息
  • critical: 严重错误
  • alert: 需要立即处理
  • emergency: 系统不可用
  • 日志格式化

    行格式(默认)

    // 配置
    return [
        'log' => [
            'channels' => [
                'single' => [
                    'driver' => 'file',
                    'formatter' => 'line',
                ],
            ],
        ],
    ];
    

    // 输出格式 // [2024-01-01 12:00:00] app.INFO: User logged in {"user_id":1}

    JSON 格式

    // 配置
    return [
        'log' => [
            'channels' => [
                'single' => [
                    'driver' => 'file',
                    'formatter' => 'json',
                ],
            ],
        ],
    ];
    

    // 输出格式 // {"timestamp":"2024-01-01T12:00:00+00:00","level":"info","message":"User logged in","context":{"user_id":1}}

    自定义格式化器

    namespace App\Log\Formatters;
    

    use Unicode\Framework\Interfaces\LogFormatterInterface; use Unicode\Framework\Log\LogLevel;

    class CustomFormatter implements LogFormatterInterface { public function format(string $level, string $message, array $context = []): string { $timestamp = date('Y-m-d H:i:s'); $contextStr = !empty($context) ? json_encode($context) : ''; return "[{$timestamp}] [{$level}] {$message} {$contextStr}\n"; } }

    // 使用 $logger->setFormatter(new CustomFormatter());

    上下文信息

    添加上下文

    // 基本上下文
    $logger->info('User logged in', [
        'user_id' => 1,
        'ip' => $request->ip(),
    ]);
    

    // 复杂上下文 $logger->error('Payment failed', [ 'user_id' => 1, 'order_id' => 123, 'amount' => 100.00, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]);

    自动添加上下文

    // 在中间件中自动添加请求信息
    class LogContextMiddleware implements MiddlewareInterface
    {
        public function handle(Request $request, callable $next): Response
        {
            $logger = LogManager::getInstance()->channel();
    

    $logger->setContext([ 'request_id' => uniqid(), 'ip' => $request->ip(), 'user_agent' => $request->getHeader('User-Agent'), ]);

    return $next($request); } }

    最佳实践

    1. 日志级别选择

    // ✅ 推荐:根据重要性选择级别
    $logger->debug('SQL query', ['sql' => $sql]);  // 调试信息
    $logger->info('User logged in', ['user_id' => 1]);  // 一般信息
    $logger->warning('Rate limit approaching', ['user_id' => 1]);  // 警告
    $logger->error('Database connection failed', ['error' => $e->getMessage()]);  // 错误
    $logger->critical('Payment system down', []);  // 严重错误
    

    // ❌ 错误:所有日志都使用 info 级别 $logger->info('Debug message'); $logger->info('Error message');

    2. 结构化日志

    // ✅ 推荐:使用结构化数据
    $logger->info('Order created', [
        'order_id' => $order->id,
        'user_id' => $order->user_id,
        'amount' => $order->amount,
        'items' => $order->items->count(),
    ]);
    

    // ❌ 错误:使用字符串拼接 $logger->info("Order created: ID={$order->id}, User={$order->user_id}");

    3. 敏感信息处理

    // ✅ 推荐:不记录敏感信息
    $logger->info('User logged in', [
        'user_id' => $user->id,
        // 不记录密码、token 等敏感信息
    ]);
    

    // ❌ 错误:记录敏感信息 $logger->info('User logged in', [ 'password' => $password, // 安全风险 'token' => $token, ]);

    4. 错误日志记录

    // ✅ 推荐:记录完整的错误信息
    try {
        // 操作
    } catch (\Exception $e) {
        $logger->error('Operation failed', [
            'error' => $e->getMessage(),
            'file' => $e->getFile(),
            'line' => $e->getLine(),
            'trace' => $e->getTraceAsString(),
        ]);
        throw $e;
    }
    

    5. 日志轮转

    // ✅ 推荐:使用按日期分割的日志
    return [
        'log' => [
            'channels' => [
                'daily' => [
                    'driver' => 'daily',
                    'path' => storage_path('logs/app.log'),
                    'days' => 30,  // 保留30天
                ],
            ],
        ],
    ];
    

    6. 不同环境配置

    // 开发环境:详细日志
    if (getenv('APP_ENV') === 'development') {
        $logger->setLevel('debug');
    }
    

    // 生产环境:只记录重要日志 if (getenv('APP_ENV') === 'production') { $logger->setLevel('info'); }

    常见问题

    Q: 如何查看日志文件?

    A: 日志文件默认存储在 storage/logs/ 目录下。

    Q: 如何清理旧日志?

    A: 使用按日期分割的日志通道,自动清理过期日志。

    Q: 如何记录到多个通道?

    A: 创建多个日志记录器实例:

    $appLogger = $logManager->channel('single');
    $errorLogger = $logManager->channel('error');
    

    Q: 如何自定义日志格式?

    A: 实现 LogFormatterInterface 接口,创建自定义格式化器。

    Q: 日志会影响性能吗?

    A: 文件日志对性能影响较小,但在高并发场景下建议使用异步日志。

    相关文档

  • 配置管理 - 日志配置
  • 性能优化 - 日志性能优化