怎样在PHP项目中实现日志记录?

wen java案例 3

本文目录导读:

怎样在PHP项目中实现日志记录?

  1. 使用 PHP 原生函数(最简单)
  2. 自定义日志函数(小项目)
  3. 使用 Monolog 库(推荐方案)
  4. 使用框架内置日志
  5. 最佳实践建议
  6. 推荐方案

在PHP项目中实现日志记录,通常有以下几种主流方案,从简单到专业:

使用 PHP 原生函数(最简单)

<?php
// 写入系统日志
error_log("用户登录失败:用户名不存在", 0);
// 写入自定义文件
error_log("错误信息", 3, "/var/log/myapp.log");
?>

优点:零依赖,开箱即用 缺点:功能单一,不支持分级、格式化

自定义日志函数(小项目)

<?php
class Logger {
    private static $logFile;
    public static function init($file = 'app.log') {
        self::$logFile = __DIR__ . '/logs/' . $file;
        if (!file_exists(dirname(self::$logFile))) {
            mkdir(dirname(self::$logFile), 0755, true);
        }
    }
    public static function write($level, $message, $context = []) {
        $timestamp = date('Y-m-d H:i:s');
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
        $caller = $trace[1] ?? null;
        $file = $caller['file'] ?? 'unknown';
        $line = $caller['line'] ?? 0;
        $contextStr = !empty($context) ? ' ' . json_encode($context) : '';
        $logMessage = "[{$timestamp}] [{$level}] [{$file}:{$line}] {$message}{$contextStr}" . PHP_EOL;
        error_log($logMessage, 3, self::$logFile);
    }
    public static function info($message, $context = []) {
        self::write('INFO', $message, $context);
    }
    public static function error($message, $context = []) {
        self::write('ERROR', $message, $context);
    }
    public static function debug($message, $context = []) {
        if (defined('APP_DEBUG') && APP_DEBUG) {
            self::write('DEBUG', $message, $context);
        }
    }
}
// 使用
Logger::init('app.log');
Logger::info('用户登录成功', ['user_id' => 123, 'ip' => '192.168.1.1']);
Logger::error('数据库连接失败', ['db' => 'main', 'error' => 'timeout']);
?>

使用 Monolog 库(推荐方案)

Monolog 是 PHP 最流行的日志库,几乎所有现代框架都在使用。

安装

composer require monolog/monolog

基本使用

<?php
require 'vendor/autoload.php';
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Formatter\LineFormatter;
use Monolog\Processor\IntrospectionProcessor;
use Monolog\Processor\WebProcessor;
// 创建日志频道
$log = new Logger('app');
// 1. 简单文件日志
$log->pushHandler(new StreamHandler(__DIR__.'/logs/app.log', Logger::DEBUG));
// 2. 按天轮转(推荐)
$handler = new RotatingFileHandler(__DIR__.'/logs/app.log', 30, Logger::DEBUG);
$log->pushHandler($handler);
// 3. 自定义格式
$dateFormat = "Y-m-d H:i:s";
$output = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n";
$formatter = new LineFormatter($output, $dateFormat);
$handler->setFormatter($formatter);
// 4. 添加上下文信息
$log->pushProcessor(new IntrospectionProcessor());
$log->pushProcessor(new WebProcessor());
// 使用
$log->info('用户登录', ['user_id' => 123]);
$log->error('数据库错误', ['exception' => $e->getMessage()]);
?>

进阶配置 - 多通道日志

<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SlackWebhookHandler;
use Monolog\Handler\SwiftMailerHandler;
// 创建多通道日志
$logger = new Logger('production');
// INFO 及以上记录到文件
$logger->pushHandler(new StreamHandler(
    __DIR__.'/logs/info.log', 
    Logger::INFO
));
// ERROR 及以上发送到 Slack
$logger->pushHandler(new SlackWebhookHandler(
    'https://hooks.slack.com/services/xxx',
    '#php-errors',
    'PHP Bot',
    true,    // use attachment
    'danger',// icon emoji
    true,    // use short attachment
    false,   // include context
    Logger::ERROR
));
// CRITICAL 发送邮件
$logger->pushHandler(new SwiftMailerHandler(
    $mailer,
    $message,
    Logger::CRITICAL
));
// 使用
$logger->error('支付失败', ['order_id' => 12345]);
$logger->critical('服务器磁盘已满', ['disk_usage' => '99%']);
?>

使用框架内置日志

Laravel

// config/logging.php 配置
'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => ['daily', 'slack'],
    ],
    'daily' => [
        'driver' => 'daily',
        'path' => storage_path('logs/laravel.log'),
        'level' => 'info',
        'days' => 14,
    ],
],
// 使用
use Illuminate\Support\Facades\Log;
Log::info('用户登录', ['user_id' => $id]);
Log::error('数据库查询失败', ['sql' => $query, 'error' => $e->getMessage()]);

ThinkPHP

// config/log.php 配置
return [
    'default' => 'file',
    'channels' => [
        'file' => [
            'type' => 'file',
            'path' => app()->getRuntimePath() . 'logs',
            'level' => ['info', 'error', 'warning'],
            'single' => false,
            'file_size' => 2097152, // 2M
            'max_files' => 30,
        ],
    ],
];
// 使用
use think\facade\Log;
Log::info('用户登录', ['user_id' => $id]);
Log::error('数据库查询失败', ['sql' => $query]);

最佳实践建议

日志级别规范

DEBUG:   调试信息(开发环境)
INFO:    一般信息(用户操作)
NOTICE:  正常但重要的事件
WARNING: 警告(潜在问题)
ERROR:   错误(不影响系统运行)
CRITICAL:严重错误(影响系统运行)
ALERT:   需要立即处理
EMERGENCY:系统不可用

规范

// 好的日志
$log->info('用户登录成功', [
    'user_id' => 123,
    'ip' => '192.168.1.1',
    'user_agent' => 'Chrome/120.0',
    'duration' => 0.15
]);
// 避免这种
$log->info('登录成功'); // 缺少有用信息

环境配置

// 根据环境设置不同级别
if (getenv('APP_ENV') === 'production') {
    $handler->setLevel(Logger::WARNING); // 生产只记录警告及以上
} else {
    $handler->setLevel(Logger::DEBUG); // 开发环境记录所有
}

安全注意事项

  • 不要记录敏感信息:密码、身份证、信用卡号等
  • 日志文件权限:设置为 644,避免直接访问
  • 日志目录隔离:放在 web 根目录之外
  • 定期清理:设置日志保留天数

推荐方案

对于大多数 PHP 项目,推荐:

  1. 小项目:自定义 Logger 类 + 文件日志
  2. 中大型项目:Monolog + 文件 + 错误监控
  3. 框架项目:使用框架提供的日志功能

选择方案时考虑项目规模、维护成本、是否需要远程告警等因素。

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