Completed
Push — 6.0 ( a73dfa...aafcf8 )
by liu
04:31
created

Log::clear()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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