Completed
Push — 6.0 ( 351621...a41474 )
by liu
05:22
created

Log::__construct()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 4
eloc 9
c 2
b 0
f 0
nc 8
nop 1
dl 0
loc 18
ccs 0
cts 10
cp 0
crap 20
rs 9.9666
1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
use InvalidArgumentException;
16
use Psr\Log\LoggerInterface;
17
18
/**
19
 * 日志管理类
20
 */
21
class Log implements LoggerInterface
22
{
23
    const EMERGENCY = 'emergency';
24
    const ALERT     = 'alert';
25
    const CRITICAL  = 'critical';
26
    const ERROR     = 'error';
27
    const WARNING   = 'warning';
28
    const NOTICE    = 'notice';
29
    const INFO      = 'info';
30
    const DEBUG     = 'debug';
31
    const SQL       = 'sql';
32
33
    /**
34
     * 日志信息
35
     * @var array
36
     */
37
    protected $log = [];
38
39
    /**
40
     * 日志通道
41
     * @var array
42
     */
43
    protected $channel = [];
44
45
    /**
46
     * 配置参数
47
     * @var array
48
     */
49
    protected $config = [];
50
51
    /**
52
     * 日志写入驱动
53
     * @var array
54
     */
55
    protected $driver = [];
56
57
    /**
58
     * 日志处理
59
     *
60
     * @var array
61
     */
62
    protected $processor = [];
63
64
    /**
65
     * 关闭日志(渠道)
66
     * @var array
67
     */
68
    protected $close = [];
69
70
    /**
71
     * (通道)允许写入类型
72
     * @var array
73
     */
74
    protected $allow = [];
75
76
    /**
77
     * 是否控制台执行
78
     * @var bool
79
     */
80
    protected $isCli = false;
81
82
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $app should have a doc-comment as per coding-style.
Loading history...
83
     * 构造方法
84
     * @access public
85
     */
86
    public function __construct(App $app)
87
    {
88
        $this->config = $app->config->get('log');
89
90
        if (isset($this->config['processor'])) {
91
            $this->processor($this->config['processor']);
92
        }
93
94
        if (!empty($this->config['close'])) {
95
            $this->close['*'] = true;
96
        }
97
98
        if (!empty($this->config['level'])) {
99
            $this->allow['*'] = $this->config['level'];
100
        }
101
102
        $this->isCli = $app->runningInConsole();
103
        $this->channel();
104
    }
105
106
    /**
107
     * 获取日志配置
108
     * @access public
109
     * @return array
110
     */
111
    public function getConfig(): array
112
    {
113
        return $this->config;
114
    }
115
116
    /**
117
     * 注册一个日志回调处理
118
     *
119
     * @param  callable $callback 回调
120
     * @param  string   $channel  日志通道名
121
     * @return void
122
     */
123
    public function processor(callable $callback, string $channel = '*'): void
124
    {
125
        $this->processor[$channel][] = $callback;
126
    }
127
128
    /**
129
     * 切换日志通道
130
     * @access public
131
     * @param  string|array $name 日志通道名
132
     * @return $this
133
     */
134
    public function channel($name = '')
135
    {
136
        if ('' == $name) {
137
            $name = $this->config['default'] ?? 'think';
138
        }
139
140
        $names = (array) $name;
141
142
        foreach ($names as $name) {
143
            if (!isset($this->config['channels'][$name])) {
144
                throw new InvalidArgumentException('Undefined log config:' . $name);
145
            }
146
147
            $config = $this->config['channels'][$name];
148
149
            if (!empty($config['processor'])) {
150
                $this->processor($config['processor'], $name);
151
            }
152
153
            if (!empty($config['close'])) {
154
                $this->close[$name] = true;
155
            }
156
157
            if (!empty($config['level'])) {
158
                $this->allow[$name] = $config['level'];
159
            }
160
        }
161
162
        $this->channel = $names;
163
        return $this;
164
    }
165
166
    /**
167
     * 实例化日志写入驱动
168
     * @access public
169
     * @param  string $name 日志通道名
170
     * @return object
171
     */
172
    protected function driver(string $name)
173
    {
174
        if (!isset($this->driver[$name])) {
175
            $config = $this->config['channels'][$name];
176
            $type   = !empty($config['type']) ? $config['type'] : 'File';
177
178
            $this->driver[$name] = App::factory($type, '\\think\\log\\driver\\', $config);
179
        }
180
181
        return $this->driver[$name];
182
    }
183
184
    /**
185
     * 获取日志信息
186
     * @access public
187
     * @param  string $channel 日志通道
188
     * @return array
189
     */
190
    public function getLog(string $channel = ''): array
191
    {
192
        $channel = $channel ?: array_shift($this->channel);
193
        return $this->log[$channel] ?? [];
194
    }
195
196
    /**
197
     * 记录日志信息
198
     * @access public
199
     * @param  mixed  $msg       日志信息
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 7 found
Loading history...
200
     * @param  string $type      日志级别
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 6 found
Loading history...
201
     * @param  array  $context   替换内容
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
202
     * @return $this
203
     */
204
    public function record($msg, string $type = 'info', array $context = [])
205
    {
206
        if (!empty($this->allow['*']) && !in_array($type, $this->allow['*'])) {
207
            return $this;
208
        }
209
210
        if (is_string($msg) && !empty($context)) {
211
            $replace = [];
212
            foreach ($context as $key => $val) {
213
                $replace['{' . $key . '}'] = $val;
214
            }
215
216
            $msg = strtr($msg, $replace);
217
        }
218
219
        if (isset($this->config['type_channel'][$type])) {
220
            $channels = (array) $this->config['type_channel'][$type];
221
        } else {
222
            $channels = $this->channel;
223
        }
224
225
        foreach ($channels as $channel) {
226
            if (empty($this->allow[$channel]) || in_array($type, $this->allow[$channel])) {
227
                $this->channelLog($channel, $msg, $type);
228
            }
229
        }
230
231
        return $this;
232
    }
233
234
    /**
235
     * 记录通道日志
236
     * @access public
237
     * @param  string $channel 日志通道
238
     * @param  mixed  $msg  日志信息
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 2 found
Loading history...
239
     * @param  string $type 日志级别
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
240
     * @return void
241
     */
242
    protected function channelLog(string $channel, $msg, string $type): void
243
    {
244
        if (!empty($this->close['*']) || !empty($this->close[$channel])) {
245
            return;
246
        }
247
248
        if ($this->isCli || !empty($this->config['channels'][$channel]['realtime_write'])) {
249
            // 实时写入
250
            $this->write($msg, $type, true, $channel);
251
        } else {
252
            $this->log[$channel][$type][] = $msg;
253
        }
254
    }
255
256
    /**
257
     * 清空日志信息
258
     * @access public
259
     * @param  string  $channel 日志通道名
260
     * @return $this
261
     */
262
    public function clear(string $channel = '')
263
    {
264
        if ($channel) {
265
            $this->log[$channel] = [];
266
        } else {
267
            $this->log = [];
268
        }
269
270
        return $this;
271
    }
272
273
    /**
274
     * 关闭本次请求日志写入
275
     * @access public
276
     * @param  string  $channel 日志通道名
277
     * @return $this
278
     */
279
    public function close(string $channel = '*')
280
    {
281
        $this->close[$channel] = true;
282
283
        $this->clear('*' == $channel ? '' : $channel);
284
285
        return $this;
286
    }
287
288
    /**
289
     * 保存日志信息
290
     * @access public
291
     * @return bool
292
     */
293
    public function save(): bool
294
    {
295
        if (!empty($this->close['*'])) {
296
            return true;
297
        }
298
299
        foreach ($this->log as $channel => $logs) {
300
            if (!empty($this->close[$channel])) {
301
                continue;
302
            }
303
304
            $result = $this->saveChannel($channel, $logs);
305
306
            if ($result) {
307
                $this->log[$channel] = [];
308
            }
309
        }
310
311
        return true;
312
    }
313
314
    /**
315
     * 保存某个通道的日志信息
316
     * @access protected
317
     * @param  string $channel 日志通道名
318
     * @param  array  $log    日志信息
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 4 found
Loading history...
319
     * @return bool
320
     */
321
    protected function saveChannel(string $channel, array $log = []): bool
322
    {
323
        // 日志处理
324
        $processors = array_merge($this->processor[$channel] ?? [], $this->processor['*'] ?? []);
325
326
        foreach ($processors as $callback) {
327
            $log = $callback($log, $channel);
328
329
            if (false === $log) {
330
                return false;
331
            }
332
        }
333
334
        return $this->driver($channel)->save($log);
335
    }
336
337
    /**
338
     * 实时写入日志信息
339
     * @access public
340
     * @param  mixed  $msg   调试信息
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 3 found
Loading history...
341
     * @param  string $type  日志级别
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 2 found
Loading history...
342
     * @param  bool   $force 是否强制写入
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 1 found
Loading history...
343
     * @param  string $channel  日志通道
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
344
     * @return bool
345
     */
346
    public function write($msg, string $type = 'info', bool $force = false, $channel = ''): bool
347
    {
348
        if (empty($this->allow['*'])) {
349
            $force = true;
350
        }
351
352
        $log = [];
353
354
        if (true === $force || in_array($type, $this->allow['*'])) {
355
            $log[$type][] = $msg;
356
        } else {
357
            return false;
358
        }
359
360
        // 写入日志
361
        $channels = $channel ? (array) $channel : $this->channel;
362
363
        foreach ($channels as $channel) {
364
            if (empty($this->allow[$channel]) || in_array($type, $this->allow[$channel])) {
365
                $this->saveChannel($channel, $log);
366
            }
367
        }
368
369
        return true;
370
    }
371
372
    /**
373
     * 记录日志信息
374
     * @access public
375
     * @param  string $level     日志级别
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 5 found
Loading history...
376
     * @param  mixed  $message   日志信息
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
377
     * @param  array  $context   替换内容
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
378
     * @return void
379
     */
380
    public function log($level, $message, array $context = []): void
381
    {
382
        $this->record($message, $level, $context);
383
    }
384
385
    /**
386
     * 记录emergency信息
387
     * @access public
388
     * @param  mixed $message 日志信息
389
     * @param  array $context 替换内容
390
     * @return void
391
     */
392
    public function emergency($message, array $context = []): void
393
    {
394
        $this->log(__FUNCTION__, $message, $context);
395
    }
396
397
    /**
398
     * 记录警报信息
399
     * @access public
400
     * @param  mixed $message 日志信息
401
     * @param  array $context 替换内容
402
     * @return void
403
     */
404
    public function alert($message, array $context = []): void
405
    {
406
        $this->log(__FUNCTION__, $message, $context);
407
    }
408
409
    /**
410
     * 记录紧急情况
411
     * @access public
412
     * @param  mixed $message 日志信息
413
     * @param  array $context 替换内容
414
     * @return void
415
     */
416
    public function critical($message, array $context = []): void
417
    {
418
        $this->log(__FUNCTION__, $message, $context);
419
    }
420
421
    /**
422
     * 记录错误信息
423
     * @access public
424
     * @param  mixed $message 日志信息
425
     * @param  array $context 替换内容
426
     * @return void
427
     */
428
    public function error($message, array $context = []): void
429
    {
430
        $this->log(__FUNCTION__, $message, $context);
431
    }
432
433
    /**
434
     * 记录warning信息
435
     * @access public
436
     * @param  mixed $message 日志信息
437
     * @param  array $context 替换内容
438
     * @return void
439
     */
440
    public function warning($message, array $context = []): void
441
    {
442
        $this->log(__FUNCTION__, $message, $context);
443
    }
444
445
    /**
446
     * 记录notice信息
447
     * @access public
448
     * @param  mixed $message 日志信息
449
     * @param  array $context 替换内容
450
     * @return void
451
     */
452
    public function notice($message, array $context = []): void
453
    {
454
        $this->log(__FUNCTION__, $message, $context);
455
    }
456
457
    /**
458
     * 记录一般信息
459
     * @access public
460
     * @param  mixed $message 日志信息
461
     * @param  array $context 替换内容
462
     * @return void
463
     */
464
    public function info($message, array $context = []): void
465
    {
466
        $this->log(__FUNCTION__, $message, $context);
467
    }
468
469
    /**
470
     * 记录调试信息
471
     * @access public
472
     * @param  mixed $message 日志信息
473
     * @param  array $context 替换内容
474
     * @return void
475
     */
476
    public function debug($message, array $context = []): void
477
    {
478
        $this->log(__FUNCTION__, $message, $context);
479
    }
480
481
    /**
482
     * 记录sql信息
483
     * @access public
484
     * @param  mixed $message 日志信息
485
     * @param  array $context 替换内容
486
     * @return void
487
     */
488
    public function sql($message, array $context = []): void
489
    {
490
        $this->log(__FUNCTION__, $message, $context);
491
    }
492
493
    public function __call($method, $args)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __call()
Loading history...
494
    {
495
        array_unshift($args, $method);
496
        call_user_func_array([$this, 'log'], $args);
497
    }
498
}
499