php5.2 日志类,每小时一个文件,超过10MB创建新文件

效果

image

image

 LogHelper.php

<?php
// ===================== LogHelper.php PHP 5.2兼容版本 =====================
/**
 * 日志助手类 - PHP 5.2兼容版本
 * 使用方法: LogHelper::write("日志消息");
 */

// 定义日志级别常量(PHP 5.2不支持类常量数组)
define('LOG_LEVEL_INFO', 'INFO');
define('LOG_LEVEL_WARN', 'WARN');
define('LOG_LEVEL_ERROR', 'ERROR');
define('LOG_LEVEL_DEBUG', 'DEBUG');

class LogHelper {
    
    // 私有属性(PHP 5.2不支持直接属性赋值,需要在构造函数中初始化)
    private static $lastMaintenance = 0;
    private static $maxFileSize = 10485760; // 10MB = 10 * 1024 * 1024
    
    /**
     * 写入日志
     * @param string $message 日志消息
     * @param string $level 日志级别
     * @param string $category 日志分类
     * @return bool 是否写入成功
     */
    public static function write($message, $level = 'INFO', $category = '') {
        // 设置时区
        date_default_timezone_set('asia/chongqing');
        
        // 获取当前时间
        $now = time();
        $currentDate = date('Y-m-d', $now);
        $currentDateTime = date('Y-m-d H:i:s', $now);
        
        // 基础日志目录
        $baseLogDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'logs';
        
        // 构建每日目录路径
        $dailyLogDir = $baseLogDir . DIRECTORY_SEPARATOR . $currentDate;
        
        // 创建目录(如果不存在)
        if (!self::ensureDirectory($dailyLogDir)) {
            error_log("无法创建日志目录: $dailyLogDir");
            return false;
        }
        
        // 构建日志文件名(按小时分组)
        $currentHour = date('Y-m-d H', $now);
        $baseLogFile = $dailyLogDir . DIRECTORY_SEPARATOR . '' . $currentHour . '.log';
        
        // 查找可用的日志文件(处理10MB轮换)
        $logFile = self::findAvailableLogFile($baseLogFile, $dailyLogDir, $currentHour);
        
        // 构建日志内容
        //$logContent = '[' . $currentDateTime . '] [' . str_pad($level, 5) . ']';
        $logContent = '[' . $currentDateTime . '] [' . $level . ']';
        
        if (!empty($category)) {
            $logContent .= ' [' . $category . ']';
        }
        
        $logContent .= ' ' . $message . "\n";
        
        // 写入文件(PHP 5.2的file_put_contents支持有限,使用fopen/fwrite)
        $fp = fopen($logFile, 'a');
        if (!$fp) {
            error_log("无法打开日志文件: $logFile");
            return false;
        }
        
        // 尝试锁定文件
        $locked = false;
        if (function_exists('flock')) {
            $locked = flock($fp, LOCK_EX);
        }
        
        if ($locked || !function_exists('flock')) {
            fwrite($fp, $logContent);
            if ($locked) {
                flock($fp, LOCK_UN);
            }
        }
        
        fclose($fp);
        
        // 自动维护
        self::autoMaintenance($baseLogDir);
        
        return true;
    }
    
    /**
     * 快捷方法:信息日志
     */
    public static function info($message, $category = '') {
        return self::write($message, LOG_LEVEL_INFO, $category);
    }
    
    /**
     * 快捷方法:警告日志
     */
    public static function warn($message, $category = '') {
        return self::write($message, LOG_LEVEL_WARN, $category);
    }
    
    /**
     * 快捷方法:错误日志
     */
    public static function error($message, $category = '') {
        return self::write($message, LOG_LEVEL_ERROR, $category);
    }
    
    /**
     * 快捷方法:调试日志
     */
    public static function debug($message, $category = '') {
        return self::write($message, LOG_LEVEL_DEBUG, $category);
    }
    
    /**
     * 确保目录存在
     */
    private static function ensureDirectory($dir) {
        if (!is_dir($dir)) {
            // PHP 5.2的mkdir需要第三个参数
            return mkdir($dir, 0755, true);
        }
        return true;
    }
    
