Passed
Push — master ( 55d732...3cbcb3 )
by Alexander
02:27
created

PsrTarget::setLogger()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
namespace samdark\log;
3
4
use Closure;
5
use Psr\Log\LoggerInterface;
6
use Psr\Log\LogLevel;
7
use yii\base\InvalidConfigException;
8
use yii\helpers\VarDumper;
9
use yii\log\Logger;
10
use yii\log\Target;
11
12
/**
13
 * PsrTarget is a log target which passes messages to PSR-3 compatible logger.
14
 *
15
 * @author Alexander Makarov <[email protected]>
16
 */
17
class PsrTarget extends Target
18
{
19
    /**
20
     * The logger instance.
21
     *
22
     * @var LoggerInterface|Closure|null
23
     */
24
    protected $logger;
25
26
    /**
27
     * @var bool If enabled, logger use original timestamp from buffer
28
     * @since 1.1.0
29
     */
30
    public $addTimestampToContext = false;
31
32
    /**
33
     * @var bool If enabled, exception's trace will extract into `trace` property
34
     */
35
    public $extractExceptionTrace = false;
36
37
    private $_levelMap = [
38
        Logger::LEVEL_ERROR => LogLevel::ERROR,
39
        Logger::LEVEL_WARNING => LogLevel::WARNING,
40
        Logger::LEVEL_INFO => LogLevel::INFO,
41
        Logger::LEVEL_TRACE => LogLevel::DEBUG,
42
        Logger::LEVEL_PROFILE => LogLevel::DEBUG,
43
        Logger::LEVEL_PROFILE_BEGIN => LogLevel::DEBUG,
44
        Logger::LEVEL_PROFILE_END => LogLevel::DEBUG,
45
46
        // Psr Levels
47
        LogLevel::EMERGENCY => LogLevel::EMERGENCY,
48
        LogLevel::ALERT => LogLevel::ALERT,
49
        LogLevel::CRITICAL => LogLevel::CRITICAL,
50
        LogLevel::ERROR => LogLevel::ERROR,
51
        LogLevel::WARNING => LogLevel::WARNING,
52
        LogLevel::NOTICE => LogLevel::NOTICE,
53
        LogLevel::INFO => LogLevel::INFO,
54
        LogLevel::DEBUG => LogLevel::DEBUG,
55
    ];
56
57
    /**
58
     * @var array
59
     */
60
    private $_levels = [];
61
62
    public function __construct($config = [])
63
    {
64
        $this->_levels = $this->_levelMap;
65
        parent::__construct($config);
66
    }
67
    
68
    /**
69
     * Sets a logger.
70
     *
71
     * @param LoggerInterface|Closure $logger
72
     */
73
    public function setLogger($logger)
74
    {
75
        $this->logger = $logger;
76
    }
77
    
78
    /**
79
     * @return LoggerInterface
80
     * @throws InvalidConfigException
81
     */
82
    public function getLogger()
83
    {
84
        if ($this->logger === null) {
85
            throw new InvalidConfigException('Logger should be configured with Psr\Log\LoggerInterface.');
86
        }
87
        if ($this->logger instanceof Closure) {
88
            $loggerClosure = $this->logger;
89
            $this->logger = $loggerClosure();
90
        }
91
        
92
        return $this->logger;
93
    }
94
95
    /**
96
     * @inheritdoc
97
     */
98
    public function export()
99
    {
100
        foreach ($this->messages as $message) {
101
            $level = $message[1];
102
103
            $context = [];
104
            if (isset($message[4])) {
105
                $context['trace'] = $message[4];
106
            }
107
108
            if (isset($message[5])) {
109
                $context['memory'] = $message[5];
110
            }
111
112
            if (isset($message[2])) {
113
                $context['category'] = $message[2];
114
            }
115
116
            if ($this->addTimestampToContext && isset($message[3])) {
117
                $context['timestamp'] = $message[3];
118
            }
119
120
            $text = $message[0];
121
            if (!is_string($text)) {
122
                // exceptions may not be serializable if in the call stack somewhere is a Closure
123
                if ($text instanceof \Throwable || $text instanceof \Exception) {
124
                    $context['exception'] = $text;
125
                    if ($this->extractExceptionTrace) {
126
                        $context['trace'] = explode(PHP_EOL, $text->getTraceAsString());
127
                        $text = $text->getMessage();
128
                    } else {
129
                        $text = (string)$text;
130
                    }
131
                } elseif ($text instanceof PsrMessage) {
132
                    $context = array_merge($text->getContext(), $context); // Will not replace standard context keys
133
                    $text = $text->getMessage();
134
                } else {
135
                    $text = VarDumper::export($text);
136
                }
137
            }
138
139
            $this->getLogger()->log($this->_levelMap[$level], $text, $context);
140
        }
141
    }
142
143
    public static function filterMessages($messages, $levels = [], $categories = [], $except = [])
144
    {
145
        $filterByLevel = function ($message) use ($levels) {
146
            return isset($levels[$message[1]]);
147
        };
148
        return array_filter(parent::filterMessages($messages, 0, $categories, $except), $filterByLevel);
149
    }
150
151
    public function getLevels()
152
    {
153
        return $this->_levels;
154
    }
155
156
    /**
157
     * Sets the message levels that this target is interested in.
158
     *
159
     * The parameter can be an array.
160
     * Valid level names include: 'error',
161
     * 'warning', 'info', 'trace' and 'profile'; valid level values include:
162
     * [[Logger::LEVEL_ERROR]], [[Logger::LEVEL_WARNING]], [[Logger::LEVEL_INFO]],
163
     * [[Logger::LEVEL_TRACE]], [[Logger::LEVEL_PROFILE]] and Psr Log levels:
164
     * [[LogLevel::EMERGENCY]], [[LogLevel::ALERT]], [[LogLevel::CRITICAL]],
165
     * [[LogLevel::ERROR]], [[LogLevel::WARNING]], [[LogLevel::NOTICE]],
166
     * [[LogLevel::INFO]] and [[LogLevel::DEBUG]].
167
     *
168
     * For example,
169
     *
170
     * ```php
171
     * ['error', 'warning', LogLevel::CRITICAL, LogLevel::EMERGENCY]
172
     * ```
173
     *
174
     * @param array $levels message levels that this target is interested in.
175
     * @throws InvalidConfigException if $levels value is not correct.
176
     */
177
    public function setLevels($levels)
178
    {
179
        static $levelMap = [
180
            'error' => Logger::LEVEL_ERROR,
181
            'warning' => Logger::LEVEL_WARNING,
182
            'info' => Logger::LEVEL_INFO,
183
            'trace' => Logger::LEVEL_TRACE,
184
            'profile' => Logger::LEVEL_PROFILE,
185
        ];
186
187
        if (is_array($levels)) {
0 ignored issues
show
introduced by
The condition is_array($levels) is always true.
Loading history...
188
            $intrestingLevels = [];
189
            
190
            foreach ($levels as $level) {
191
                if (!isset($this->_levels[$level]) && !isset($levelMap[$level])) {
192
                    throw new InvalidConfigException("Unrecognized level: $level");
193
                }
194
195
                if (isset($levelMap[$level])) {
196
                    $intrestingLevels[$levelMap[$level]] = $this->_levels[$levelMap[$level]];
197
                }
198
199
                if (isset($this->_levels[$level])) {
200
                    $intrestingLevels[$level] = $this->_levels[$level];
201
                }
202
            }
203
            
204
            $this->_levels = $intrestingLevels;
205
        } else {
206
            throw new InvalidConfigException("Incorrect $levels value");
207
        }
208
    }
209
}
210