Completed
Push — 6.0 ( 62d9a3...e4824c )
by liu
05:31
created

Log::saveChannel()   B

Complexity

Conditions 8
Paths 9

Size

Total Lines 26
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

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