PHP项目自定义日志类如何封装编写

wen PHP项目 22

本文目录导读:

PHP项目自定义日志类如何封装编写

  1. 基础日志类实现
  2. 增强版日志类(支持更多功能)
  3. 使用示例
  4. 特点说明

我来提供一个完整的PHP自定义日志类封装方案:

基础日志类实现

<?php
/**
 * 自定义日志类
 */
class Logger {
    // 日志级别
    const DEBUG = 'DEBUG';
    const INFO = 'INFO';
    const WARNING = 'WARNING';
    const ERROR = 'ERROR';
    const CRITICAL = 'CRITICAL';
    private static $instance = null;
    private $logDir = '';
    private $logLevel = self::DEBUG;
    private $dateFormat = 'Y-m-d H:i:s';
    private $filePrefix = 'app';
    private $maxFileSize = 10485760; // 10MB
    private $backupCount = 5;
    /**
     * 私有构造函数
     */
    private function __construct($config = []) {
        if (!empty($config)) {
            $this->initialize($config);
        }
    }
    /**
     * 获取单例实例
     */
    public static function getInstance($config = []) {
        if (self::$instance === null) {
            self::$instance = new self($config);
        }
        return self::$instance;
    }
    /**
     * 初始化配置
     */
    public function initialize($config) {
        if (isset($config['log_dir'])) {
            $this->logDir = rtrim($config['log_dir'], '/') . '/';
        } else {
            $this->logDir = dirname(__FILE__) . '/../logs/';
        }
        if (isset($config['log_level'])) {
            $this->logLevel = strtoupper($config['log_level']);
        }
        if (isset($config['date_format'])) {
            $this->dateFormat = $config['date_format'];
        }
        if (isset($config['file_prefix'])) {
            $this->filePrefix = $config['file_prefix'];
        }
        if (isset($config['max_file_size'])) {
            $this->maxFileSize = (int)$config['max_file_size'];
        }
        if (isset($config['backup_count'])) {
            $this->backupCount = (int)$config['backup_count'];
        }
        // 创建日志目录
        $this->createLogDirectory();
    }
    /**
     * 创建日志目录
     */
    private function createLogDirectory() {
        if (!is_dir($this->logDir)) {
            @mkdir($this->logDir, 0777, true);
        }
        // 按日期创建子目录
        $dateDir = $this->logDir . date('Ymd') . '/';
        if (!is_dir($dateDir)) {
            @mkdir($dateDir, 0777, true);
        }
    }
    /**
     * 记录调试日志
     */
    public function debug($message, $context = []) {
        $this->log(self::DEBUG, $message, $context);
    }
    /**
     * 记录信息日志
     */
    public function info($message, $context = []) {
        $this->log(self::INFO, $message, $context);
    }
    /**
     * 记录警告日志
     */
    public function warning($message, $context = []) {
        $this->log(self::WARNING, $message, $context);
    }
    /**
     * 记录错误日志
     */
    public function error($message, $context = []) {
        $this->log(self::ERROR, $message, $context);
    }
    /**
     * 记录关键错误日志
     */
    public function critical($message, $context = []) {
        $this->log(self::CRITICAL, $message, $context);
    }
    /**
     * 核心日志记录方法
     */
    public function log($level, $message, $context = []) {
        // 检查日志级别
        if (!$this->isLevelAllowed($level)) {
            return;
        }
        // 格式化消息
        $formattedMessage = $this->formatMessage($level, $message, $context);
        // 写入日志
        $this->writeToFile($level, $formattedMessage);
    }
    /**
     * 检查日志级别是否允许
     */
    private function isLevelAllowed($level) {
        $levels = [
            self::DEBUG => 0,
            self::INFO => 1,
            self::WARNING => 2,
            self::ERROR => 3,
            self::CRITICAL => 4
        ];
        return $levels[$level] >= $levels[$this->logLevel];
    }
    /**
     * 格式化日志消息
     */
    private function formatMessage($level, $message, $context = []) {
        $timestamp = date($this->dateFormat);
        if (!empty($context)) {
            $message = $this->interpolate($message, $context);
        }
        // 获取调用信息
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
        $caller = isset($trace[2]) ? $trace[2] : [];
        $file = isset($caller['file']) ? basename($caller['file']) : 'unknown';
        $line = isset($caller['line']) ? $caller['line'] : 'unknown';
        return sprintf(
            "[%s] [%s] [%s:%d] %s",
            $timestamp,
            $level,
            $file,
            $line,
            $message
        );
    }
    /**
     * 替换消息中的占位符
     */
    private function interpolate($message, $context = []) {
        $replace = [];
        foreach ($context as $key => $val) {
            if (is_string($val) || method_exists($val, '__toString')) {
                $replace['{' . $key . '}'] = $val;
            }
        }
        return strtr($message, $replace);
    }
    /**
     * 写入日志文件
     */
    private function writeToFile($level, $message) {
        $filename = $this->getLogFilename($level);
        $this->rotateLogFile($filename);
        $result = @file_put_contents(
            $filename,
            $message . PHP_EOL,
            FILE_APPEND | LOCK_EX
        );
        if ($result === false) {
            error_log("Failed to write to log file: {$filename}");
        }
    }
    /**
     * 获取日志文件名
     */
    private function getLogFilename($level) {
        $dateDir = $this->logDir . date('Ymd') . '/';
        $levelLower = strtolower($level);
        return $dateDir . "{$this->filePrefix}_{$levelLower}.log";
    }
    /**
     * 日志文件轮转
     */
    private function rotateLogFile($filename) {
        if (!file_exists($filename)) {
            return;
        }
        if (filesize($filename) < $this->maxFileSize) {
            return;
        }
        // 删除最旧的备份
        $oldestBackup = $filename . '.' . $this->backupCount;
        if (file_exists($oldestBackup)) {
            @unlink($oldestBackup);
        }
        // 轮转备份文件
        for ($i = $this->backupCount - 1; $i >= 1; $i--) {
            $backup = $filename . '.' . $i;
            if (file_exists($backup)) {
                rename($backup, $filename . '.' . ($i + 1));
            }
        }
        // 重命名当前文件
        rename($filename, $filename . '.1');
    }
    /**
     * 防止克隆
     */
    private function __clone() {}
    /**
     * 防止反序列化
     */
    private function __wakeup() {}
}

