Passed
Push — master ( f2cf92...5bb09d )
by 世昌
01:42
created

FileLogger::rollLatest()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
c 0
b 0
f 0
nc 5
nop 0
dl 0
loc 12
rs 9.9666
1
<?php
2
namespace nebula\component\debug\log\logger;
3
4
use ZipArchive;
5
use nebula\component\debug\ConfigTrait;
6
use nebula\component\debug\log\LogLevel;
7
use nebula\component\debug\ConfigInterface;
8
use nebula\component\debug\log\AbstractLogger;
9
use nebula\component\debug\log\logger\exception\FileLoggerException;
10
11
class FileLogger extends AbstractLogger implements ConfigInterface
12
{
13
    use ConfigTrait;
14
15
    /**
16
     * 文件
17
     *
18
     * @var resource
19
     */
20
    protected $temp;
21
22
    /**
23
     * 临时文件名
24
     *
25
     * @var string
26
     */
27
    protected $tempname;
28
29
    /**
30
     * 移除文件
31
     *
32
     * @var array
33
     */
34
    protected $removeFiles = [];
35
36
    /**
37
     * 最后的日志
38
     *
39
     * @var string
40
     */
41
    protected $latest;
42
43
    /**
44
     * 构建文件日志
45
     *
46
     * @throws FileLoggerException
47
     * @param array $config
48
     */
49
    public function __construct(array $config=[])
50
    {
51
        $this->applyConfig($config);
52
        $temp = tmpfile();
53
        if ($temp === false) {
54
            $this->tempname = $this->getConfig('save-path').'/log-'. microtime(true).'.tmp';
55
            $temp = fopen($this->tempname, 'w+');
56
        }
57
        if ($temp !== false) {
58
            $this->temp = $temp;
59
        } else {
60
            throw new FileLoggerException(__CLASS__.':'.sprintf('cannot create log file'));
61
        }
62
        $this->latest = $this->getConfig('save-path').'/'.$this->getConfig('file-name');
63
    }
64
65
    public function getDefaultConfig():array
66
    {
67
        return [
68
            'save-path' => './logs',
69
            'save-zip-path' => './logs/zip',
70
            'save-pack-path' => './logs/dump',
71
            'max-file-size' => 2097152,
72
            'file-name' => 'latest.log',
73
            'log-level' => 'debug',
74
            'log-format' => '[%level%] %message%',
75
        ];
76
    }
77
    
78
    protected function packLogFile()
79
    {
80
        $logFile= $this->latest;
81
        $path=preg_replace('/[\\\\]+/', '/', $this->getConfig('save-zip-path') .'/'.date('Y-m-d').'.zip');
82
        $zip = new ZipArchive;
83
        $res = $zip->open($path, ZipArchive::CREATE);
84
        if ($res === true) {
85
            if ($zip->addFile($logFile, date('Y-m-d'). '-'. $zip->numFiles .'.log')) {
86
                array_push($this->removeFiles, $logFile);
87
            }
88
            $it = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getConfig('save-pack-path')));
89
            foreach ($it as $dumpLog) {
90
                if ($zip->addFile($dumpLog, 'pack/'.basename($dumpLog))) {
91
                    array_push($this->removeFiles, $dumpLog);
92
                }
93
            }
94
            $zip->close();
95
        } else {
96
            if (is_file($logFile) && file_exists($logFile)) {
97
                rename($logFile, $this->getConfig('save-path') . '/' . date('Y-m-d'). '-'. substr(md5_file($logFile), 0, 8).'.log');
98
            }
99
        }
100
    }
101
102
    /**
103
     * 检查日志文件大小
104
     *
105
     * @return boolean
106
     */
107
    protected function checkSize():bool
108
    {
109
        $logFile= $this->latest;
110
        if (file_exists($logFile)) {
111
            if (filesize($logFile) > $this->getConfig('max-file-size')) {
112
                return true;
113
            }
114
        }
115
        return false;
116
    }
117
118
119
    public function log($level, string $message, array $context = [])
120
    {
121
        if (LogLevel::compare($level, $this->getConfig('log-level')) >=0) {
122
            $replace = [];
123
            $message = $this->interpolate($message, $context);
124
            $replace['%level%'] = $level;
125
            $replace['%message%'] = $message;
126
            $write = \strtr($this->getConfig('log-format'), $replace);
127
            \fwrite($this->temp, $write.PHP_EOL);
128
        }
129
    }
130
131
    protected function rollLatest()
132
    {
133
        if (isset($this->latest)) {
134
            $size=ftell($this->temp);
135
            fseek($this->temp, 0);
136
            if ($size > 0) {
137
                $body=fread($this->temp, $size);
138
                file_put_contents($this->latest, $body, FILE_APPEND);
139
            }
140
            fclose($this->temp);
141
            if (isset($this->tempname)) {
142
                unlink($this->tempname);
143
            }
144
        }
145
    }
146
147
    protected function removePackFiles()
148
    {
149
        foreach ($this->removeFiles as $file) {
150
            if (\is_file($file) && \file_exists($file)) {
151
                unlink($file);
152
            }
153
        }
154
    }
155
156
    public function save()
157
    {
158
        if ($this->checkSize()) {
159
            $this->packLogFile();
160
        }
161
        $this->rollLatest();
162
        $this->removePackFiles();
163
    }
164
}
165