FileLogger.php 6.43 KB
<?php

namespace common\components\dlog;

use Yii;
use yii\helpers\FileHelper;
use yii\base\Component;
use yii\log\Logger;
use function array_key_exists;
use function debug_backtrace;
use function date;
use function is_dir;
use function opendir;
use function readdir;
use function strtotime;
use function round;
use function unlink;
use function closedir;
use function is_file;
use function clearstatcache;
use function filesize;
use function strtoupper;

/**
 * Class FileLogger
 * @package common\components\dlogs
 */
class FileLogger extends Component
{
    private $dirname = 'dlogs';
    /** @var LogFileHandler **/
    private $handler;
    private $level = 15;
    public $dirMode = 0755;
    /**
     * 一个文件最大容量 10M
     * @var int
     */
    public $maxFileSize = 10240; // in  KB
    /**
     * 最大文件数目 100
     * @var int
     */
    public $maxLogFiles = 10;
    /**
     * @var
     */
    public $logFile;
    /**
     * @param int $level
     * @return Log|null
     */
    public function __construct($level = 15)
    {
        // 异常处理
        if ($this->maxLogFiles < 1) {
            $this->maxLogFiles = 1;
        }
        if ($this->maxFileSize < 1) {
            $this->maxFileSize = 1;
        }

        /**
         * 获取当前logFile
         */
        $logFile = $this->getLogFile();

        $handler = new FileHandler($logFile);

        $this->__setHandle($handler);
        $this->__setLevel($level);
    }

    /**
     * @param $handler
     */
    private function __setHandle($handler){
        $this->handler = $handler;
    }

    /**
     * @param $level
     */
    private function __setLevel($level)
    {
        $this->level = $level;
    }

    /**
     * @param $msg
     */
    public function debug($msg)
    {
        $this->write(1, $msg);
    }

    /**
     * @param $msg
     */
    public function warn($msg)
    {
        $this->write(4, $msg);
    }

    /**
     * @param $msg
     */
    public function error($msg)
    {
        $debugInfo = debug_backtrace();
        $stack = "[";
        foreach ($debugInfo as $key => $val) {
            if (array_key_exists("file", $val)) {
                $stack .= ",file:" . $val["file"];
            }
            if(array_key_exists("line", $val)) {
                $stack .= ",line:" . $val["line"];
            }
            if (array_key_exists("function", $val)) {
                $stack .= ",function:" . $val["function"];
            }
        }
        $stack .= "]";
        $this->write(8, $stack . $msg);
    }

    /**
     * @param $msg
     */
    public function info($msg)
    {
        $this->write(2, $msg);
    }

    /**
     * @param $level
     * @return string
     */
    private function getLevelStr($level)
    {
        switch ($level)
        {
            case 1:
                return 'debug';
                break;
            case 2:
                return 'info';
                break;
            case 4:
                return 'warn';
                break;
            case 8:
                return 'error';
                break;
            default:

        }
    }

    /**
     * @param $level
     * @param $msg
     */
    protected function write($level, $msg)
    {
        if(($level & $this->level) == $level ) {
            $msg = '[' . date('Y-m-d H:i:s') . '][' . $this->getLevelStr($level) . '] ' . $msg . "\n";
            $this->handler->write($msg);
        }
    }
    /**
     * 删除目录下N天前所有文件
     * by http://www.jbxue.com
     */
    protected function delFile($dir,$n) //删除DIR路径下N天前创建的所有文件;
    {
        if (is_dir($dir)) {
            if ($dh = opendir($dir)) {
                while (false !== ($file = readdir($dh))) {
                    if ($file != "." && $file != "..") {
                        $fullpath = $dir . "/" . $file;
                        if (!is_dir($fullpath)) {
                            $filedate = date("Y-m-d", filemtime($fullpath));
                            $d1 = strtotime(date("Y-m-d"));
                            $d2 = strtotime($filedate);
                            $Days = round(($d1 - $d2) / 3600 / 24);

                            if ($Days > $n) {
                                unlink($fullpath);
                            }
                        }
                    }
                }
            }
            closedir($dh);
        }
    }

    /**
     * @return bool|string
     * @throws \yii\base\Exception
     */
    protected function getLogFile()
    {
        if (null !== $this->logFile) {
            return  $this->logFile;
        }

        // 文件命名规律 *logs/20160802_*.log
        // runtime app 位置
        $dlogs = Yii::$app->getRuntimePath() . '/' . $this->dirname;
        if (false == is_dir($dlogs)) {
            FileHelper::createDirectory($dlogs, $this->dirMode, true);
        }

        // 删除N天前的数据
        //self::delFile($dlogs,7);

        //*logs/201603/03/18
        $logFile = $dlogs . '/' . date('Ymd');

        // 先找数值最大的
        for ($i = $this->maxLogFiles; $i >= 0; --$i) {
            //*logs/201601/03/18_9.log
            $file = $logFile.'_'.$i.'.log';

            // 如果log文件已经存在
            if (is_file($file)) {
                // 删除多出来的文件
                if ($i === $this->maxLogFiles) {
                    @unlink($file);
                } else {
                    // 清楚文件计算缓存
                    clearstatcache();

                    // 如果当前文件大于 最大限制,而且已经是第大文件数,就到系统错误 log中
                    if (@filesize($file) > $this->maxFileSize * 1024) {
                        if ($i === $this->maxLogFiles - 1) {
                            Yii::getLogger()->log(strtoupper($this->dirname) . "文件溢出,已经超出最大文件数:" . $this->maxLogFiles . ", 每个文件最大:" . $this->maxFileSize . "K", Logger::LEVEL_ERROR);
                        } else {
                            return $this->logFile = $logFile . '_' . ($i + 1) . '.log';
                        }
                    } else {
                        // 如果文件存在,又没有超过最大文件限制
                        return $this->logFile = $file;
                    }
                }
            } else {
                if ($i === 0) {
                    return $this->logFile = $file;
                }
            }
        }

        return $this->logFile;
    }
}