Passed
Push — dev ( 102376...2c57c5 )
by 世昌
02:18
created

Debug::compare()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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