Completed
Push — 6.0 ( 0285c5...28e2fd )
by liu
04:21
created

Log   D

Complexity

Total Complexity 59

Size/Duplication

Total Lines 465
Duplicated Lines 0 %

Test Coverage

Coverage 8.66%

Importance

Changes 7
Bugs 0 Features 0
Metric Value
eloc 115
c 7
b 0
f 0
dl 0
loc 465
ccs 11
cts 127
cp 0.0866
rs 4.08
wmc 59

24 Methods

Rating   Name   Duplication   Size   Complexity  
A getConfig() 0 3 1
A processor() 0 3 1
A __construct() 0 14 3
A driver() 0 10 3
A channel() 0 27 6
A close() 0 7 2
A error() 0 3 1
A log() 0 3 1
A clear() 0 9 2
A alert() 0 3 1
A info() 0 3 1
A record() 0 22 6
A getLog() 0 4 2
A notice() 0 3 1
B saveChannel() 0 26 7
A warning() 0 3 1
A write() 0 22 6
A debug() 0 3 1
A emergency() 0 3 1
A critical() 0 3 1
A save() 0 15 4
A __call() 0 4 1
A channelLog() 0 11 5
A sql() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Log often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Log, and based on these observations, apply Extract Interface, too.

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