    /**
     * 查找可用的日志文件(处理10MB大小限制)
     */
    private static function findAvailableLogFile($baseFile, $dailyLogDir, $currentHour) {
        // 尝试基础文件名(无序号)
        if (!file_exists($baseFile)) {
            return $baseFile;
        }
        
        // 检查基础文件大小
        if (filesize($baseFile) < self::$maxFileSize) {
            return $baseFile;
        }
        
        // 基础文件超过10MB,查找带序号的文件
        $filePattern = $dailyLogDir . DIRECTORY_SEPARATOR . 'app_' . $currentHour . '_';
        
        // 查找已有序号文件
        $existingFiles = array();
        if (function_exists('glob')) {
            $existingFiles = glob($filePattern . '*.log');
        } else {
            // PHP 5.2可能没有glob,使用opendir
            if ($handle = opendir($dailyLogDir)) {
                while (false !== ($file = readdir($handle))) {
                    if (preg_match('/^app_' . $currentHour . '_(\d+)\.log$/', $file)) {
                        $existingFiles[] = $dailyLogDir . DIRECTORY_SEPARATOR . $file;
                    }
                }
                closedir($handle);
            }
        }
        
        $maxIndex = 0;
        
        foreach ($existingFiles as $file) {
            if (preg_match('/_(\d+)\.log$/', basename($file), $matches)) {
                $index = intval($matches[1]);
                if ($index > $maxIndex) {
                    $maxIndex = $index;
                }
            }
        }
        
        // 检查最后一个文件的大小
        $lastFile = $filePattern . sprintf('%03d', $maxIndex) . '.log';
        if ($maxIndex > 0 && file_exists($lastFile) && filesize($lastFile) < self::$maxFileSize) {
            return $lastFile;
        }
        
        // 需要创建新文件
        $newIndex = $maxIndex + 1;
        return $filePattern . sprintf('%03d', $newIndex) . '.log';
    }
    
    /**
     * 自动维护(清理旧日志)
     */
    private static function autoMaintenance($baseLogDir) {
        // 每小时最多执行一次维护
        if (time() - self::$lastMaintenance < 3600) {
            return;
        }
        
        self::$lastMaintenance = time();
        
        // 保留30天的目录
        $retentionDays = 30;
        $retentionTime = time() - ($retentionDays * 24 * 60 * 60);
        
        $dateDirs = array();
        if (function_exists('glob')) {
            $dateDirs = glob($baseLogDir . DIRECTORY_SEPARATOR . '20*', GLOB_ONLYDIR);
        } else {
            // 手动扫描目录
            if ($handle = opendir($baseLogDir)) {
                while (false !== ($entry = readdir($handle))) {
                    $path = $baseLogDir . DIRECTORY_SEPARATOR . $entry;
                    if ($entry != '.' && $entry != '..' && is_dir($path) && 
                        preg_match('/^\d{4}-\d{2}-\d{2}$/', $entry)) {
                        $dateDirs[] = $path;
                    }
                }
                closedir($handle);
            }
        }
        
        foreach ($dateDirs as $dir) {
            if (filemtime($dir) < $retentionTime) {
                self::deleteDirectoryRecursive($dir);
            }
        }
    }
    
    /**
     * 递归删除目录
     */
    private static function deleteDirectoryRecursive($dir) {
        if (!is_dir($dir)) {
            return false;
        }
        
        $files = array_diff(scandir($dir), array('.', '..'));
        
        foreach ($files as $file) {
            $path = $dir . DIRECTORY_SEPARATOR . $file;
            if (is_dir($path)) {
                self::deleteDirectoryRecursive($path);
            } else {
                // PHP 5.2确保文件存在再删除
                if (file_exists($path)) {
                    unlink($path);
                }
            }
        }
        
        // 再次检查目录是否为空
        $remainingFiles = array_diff(scandir($dir), array('.', '..'));
        if (empty($remainingFiles)) {
            return rmdir($dir);
        }
        
        return false;
    }
    
    /**
     * 获取日志统计信息
     */
    public static function getStats() {
        $baseLogDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'logs';
        
        if (!is_dir($baseLogDir)) {
            return array('error' => '日志目录不存在');
        }
        
        $stats = array(
            'total_dirs' => 0,
            'total_files' => 0,
            'total_size_mb' => 0,
            'recent_days' => array()
        );
        
        // 获取所有日期目录
        $dateDirs = array();
        if ($handle = opendir($baseLogDir)) {
            while (false !== ($entry = readdir($handle))) {
                $path = $baseLogDir . DIRECTORY_SEPARATOR . $entry;
                if ($entry != '.' && $entry != '..' && is_dir($path) && 
                    preg_match('/^\d{4}-\d{2}-\d{2}$/', $entry)) {
                    $dateDirs[] = $path;
                }
            }
            closedir($handle);
        }
        
        // 按日期排序(手动)
        sort($dateDirs);
        
        // 只显示最近7天
        $recentDirs = array_slice($dateDirs, -7);
        
        foreach ($recentDirs as $dir) {
            $date = basename($dir);
            $files = array();
            
            // 获取目录中的所有.log文件
            if ($handle = opendir($dir)) {
                while (false !== ($entry = readdir($handle))) {
                    if (preg_match('/\.log$/', $entry)) {
                        $files[] = $dir . DIRECTORY_SEPARATOR . $entry;
                    }
                }
                closedir($handle);
            }
            
            $dayStats = array(
                'date' => $date,
                'file_count' => count($files),
                'size_mb' => 0
            );
            
            $daySize = 0;
            foreach ($files as $file) {
                if (file_exists($file)) {
                    $daySize += filesize($file);
                }
            }
            
            $dayStats['size_mb'] = round($daySize / 1024 / 1024, 2);
            $stats['recent_days'][] = $dayStats;
            
            $stats['total_dirs']++;
            $stats['total_files'] += count($files);
            $stats['total_size_mb'] += $dayStats['size_mb'];
        }
        
        $stats['total_size_mb'] = round($stats['total_size_mb'], 2);
        
        return $stats;
    }
    
