1 | <?php |
||
2 | |||
3 | namespace WebStream\Log; |
||
4 | |||
5 | use WebStream\Container\Container; |
||
6 | use WebStream\Exception\Extend\LoggerException; |
||
7 | use WebStream\IO\File; |
||
8 | use WebStream\IO\Writer\SimpleFileWriter; |
||
9 | |||
10 | /** |
||
11 | * LoggerConfigurationManager |
||
12 | * @author Ryuichi Tanaka |
||
13 | * @since 2016/01/29 |
||
14 | * @version 0.7 |
||
15 | */ |
||
16 | class LoggerConfigurationManager |
||
17 | { |
||
18 | use LoggerUtils; |
||
19 | |||
20 | /** |
||
21 | * @var Container ログ設定コンテナ |
||
22 | */ |
||
23 | private Container $logContainer; |
||
24 | |||
25 | /** |
||
26 | * @var Container IOコンテナ |
||
27 | */ |
||
28 | private Container $ioContainer; |
||
29 | |||
30 | /** |
||
31 | * @var array<string> ログ設定情報 |
||
32 | */ |
||
33 | private $configMap; |
||
34 | |||
35 | /** |
||
36 | * Constructor |
||
37 | 141 | * @param mixed $config ログ設定 |
|
38 | * @throws LoggerException |
||
39 | 141 | */ |
|
40 | public function __construct($config) |
||
41 | { |
||
42 | 141 | if (is_array($config)) { |
|
43 | 141 | $configMap = $config; |
|
44 | } else { |
||
45 | $configMap = parse_ini_file($config); |
||
46 | if ($configMap === null) { |
||
47 | throw new LoggerException("Log config file does not exist: " . $config); |
||
48 | 141 | } |
|
49 | 141 | } |
|
50 | |||
51 | 141 | $this->logContainer = new Container(false); |
|
52 | 141 | $this->ioContainer = new Container(); |
|
53 | |||
54 | $this->ioContainer->file = function () use ($configMap) { |
||
55 | 141 | if (!array_key_exists("path", $configMap)) { |
|
56 | throw new LoggerException("Log path must be defined."); |
||
57 | 9 | } |
|
58 | 9 | return new File($configMap["path"]); |
|
59 | }; |
||
60 | $this->ioContainer->fileWriter = function () use ($configMap) { |
||
61 | 141 | return new SimpleFileWriter($configMap["path"]); |
|
62 | 141 | }; |
|
63 | |||
64 | $this->configMap = $configMap; |
||
65 | } |
||
66 | |||
67 | /** |
||
68 | 141 | * 設定を読み込む |
|
69 | * @throws LoggerException |
||
70 | 141 | */ |
|
71 | 141 | public function load() |
|
72 | 141 | { |
|
73 | 141 | $this->loadLogLevel() |
|
74 | 141 | ->loadLogFilePath() |
|
75 | 141 | ->loadRotateCycle() |
|
76 | 141 | ->loadRotateSize() |
|
77 | ->loadApplicationName() |
||
78 | ->loadFormat(); |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | 141 | * ログ設定を返却する |
|
83 | * @return Container ログ設定 |
||
84 | 141 | */ |
|
85 | public function getConfig() |
||
86 | { |
||
87 | return $this->logContainer; |
||
88 | } |
||
89 | |||
90 | /** |
||
91 | 141 | * ログレベルを読み込む |
|
92 | * @throws LoggerException |
||
93 | 141 | */ |
|
94 | private function loadLogLevel() |
||
95 | { |
||
96 | if (!array_key_exists("level", $this->configMap)) { |
||
97 | 141 | throw new LoggerException("Log level must be defined."); |
|
98 | 141 | } |
|
99 | |||
100 | 141 | $logLevel = $this->toLogLevelValue($this->configMap["level"]); |
|
101 | $this->logContainer->logLevel = $logLevel; |
||
102 | |||
103 | return $this; |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | 141 | * ログ保存先パスを読み込む |
|
108 | * @throws LoggerException |
||
109 | 141 | */ |
|
110 | 141 | private function loadLogFilePath() |
|
111 | 9 | { |
|
112 | $file = $this->ioContainer->file; |
||
113 | if (!($file->exists() && $file->isFile())) { |
||
114 | 141 | $this->ioContainer->fileWriter->write(""); |
|
115 | 141 | } |
|
116 | 141 | ||
117 | 141 | $this->logContainer->logPath = $file->getAbsoluteFilePath(); |
|
118 | $this->logContainer->statusPath = preg_replace_callback('/(.*)\..+/', function ($matches) { |
||
119 | 141 | return "$matches[1].status"; |
|
120 | }, $this->logContainer->logPath); |
||
121 | |||
122 | return $this; |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | 141 | * ログローテートサイクルを読み込む |
|
127 | * @throws LoggerException |
||
128 | 141 | */ |
|
129 | 14 | private function loadRotateCycle() |
|
130 | { |
||
131 | if (array_key_exists("rotate_cycle", $this->configMap)) { |
||
132 | 141 | $this->logContainer->rotateCycle = $this->cycle2value($this->configMap["rotate_cycle"]); |
|
133 | } |
||
134 | |||
135 | return $this; |
||
136 | } |
||
137 | |||
138 | /** |
||
139 | 141 | * ログローテートサイズを読み込む |
|
140 | * @throws LoggerException |
||
141 | 141 | */ |
|
142 | private function loadRotateSize() |
||
143 | { |
||
144 | if (array_key_exists("rotate_size", $this->configMap)) { |
||
145 | $rotateSize = intval($this->configMap["rotate_size"]); |
||
146 | // ローテートサイズが不正の場合(正の整数以外の値が設定された場合) |
||
147 | if ($rotateSize <= 0) { |
||
148 | throw new LoggerException("Invalid log rotate size: " . $this->configMap["rotate_size"]); |
||
149 | } |
||
150 | 141 | $this->logContainer->rotateSize = $rotateSize; |
|
151 | } |
||
152 | |||
153 | return $this; |
||
154 | } |
||
155 | |||
156 | 141 | /** |
|
157 | * アプリケーション名を読み込む |
||
158 | 141 | */ |
|
159 | 115 | private function loadApplicationName() |
|
160 | { |
||
161 | if (array_key_exists("application_name", $this->configMap) && !empty($this->configMap["application_name"])) { |
||
162 | 141 | $this->logContainer->applicationName = $this->configMap["application_name"]; |
|
163 | } |
||
164 | |||
165 | return $this; |
||
166 | } |
||
167 | |||
168 | 141 | /** |
|
169 | * ロガーフォーマットを読み込む |
||
170 | 141 | */ |
|
171 | 141 | private function loadFormat() |
|
172 | { |
||
173 | if (array_key_exists("format", $this->configMap)) { |
||
174 | $this->logContainer->format = $this->configMap["format"]; |
||
175 | } else { |
||
176 | 141 | $this->logContainer->format = $this->defaultLoggerFormatter(); |
|
177 | } |
||
178 | |||
179 | return $this; |
||
180 | } |
||
181 | |||
182 | /** |
||
183 | * ログローテートサイクルを時間に変換 |
||
184 | * @param string ローテートサイクル |
||
185 | 14 | * @return int ローテート時間 |
|
186 | * @throws LoggerException |
||
187 | 14 | */ |
|
188 | 14 | private function cycle2value($cycle) |
|
189 | 14 | { |
|
190 | 14 | $day_to_h = 24; |
|
191 | $week_to_h = $day_to_h * 7; |
||
192 | 14 | $month_to_h = $day_to_h * intval(date("t", time())); |
|
193 | 14 | $year_to_h = $day_to_h * 365; |
|
194 | |||
195 | $year = date("Y"); |
||
196 | if (($year % 4 === 0 && $year % 100 !== 0) || $year % 400 === 0) { |
||
197 | 14 | $year_to_h = $day_to_h * 366; |
|
198 | 14 | } |
|
199 | 4 | ||
200 | 10 | switch (strtolower($cycle)) { |
|
201 | 4 | case 'day': |
|
202 | 6 | return $day_to_h; |
|
203 | 3 | case 'week': |
|
204 | 3 | return $week_to_h; |
|
205 | 3 | case 'month': |
|
206 | return $month_to_h; |
||
207 | case 'year': |
||
208 | return $year_to_h; |
||
209 | default: |
||
210 | throw new LoggerException("Invalid log rotate cycle: " . $cycle); |
||
211 | } |
||
212 | } |
||
213 | |||
214 | /** |
||
215 | * ログレベルを数値に変換 |
||
216 | * ログレベルはWebStream独自、PSR-3両方対応 |
||
217 | * @param string ログレベル文字列 |
||
218 | 141 | * @throws LoggerException |
|
219 | * @return int ログレベル数値 |
||
220 | 141 | */ |
|
221 | 141 | private function toLogLevelValue(string $level) |
|
222 | 42 | { |
|
223 | 99 | switch (strtolower($level)) { |
|
224 | 11 | case 'debug': |
|
225 | 88 | return 1; |
|
226 | 11 | case 'info': |
|
227 | 77 | return 2; |
|
228 | 55 | case 'notice': // PSR-3 |
|
229 | 22 | return 3; |
|
230 | 55 | case 'warn': |
|
231 | 11 | case 'warning': // PSR-3 |
|
232 | 44 | return 4; |
|
233 | 11 | case 'error': |
|
234 | 33 | return 5; |
|
235 | 11 | case 'critical': // PSR-3 |
|
236 | 22 | return 6; |
|
237 | 11 | case 'alert': // PSR-3 |
|
238 | 11 | return 7; |
|
239 | 11 | case 'emergency': // PSR-3 |
|
240 | return 8; |
||
241 | case 'fatal': |
||
242 | return 9; |
||
243 | default: |
||
244 | throw new LoggerException("Undefined log level: $level"); |
||
245 | } |
||
246 | } |
||
247 | } |
||
248 |