PHP日志类(支持按时间、大小分隔日志文件和保存指定数量的日志文件)

日志对象

<?php

/**
 * 日志类,支持按时间和文件大小分割文件,支持保存指定数量的日志文件
 *
 * @author zengriri
 * @date 2020-03-31
 */
class Logger {

    private $FileName, $When, $Size, $BackupCount;
    private $SuffixFormat = [
        'H' => 'Y-m-d_H',
        'D' => 'Y-m-d',
        'W' => 'Y-m-d',
        'M' => 'Y-m'
    ];

    /**
     * 获取日志类对象
     * @param string $fileName 日志文件名,可以带路径,不存在的目录将被创建
     * @return object
     */
    public static function getLogger($fileName) {
        return new Logger($fileName);
    }

    /**
     * 获取按时间分割的日志类对象
     * @param string $fileName 日志文件名,可以带路径,不存在的目录将被创建
     * @param string $when 分割的时间单位 H 每小时, D 每天, W 每周, M 每月
     * @param integer $backupCount 文件备份数量,默认全部,超出将会删除旧的文件
     * @return object
     */
    public static function getTimedRotatingLogger($fileName, $when = 'D', $backupCount = 0) {
        $logger = new Logger($fileName);
        $logger->setTimedRotating($when, abs( intval($backupCount) ) );
        return $logger;
    }

    /**
     * 获取按文件大小分割的日志类对象
     * @param string $fileName 日志文件名,可以带路径,不存在的目录将被创建
     * @param integer $size 分割的文件大小,单位(kb)
     * @param integer $backupCount 文件备份数量,默认全部,超出将会删除旧的文件
     * @return object
     */
    public static function getSizedRotatingLogger($fileName, $size = 1024, $backupCount = 0) {
        $logger = new Logger($fileName);
        $logger->setSizedRotating( abs( intval($size) ), abs( intval($backupCount) ) );
        return $logger;
    }

    private function setTimedRotating($when, $backupCount) {
        $this->When = $when;
        $this->BackupCount = $backupCount;
    }

    private function setSizedRotating($size, $backupCount) {
        $this->Size = $size;
        $this->BackupCount = $backupCount;
    }

    /**
     * 初始化配置
     * @param string $fileName 日志文件名
     */
    public function __construct($fileName) {
        $this->FileName = $fileName;
    }

    /**
     * 写入信息日志
     * @param  String $msg 日志消息
     * @return Boolean
     */
    public function info($msg){
        return $this->write('INFO', $msg);
    }

    /**
     * 写入警告日志
     * @param  String  $msg 日志消息
     * @return Boolean
     */
    public function warn($msg){
        return $this->write('WARN', $msg);
    }

    /**
     * 写入警告日志
     * @param  String  $msg 日志消息
     * @return Boolean
     */
    public function debug($msg){
        return $this->write('DEBUG', $msg);
    }

    /**
     * 写入错误日志
     * @param  String  $msg 日志消息
     * @return Boolean
     */
    public function error($msg){
        return $this->write('ERROR', $msg);
    }

    /**
     * 写入日志
     * @param  String  $type 日志类型
     * @param  String  $msg 日志消息
     * @return Boolean
     */
    private function write($type, $msg){
        $fileName = $this->FileName;
        // 设置日志文件名
        $this->When && $fileName = $this->getTimedFileName();
        $this->Size && $fileName = $this->getSizedFileName();
        // 清理备份日志
        $this->BackupCount && $this->clearLogFile();
        // 创建日志目录
        $isCreate = $this->createLogPath();
        // 日志内容
        $msg = sprintf('[%s] %-5s %s : %s'.PHP_EOL, date('Y-m-d H:i:s'), $type, get_current_user(), $msg);
        // 写入日志文件
        if($isCreate){
            return file_put_contents($fileName, $msg, FILE_APPEND);
        }
        return false;
    }

    /**
     * 清理超出备份数量的旧日志文件
     * @return boolean 清理结果
     */
    private function clearLogFile() { 
        $files = $this->getAsortFileByTime();
        $fileCnt = count($files);
        if ($fileCnt <= $this->BackupCount) {
            return true;
        }
        $cnt = 0;
        $result = true;
        foreach ($files as $file) {
            $result &= unlink($file['name']);
            if ( ++$cnt == $fileCnt - $this->BackupCount ) {
                break;
            }
        }
        return $result;
    }

    /**
     * 获取根据修改时间升序排序的文件
     * @return array
     */
    private function getAsortFileByTime() {
        $name = explode('.', basename($this->FileName))[0];
        $fold = dirname($this->FileName);
        $result = glob("$fold/$name*");
        $files = [];
        foreach ($result as $i => $file) {
            $files[$i]['name'] = $file;
            $files[$i]['time'] = filemtime($file);
        }
        uasort($files, function ($f1, $f2){
            return $f1['time'] - $f2['time'];
        });
        return $files;
    }

    /**
     * 获取按时间分割的文件名
     * @return string
     */
    private function getTimedFileName() {
        $name = basename($this->FileName);
        $pos = strrpos($name, '.');
        !isset($this->SuffixFormat[$this->When]) && $this->When = 'D';
        $suffix = date($this->SuffixFormat[$this->When]);
        $files = $this->getAsortFileByTime();
        $lastFile = end($files);
        $newFileName = dirname($this->FileName) . '/' . ($pos ? substr($name, 0, $pos) . $suffix . substr($name, $pos) : $name . $suffix);
        return $this->When == 'W' && $lastFile && time() - $lastFile['time'] > 7 * 24 * 3600 || $this->When != 'W' ? $newFileName : $lastFile['name'];
    }

    /**
     * 获取按文件大小分割的文件名
     * @return string
     */
    private function getSizedFileName() {
        $files = $this->getAsortFileByTime();
        $lastFile = end($files);
        $fileName = $this->FileName;
        if ($lastFile && filesize($lastFile['name']) > 1024 * $this->Size) {
            $this->When = 'S';
            $this->SuffixFormat['S'] = 'Y-m-d_H-i-s';
            $fileName = $this->getTimedFileName();
        } else if ($lastFile) {
            $fileName = $lastFile['name'];
        }
        return $fileName;
    }

    /**
     * 创建日志目录
     * @return Boolean
     */
    private function createLogPath(){
        $path = dirname($this->FileName);
        if(!is_dir($path)){
            return mkdir($path, 0777, true);
        }
        return true;
    }

}
?>

获取日志对象

$fileName = 'logging/test.log';
$logger = Logger::getLogger($fileName); // 普通日志
$sizedLogger = Logger::getSizedRotatingLogger($fileName, 5, 3); // 按文件大小分割的日志,超过5KB分割,保留最新的三个日志文件
$timedLogger = Logger::getTimedRotatingLogger($fileName, 'H'); // 按时间分割的日志,按小时分割,保留所有日志

普通日志测试

// 普通日志测试
for ($i = 0;$i < 10;$i++) {
    $logger->info('test info');
    $logger->warn('test warn');
    $logger->error('test error');
    $logger->debug('test debug');
}

普通日志

按文件大小分割的日志测试

// 按文件大小分割的日志测试
for ($i = 0;$i < 600;$i++) {
    $sizedLogger->info('test info');
    $i % 100 == 0 && sleep(1);
}

按文件大小分割的日志

按时间分割的日志测试

// 按时间分割的日志测试
for ($i = 0;$i < 100;$i++) {
    $timedLogger->info('test info');
}

按时间分割的日志

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值