Skip to content

日志系统

DuxLite 提供了强大的日志系统,帮助你记录和监控应用运行状态。

🚀 快速开始

基础使用

php
use Core\App;

// 记录不同级别的日志
App::log()->info('用户登录成功', ['user_id' => 123]);
App::log()->warning('缓存连接失败,使用备用方案');
App::log()->error('数据库连接异常', ['error' => $exception->getMessage()]);
App::log()->debug('调试信息', ['data' => $debugData]);

// 记录异常
try {
    // 业务逻辑
} catch (Exception $e) {
    App::log()->error('操作失败', [
        'exception' => $e->getMessage(),
        'file' => $e->getFile(),
        'line' => $e->getLine(),
        'trace' => $e->getTraceAsString()
    ]);
}

日志级别

DuxLite 支持标准的日志级别:

  • emergency: 系统不可用
  • alert: 必须立即采取行动
  • critical: 严重错误
  • error: 运行时错误
  • warning: 警告信息
  • notice: 正常但重要的信息
  • info: 一般信息
  • debug: 调试信息

📋 日志配置

配置文件

config/use.toml 中配置日志:

toml
[log]
# 日志级别:debug, info, notice, warning, error, critical, alert, emergency
level = "info"

# 日志驱动:file, database, syslog
driver = "file"

# 日志格式:json, line
format = "json"

# 文件日志配置
[log.file]
path = "storage/logs"
filename = "app.log"
max_files = 30
max_size = "10MB"

# 数据库日志配置
[log.database]
table = "logs"
connection = "default"

# 系统日志配置
[log.syslog]
facility = "local0"

🔧 高级用法

上下文信息

php
// 添加上下文信息
App::log()->info('用户操作', [
    'user_id' => $userId,
    'action' => 'create_post',
    'ip' => request()->getClientIp(),
    'user_agent' => request()->getHeader('User-Agent'),
    'timestamp' => time()
]);

// 使用数组记录复杂数据
App::log()->debug('API 请求详情', [
    'method' => 'POST',
    'url' => '/api/users',
    'headers' => $request->getHeaders(),
    'body' => $request->getBody(),
    'response_time' => $responseTime
]);

条件日志

php
// 只在开发环境记录调试日志
if (App::env('APP_DEBUG')) {
    App::log()->debug('SQL 查询', [
        'query' => $sql,
        'bindings' => $bindings,
        'time' => $queryTime
    ]);
}

// 只在生产环境记录性能日志
if (App::env('APP_ENV') === 'production') {
    App::log()->info('性能监控', [
        'memory_usage' => memory_get_usage(true),
        'execution_time' => microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']
    ]);
}

🎯 实际应用示例

用户操作日志

php
<?php

namespace App\System\Service;

use Core\App;

class UserLogService
{
    /**
     * 记录用户登录日志
     */
    public static function logLogin(int $userId, string $ip, bool $success = true): void
    {
        $level = $success ? 'info' : 'warning';
        $message = $success ? '用户登录成功' : '用户登录失败';
        
        App::log()->$level($message, [
            'user_id' => $userId,
            'ip' => $ip,
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
            'timestamp' => date('Y-m-d H:i:s')
        ]);
    }

    /**
     * 记录用户操作日志
     */
    public static function logAction(int $userId, string $action, array $data = []): void
    {
        App::log()->info('用户操作', [
            'user_id' => $userId,
            'action' => $action,
            'data' => $data,
            'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
            'timestamp' => date('Y-m-d H:i:s')
        ]);
    }

    /**
     * 记录权限检查日志
     */
    public static function logPermissionCheck(int $userId, string $permission, bool $granted): void
    {
        $level = $granted ? 'info' : 'warning';
        $message = $granted ? '权限检查通过' : '权限检查失败';
        
        App::log()->$level($message, [
            'user_id' => $userId,
            'permission' => $permission,
            'granted' => $granted,
            'timestamp' => date('Y-m-d H:i:s')
        ]);
    }
}

API 请求日志

php
<?php

namespace App\System\Middleware;