    /**
     * 运行手动维护
     */
    public static function runMaintenance() {
        $baseLogDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'logs';
        
        if (!is_dir($baseLogDir)) {
            return "日志目录不存在: $baseLogDir";
        }
        
        $retentionDays = 30;
        $retentionTime = time() - ($retentionDays * 24 * 60 * 60);
        $deletedCount = 0;
        
        // 获取所有日期目录
        $dateDirs = array();
        if ($handle = opendir($baseLogDir)) {
            while (false !== ($entry = readdir($handle))) {
                $path = $baseLogDir . DIRECTORY_SEPARATOR . $entry;
                if ($entry != '.' && $entry != '..' && is_dir($path) && 
                    preg_match('/^\d{4}-\d{2}-\d{2}$/', $entry)) {
                    $dateDirs[] = $path;
                }
            }
            closedir($handle);
        }
        
        foreach ($dateDirs as $dir) {
            if (filemtime($dir) < $retentionTime) {
                if (self::deleteDirectoryRecursive($dir)) {
                    $deletedCount++;
                }
            }
        }
        
        return "维护完成,删除了 " . $deletedCount . " 个旧日志目录";
    }
}

// ===================== 兼容旧代码的函数 =====================
/**
 * 兼容旧代码的日志函数
 * 可以逐步替换为 LogHelper::write()
 */
function WriteLog($msg) {
    //return LogHelper::info($msg, 'Legacy');
    return LogHelper::info($msg);
}

?>

使用方法

require_once('Log/LogHelper.php');

//
WriteLog("收到REQUEST=". "  '$UniqueId','$StartTime', '$EndTime', '$BillableSeconds'," ."'$CallerId', '$Called', '$CallType', '$CallFee'");

 

 
// ===================== PHP 5.2兼容的测试代码 =====================
// 只有在命令行直接运行此文件时才执行测试
if (basename(__FILE__) == 'LogHelper.php') {
    // 简单的命令行检测
    if (isset($argv) && is_array($argv) && count($argv) > 1 && $argv[1] == 'test') {
        echo "LogHelper PHP 5.2兼容版本测试\n";
        echo "===============================\n";
        
        // 测试不同级别的日志
        LogHelper::info("系统启动成功 - PHP 5.2测试");
        LogHelper::warn("数据库连接较慢 - PHP 5.2测试");
        LogHelper::error("文件上传失败 - PHP 5.2测试");
        LogHelper::debug("调试信息: user_id=123 - PHP 5.2测试");
        
        // 使用分类
        LogHelper::info("用户登录", "Auth");
        LogHelper::info("计费计算: 0.22元", "Billing");
        
        // 测试旧函数兼容性
        WriteLog("旧代码兼容性测试");
        
        echo "基本日志测试完成\n";
        
        // 查看统计
        $stats = LogHelper::getStats();
        echo "\n日志统计:\n";
        echo "总目录数: " . $stats['total_dirs'] . "\n";
        echo "总文件数: " . $stats['total_files'] . "\n";
        echo "总大小: " . $stats['total_size_mb'] . " MB\n";
        
        if (!empty($stats['recent_days'])) {
            echo "最近7天日志:\n";
            foreach ($stats['recent_days'] as $day) {
                echo "  " . $day['date'] . ": " . $day['file_count'] . " 个文件, " . 
                     $day['size_mb'] . " MB\n";
            }
        }
        
        // 运行维护
        echo "\n运行维护:\n";
        echo LogHelper::runMaintenance() . "\n";
        
        echo "\n测试完成!\n";
    } elseif (isset($argv) && is_array($argv) && count($argv) > 1 && $argv[1] == 'clean') {
        // 清理命令
        echo LogHelper::runMaintenance() . "\n";
    } elseif (isset($argv) && is_array($argv) && count($argv) > 1 && $argv[1] == 'stats') {
        // 统计命令
        $stats = LogHelper::getStats();
        echo "日志统计信息:\n";
        echo "=============\n";
        echo "总目录数: " . $stats['total_dirs'] . "\n";
        echo "总文件数: " . $stats['total_files'] . "\n";
        echo "总大小: " . $stats['total_size_mb'] . " MB\n\n";
        
        if (!empty($stats['recent_days'])) {
            echo "最近7天详细统计:\n";
            foreach ($stats['recent_days'] as $day) {
                echo "  [" . $day['date'] . "] 文件: " . $day['file_count'] . 
                     ", 大小: " . $day['size_mb'] . " MB\n";
            }
        }
    }
}
 

 

posted @ 2025-12-08 16:24  海乐学习  阅读(1)  评论(0)    收藏  举报