增强版日志类(支持更多功能)

<?php
/**
 * 增强版日志类
 */
class AdvancedLogger {
    private static $instance = null;
    private $config = [];
    private $buffer = [];
    // 日志级别定义
    const LEVELS = [
        'DEBUG' => 100,
        'INFO' => 200,
        'NOTICE' => 250,
        'WARNING' => 300,
        'ERROR' => 400,
        'CRITICAL' => 500,
        'ALERT' => 550,
        'EMERGENCY' => 600
    ];
    private function __construct($config = []) {
        $this->config = array_merge([
            'log_dir' => dirname(__FILE__) . '/../logs/',
            'log_level' => 'DEBUG',
            'date_format' => 'Y-m-d H:i:s',
            'file_prefix' => 'app',
            'max_file_size' => 10485760,
            'backup_count' => 5,
            'enable_buffer' => false,
            'buffer_size' => 100,
            'enable_email' => false,
            'email_recipients' => [],
            'email_level' => 'ERROR',
            'enable_console' => false,
            'format' => 'json', // json or text
        ], $config);
        $this->init();
    }
    public static function getInstance($config = []) {
        if (self::$instance === null) {
            self::$instance = new self($config);
        }
        return self::$instance;
    }
    private function init() {
        $this->createDirectory();
        $this->registerShutdownHandler();
    }
    /**
     * 注册关闭处理器
     */
    private function registerShutdownHandler() {
        register_shutdown_function(function() {
            $this->flushBuffer();
        });
    }
    /**
     * 记录日志
     */
    public function log($level, $message, $context = []) {
        if (!$this->isLevelAllowed($level)) {
            return;
        }
        $record = $this->createRecord($level, $message, $context);
        if ($this->config['enable_buffer']) {
            $this->buffer[] = $record;
            if (count($this->buffer) >= $this->config['buffer_size']) {
                $this->flushBuffer();
            }
        } else {
            $this->writeRecord($record);
        }
    }
    /**
     * 创建日志记录
     */
    private function createRecord($level, $message, $context = []) {
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
        $caller = isset($trace[2]) ? $trace[2] : [];
        $record = [
            'timestamp' => date($this->config['date_format']),
            'level' => $level,
            'message' => $this->interpolate($message, $context),
            'file' => isset($caller['file']) ? $caller['file'] : 'unknown',
            'line' => isset($caller['line']) ? $caller['line'] : 'unknown',
            'context' => $context,
            'extra' => $this->getExtraData()
        ];
        return $record;
    }
    /**
     * 获取额外数据
     */
    private function getExtraData() {
        return [
            'ip' => $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1',
            'uri' => $_SERVER['REQUEST_URI'] ?? 'cli',
            'method' => $_SERVER['REQUEST_METHOD'] ?? 'UNKNOWN',
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
            'memory_usage' => memory_get_usage(true),
            'memory_peak' => memory_get_peak_usage(true),
            'execution_time' => defined('START_TIME') ? microtime(true) - START_TIME : 0
        ];
    }
    /**
     * 写入日志记录
     */
    private function writeRecord($record) {
        $formatted = $this->formatRecord($record);
        $filename = $this->getLogFilename($record['level']);
        $this->rotateLogFile($filename);
        $this->writeToFile($filename, $formatted);
        // 发送邮件告警
        if ($this->config['enable_email'] && 
            $this->isLevelReached($record['level'], $this->config['email_level'])) {
            $this->sendEmailAlert($record);
        }
        // 控制台输出
        if ($this->config['enable_console'] && PHP_SAPI === 'cli') {
            $this->writeToConsole($formatted);
        }
    }
    /**
     * 格式化日志记录
     */
    private function formatRecord($record) {
        if ($this->config['format'] === 'json') {
            return json_encode($record, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        } else {
            return sprintf(
                "[%s] [%s] [%s:%d] %s",
                $record['timestamp'],
                $record['level'],
                basename($record['file']),
                $record['line'],
                $record['message']
            );
        }
    }
    /**
     * 写入文件
     */
    private function writeToFile($filename, $content) {
        $result = @file_put_contents(
            $filename,
            $content . PHP_EOL,
            FILE_APPEND | LOCK_EX
        );
        if ($result === false) {
            // 写入失败时使用系统日志
            error_log("Logger: Failed to write log to {$filename}: {$content}");
        }
    }
    /**
     * 写入控制台
     */
    private function writeToConsole($content) {
        $colors = [
            'DEBUG' => "\033[36m",   // Cyan
            'INFO' => "\033[32m",    // Green
            'NOTICE' => "\033[34m",  // Blue
            'WARNING' => "\033[33m", // Yellow
            'ERROR' => "\033[31m",   // Red
            'CRITICAL' => "\033[41m",// Red background
            'ALERT' => "\033[45m",   // Purple background
            'EMERGENCY' => "\033[41m"// Red background
        ];
        $level = json_decode($content, true)['level'] ?? 'INFO';
        $color = $colors[$level] ?? "\033[0m";
        $reset = "\033[0m";
        echo $color . $content . $reset . PHP_EOL;
    }
    /**
     * 刷新缓冲区
     */
    public function flushBuffer() {
        if (empty($this->buffer)) {
            return;
        }
        $records = $this->buffer;
        $this->buffer = [];
        // 按级别分组写入
        $grouped = [];
        foreach ($records as $record) {
            $grouped[$record['level']][] = $record;
        }
        foreach ($grouped as $level => $records) {
            $filename = $this->getLogFilename($level);
            $this->rotateLogFile($filename);
            $content = '';
            foreach ($records as $record) {
                $content .= $this->formatRecord($record) . PHP_EOL;
            }
            $this->writeToFile($filename, $content);
        }
    }
    /**
     * 发送邮件告警
     */
    private function sendEmailAlert($record) {
        if (empty($this->config['email_recipients'])) {
            return;
        }
        $subject = sprintf(
            '[%s] Log Alert: %s',
            $record['level'],
            substr($record['message'], 0, 100)
        );
        $body = print_r($record, true);
        foreach ($this->config['email_recipients'] as $recipient) {
            @mail($recipient, $subject, $body);
        }
    }
    /**
     * 检查日志级别是否允许
     */
    private function isLevelAllowed($level) {
        return self::LEVELS[$level] >= self::LEVELS[$this->config['log_level']];
    }
    /**
     * 检查是否达到指定级别
     */
    private function isLevelReached($current, $target) {
        return self::LEVELS[$current] >= self::LEVELS[$target];
    }
    // ... 其他辅助方法与基础版本相同
    private function __clone() {}
    private function __wakeup() {}
}

使用示例

<?php
// 配置文件
$config = [
    'log_dir' => '/path/to/logs',
    'log_level' => 'DEBUG',
    'file_prefix' => 'myapp',
    'max_file_size' => 5242880, // 5MB
    'backup_count' => 3,
    'enable_buffer' => true,
    'buffer_size' => 50,
    'format' => 'json',
    'enable_email' => true,
    'email_recipients' => ['admin@example.com'],
    'email_level' => 'ERROR',
    'enable_console' => true
];
// 获取日志实例
$logger = Logger::getInstance($config);
// 基本使用
$logger->info('User logged in', ['user_id' => 123, 'username' => 'john']);
$logger->error('Database connection failed', ['error_code' => 1045]);
$logger->debug('Memory usage: {memory}', ['memory' => memory_get_usage()]);
// 使用高级版本
$advLogger = AdvancedLogger::getInstance($config);
// 批量记录
$advLogger->log('INFO', 'API Request', [
    'endpoint' => '/users',
    'method' => 'GET',
    'params' => $_GET
]);
// 异常记录
try {
    // 一些代码
    throw new Exception('Something went wrong');
} catch (Exception $e) {
    $logger->critical($e->getMessage(), [
        'file' => $e->getFile(),
        'line' => $e->getLine(),
        'trace' => $e->getTraceAsString()
    ]);
}
// 性能监控
$logger->info('Page load completed', [
    'execution_time' => (microtime(true) - START_TIME),
    'memory_usage' => memory_get_usage()
]);

特点说明

  1. 单例模式:确保全局只有一个日志实例
  2. 多级别支持:DEBUG到CRITICAL多个级别
  3. 自动轮转:当文件超过指定大小时自动分割
  4. 日期目录:按日期创建子目录,便于管理
  5. 缓冲机制:支持批量写入,提高性能
  6. 上下文信息:自动记录调用位置、IP、URI等
  7. 多种输出:支持文件、控制台、邮件
  8. 格式化灵活:支持JSON和文本格式

这个日志类封装了企业级应用所需的大部分功能,你可以根据实际需求进行扩展和调整。

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