use Core\App;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class ApiLogMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $startTime = microtime(true);
        
        // 记录请求开始
        App::log()->info('API 请求开始', [
            'method' => $request->getMethod(),
            'uri' => (string) $request->getUri(),
            'headers' => $request->getHeaders(),
            'query' => $request->getQueryParams(),
            'ip' => $this->getClientIp($request)
        ]);

        try {
            $response = $handler->handle($request);
            
            // 记录请求成功
            $this->logResponse($request, $response, $startTime);
            
            return $response;
        } catch (\Throwable $e) {
            // 记录请求异常
            App::log()->error('API 请求异常', [
                'method' => $request->getMethod(),
                'uri' => (string) $request->getUri(),
                'exception' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'execution_time' => round((microtime(true) - $startTime) * 1000, 2) . 'ms'
            ]);
            
            throw $e;
        }
    }

    private function logResponse(ServerRequestInterface $request, ResponseInterface $response, float $startTime): void
    {
        $executionTime = round((microtime(true) - $startTime) * 1000, 2);
        
        $level = $response->getStatusCode() >= 400 ? 'warning' : 'info';
        
        App::log()->$level('API 请求完成', [
            'method' => $request->getMethod(),
            'uri' => (string) $request->getUri(),
            'status_code' => $response->getStatusCode(),
            'execution_time' => $executionTime . 'ms',
            'memory_usage' => round(memory_get_usage(true) / 1024 / 1024, 2) . 'MB'
        ]);
    }

    private function getClientIp(ServerRequestInterface $request): string
    {
        $serverParams = $request->getServerParams();
        
        return $serverParams['HTTP_X_FORWARDED_FOR'] 
            ?? $serverParams['HTTP_X_REAL_IP'] 
            ?? $serverParams['REMOTE_ADDR'] 
            ?? 'unknown';
    }
}

数据库操作日志

php
<?php

namespace App\System\Service;

use Core\App;

class DatabaseLogService
{
    /**
     * 记录 SQL 查询日志
     */
    public static function logQuery(string $sql, array $bindings = [], float $time = 0): void
    {
        // 只在调试模式下记录 SQL 日志
        if (!App::env('APP_DEBUG')) {
            return;
        }

        App::log()->debug('SQL 查询', [
            'sql' => $sql,
            'bindings' => $bindings,
            'time' => round($time * 1000, 2) . 'ms'
        ]);
    }

    /**
     * 记录慢查询日志
     */
    public static function logSlowQuery(string $sql, array $bindings = [], float $time = 0): void
    {
        App::log()->warning('慢查询检测', [
            'sql' => $sql,
            'bindings' => $bindings,
            'time' => round($time * 1000, 2) . 'ms',
            'threshold' => '1000ms'
        ]);
    }

    /**
     * 记录数据库连接错误
     */
    public static function logConnectionError(\Throwable $e): void
    {
        App::log()->error('数据库连接失败', [
            'error' => $e->getMessage(),
            'code' => $e->getCode(),
            'file' => $e->getFile(),
            'line' => $e->getLine()
        ]);
    }
}

💡 最佳实践

1. 结构化日志

php
// ✅ 好的做法 - 结构化日志
App::log()->info('订单创建', [
    'order_id' => $orderId,
    'user_id' => $userId,
    'amount' => $amount,
    'status' => 'pending',
    'created_at' => date('Y-m-d H:i:s')
]);

// ❌ 避免 - 非结构化日志
App::log()->info("用户 {$userId} 创建了订单 {$orderId},金额 {$amount}");

2. 敏感信息处理

php
// 过滤敏感信息
$userData = [
    'username' => $user->username,
    'email' => $user->email,
    'password' => '[FILTERED]',
    'credit_card' => '[FILTERED]'
];

App::log()->info('用户注册', $userData);

3. 日志分类

php
// 按功能模块分类记录日志
class OrderLogService
{
    public static function logOrderCreated(int $orderId, array $data): void
    {
        App::log()->info('[ORDER] 订单创建', [
            'module' => 'order',
            'action' => 'create',
            'order_id' => $orderId,
            'data' => $data
        ]);
    }

    public static function logPaymentProcessed(int $orderId, string $paymentId): void
    {
        App::log()->info('[PAYMENT] 支付处理', [
            'module' => 'payment',
            'action' => 'process',
            'order_id' => $orderId,
            'payment_id' => $paymentId
        ]);
    }
}

4. 性能监控

php
class PerformanceLogger
{
    private static array $timers = [];

    public static function start(string $name): void
    {
        self::$timers[$name] = microtime(true);
    }

    public static function end(string $name, array $context = []): void
    {
        if (!isset(self::$timers[$name])) {
            return;
        }

        $duration = microtime(true) - self::$timers[$name];
        unset(self::$timers[$name]);

        App::log()->info('性能监控', array_merge([
            'operation' => $name,
            'duration' => round($duration * 1000, 2) . 'ms',
            'memory_usage' => round(memory_get_usage(true) / 1024 / 1024, 2) . 'MB'
        ], $context));
    }
}

// 使用示例
PerformanceLogger::start('user_query');
$users = User::all();
PerformanceLogger::end('user_query', ['count' => $users->count()]);

🎉 总结

DuxLite 日志系统的特点:

  • 🚀 简单易用:统一的日志接口,易于使用
  • 🔧 多驱动支持:支持文件、数据库等多种存储方式
  • ⚡ 高性能:异步写入,不影响应用性能
  • 🛡️ 结构化:支持结构化日志,便于分析
  • 📊 监控友好:便于集成监控和告警系统

合理使用日志系统可以帮助你更好地监控和调试应用!