Passed
Push — master ( b817d9...04ae87 )
by 世昌
02:23
created

Debug::analyse()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
c 0
b 0
f 0
nc 3
nop 2
dl 0
loc 13
rs 9.9666
1
<?php
2
3
namespace suda\framework\debug;
4
5
use suda\framework\debug\log\LogLevel;
6
use suda\framework\debug\log\LoggerTrait;
7
use suda\framework\debug\attach\DumpTrait;
8
use suda\framework\debug\attach\AttachTrait;
9
use suda\framework\debug\log\LoggerInterface;
10
use suda\framework\debug\attach\DumpInterface;
11
use suda\framework\debug\log\LoggerAwareTrait;
12
use suda\framework\debug\attach\AttachInterface;
13
use suda\framework\debug\log\LoggerAwareInterface;
14
15
class Debug implements LoggerInterface, LoggerAwareInterface, DumpInterface, AttachInterface, ConfigInterface
16
{
17
    use LoggerTrait, LoggerAwareTrait, DumpTrait, AttachTrait, ConfigTrait;
18
19
    /**
20
     * 忽略堆栈
21
     *
22
     * @var array
23
     */
24
    protected $ignoreTraces = [__DIR__];
25
26
    /**
27
     * 时间记录
28
     *
29
     * @var array
30
     */
31
    protected $timeRecord;
32
33
    public function log(string $level, string $message, array $context = [])
34
    {
35
        $attribute = $this->getAttribute();
36
        list($attach, $replace) = $this->analyse($message, $context);
37
        $attribute = array_merge($attribute, $attach);
38
        $attribute['message'] = strtr($message, $replace);
39
        $attribute['level'] = $level;
40
        $caller = new Caller(debug_backtrace(), $this->getIgnoreTraces());
41
        $trace = $caller->getCallerTrace();
42
        $attribute['file'] = $trace['file'];
43
        $attribute['line'] = $trace['line'];
44
        $attribute = $this->assignAttributes($attribute);
45
        $this->logger->log($level, $this->interpolate($this->getConfig('log-format'), $attach, $attribute), []);
46
    }
47
48
    public function analyse(string $message, array $context)
49
    {
50
        $replace = [];
51
        $attach = [];
52
        foreach ($context as $key => $val) {
53
            $replaceKey = '{' . $key . '}';
54
            if ($this->canBeStringValue($val) && strpos($message, $replaceKey) !== false) {
55
                $replace['{' . $key . '}'] = $val;
56
            } else {
57
                $attach[$key] = $val;
58
            }
59
        }
60
        return [$attach, $replace];
61
    }
62
63
    /**
64
     * 设置忽略前缀
65
     *
66
     * @return array
67
     */
68
    public function getIgnoreTraces(): array
69
    {
70
        return $this->ignoreTraces;
71
    }
72
73
    public function getDefaultConfig(): array
74
    {
75
        return [
76
            'log-format' => '%time-format% - %memory-format% [%level%] %file%:%line% %message%',
77
            'start-time' => 0,
78
            'start-memory' => 0,
79
        ];
80
    }
81
82
    protected function canBeStringValue($val) : bool
83
    {
84
        return !is_array($val) && (!is_object($val) || method_exists($val, '__toString'));
85
    }
86
87
    protected function assignAttributes(array $attribute): array
88
    {
89
        $attribute['current-time'] = number_format(microtime(true), 4, '.', '');
90
        $time = microtime(true) - $this->getConfig('start-time');
91
        $memory = memory_get_usage() - $this->getConfig('start-memory');
92
        $attribute['time-format'] = number_format($time, 10, '.', '');
93
        $attribute['memory-format'] = $this->formatBytes($memory, 2);
94
        $attribute['memory'] = $memory;
95
        return $attribute;
96
    }
97
98
    public static function formatBytes(int $bytes, int $precision = 0)
99
    {
100
        $human = ['B', 'KB', 'MB', 'GB', 'TB'];
101
        $bytes = max($bytes, 0);
102
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
103
        $pos = min($pow, count($human) - 1);
104
        $bytes /= (1 << (10 * $pos));
105
        return round($bytes, $precision) . ' ' . $human[$pos];
106
    }
107
108
    public function time(string $name, string $type = LogLevel::INFO)
109
    {
110
        $this->timeRecord[$name] = ['time' => microtime(true), 'level' => $type];
111
    }
112
113
    public function timeEnd(string $name)
114
    {
115
        if (array_key_exists($name, $this->timeRecord)) {
116
            $pass = microtime(true) - $this->timeRecord[$name]['time'];
117
            $this->log(
118
                $this->timeRecord[$name]['level'],
119
                sprintf("process %s cost %ss", $name, number_format($pass, 5))
120
            );
121
            return $pass;
122
        }
123
        return 0;
124
    }
125
126
    /**
127
     * @param array $ignoreTraces
128
     * @return $this
129
     */
130
    public function setIgnoreTraces(array $ignoreTraces)
131
    {
132
        $this->ignoreTraces = $ignoreTraces;
133
        return $this;
134
    }
135
136
137
    /**
138
     * 添加忽略路径
139
     * @param string $path
140
     * @return $this
141
     */
142
    public function addIgnorePath(string $path)
143
    {
144
        $this->ignoreTraces[] = $path;
145
        return $this;
146
    }
147
}
148