Completed
Push — master ( c55b9c...a42776 )
by ྅༻ Ǭɀħ
02:36 queued 01:19
created

Logger   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 325
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 32
lcom 1
cbo 1
dl 0
loc 325
ccs 88
cts 88
cp 1
rs 9.6
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 2
A emergency() 0 4 1
A alert() 0 4 1
A critical() 0 4 1
A error() 0 4 1
A warning() 0 4 1
A notice() 0 4 1
A info() 0 4 1
A debug() 0 4 1
A log() 0 18 4
A isLogLevel() 0 7 2
A shouldLog() 0 3 1
A isStringable() 0 11 4
A getLog() 0 4 1
A defaultFormat() 0 12 2
B formatContext() 0 23 4
A setMessageFormat() 0 4 1
A getMessageFormat() 0 4 1
A setLevel() 0 4 1
A getLevel() 0 4 1
1
<?php
2
3
namespace Ozh\Log;
4
5
use \Psr\Log\LoggerInterface;
6
use \Psr\Log\LogLevel;
7
use \Psr\Log\InvalidArgumentException;
8
9
/**
10
 * Ozh\Log\Logger - a minimalist PSR-3 compliant logger, that logs into an array.
11
 *
12
 * (c) Ozh 2017 - Do whatever the hell you want with it
13
 */
14
15
class Logger implements LoggerInterface
16
{
17
    /**
18
     * The array that will collect all the log messages
19
     *
20
     * @see Logger::log()
21
     * @see Logger::getLog()
22
     * @var array
23
     */
24
    protected $log = array();
25
    
26
27
    /**
28
     * The callable to format every logged message
29
     *
30
     * @var callable
31
     * @see Logger::defaultFormat()
32
     */
33
    protected $message_format;
34
    
35
36
    /**
37
     * Current logging level (eg 'debug', 'info', 'notice', 'warning', 'error', 'critical', 'alert' or 'emergency')
38
     *
39
     * @var string
40
     */
41
    protected $level;
42
43
44
    /**
45
     * Logging level mapping, used to hierarchize
46
     *
47
     * This complies to \Psr\Log\LogLevel and RFC 5424 severity values :
48
     *   0  Emergency: system is unusable
49
     *   1  Alert: action must be taken immediately
50
     *   2  Critical: critical conditions
51
     *   3  Error: error conditions
52
     *   4  Warning: warning conditions
53
     *   5  Notice: normal but significant condition
54
     *   6  Informational: informational messages
55
     *   7  Debug: debug-level messages
56
     *
57
     * @var array
58
     */
59
    protected $log_levels = array(
60
        LogLevel::DEBUG     => 7,
61
        LogLevel::INFO      => 6,
62
        LogLevel::NOTICE    => 5,
63
        LogLevel::WARNING   => 4,
64
        LogLevel::ERROR     => 3,
65
        LogLevel::CRITICAL  => 2,
66
        LogLevel::ALERT     => 1,
67
        LogLevel::EMERGENCY => 0,
68
    );
69
70
71
    /**
72
     * @param  string $level
73
     */
74 75
    public function __construct($level = LogLevel::DEBUG)
75
    {
76 75
        if ($this->isLogLevel($level)) {
77 72
            $this->level = $level;
78 72
            $this->setMessageFormat(array($this, 'defaultFormat'));
79 24
        }
80 72
    }
81
82
83
    /**
84
     * @param  string $message
85
     * @param  array  $context
86
     * @see    Logger::log()
87
     * @return void
88
     */
89 3
    public function emergency($message, array $context = array())
90
    {
91 3
        $this->log(LogLevel::EMERGENCY, $message, $context);
92 3
    }
93
94
95
    /**
96
     * @param  string $message
97
     * @param  array  $context
98
     * @see    Logger::log()
99
     * @return void
100
     */
101 3
    public function alert($message, array $context = array())
102
    {
103 3
        $this->log(LogLevel::ALERT, $message, $context);
104 3
    }
105
106
107
    /**
108
     * @param  string $message
109
     * @param  array  $context
110
     * @see    Logger::log()
111
     * @return void
112
     */
113 3
    public function critical($message, array $context = array())
114
    {
115 3
        $this->log(LogLevel::CRITICAL, $message, $context);
116 3
    }
117
118
119
    /**
120
     * @param  string $message
121
     * @param  array  $context
122
     * @see    Logger::log()
123
     * @return void
124
     */
125 15
    public function error($message, array $context = array())
126
    {
127 15
        $this->log(LogLevel::ERROR, $message, $context);
128 12
    }
129
130
131
    /**
132
     * @param  string $message
133
     * @param  array  $context
134
     * @see    Logger::log()
135
     * @return void
136
     */
137 3
    public function warning($message, array $context = array())
138
    {
139 3
        $this->log(LogLevel::WARNING, $message, $context);
140 3
    }
141
142
143
    /**
144
     * @param  string $message
145
     * @param  array  $context
146
     * @see    Logger::log()
147
     * @return void
148
     */
149 3
    public function notice($message, array $context = array())
150
    {
151 3
        $this->log(LogLevel::NOTICE, $message, $context);
152 3
    }
153
154
155
    /**
156
     * @param  string $message
157
     * @param  array  $context
158
     * @see    Logger::log()
159
     * @return void
160
     */
161 3
    public function info($message, array $context = array())
162
    {
163 3
        $this->log(LogLevel::INFO, $message, $context);
164 3
    }
165
166
    /**
167
     * @param  string $message
168
     * @param  array  $context
169
     * @see    Logger::log()
170
     * @return void
171
     */
172 9
    public function debug($message, array $context = array())
173
    {
174 9
        $this->log(LogLevel::DEBUG, $message, $context);
175 9
    }
176
177
178
    /**
179
     * @param  string $level
180
     * @param  mixed  $message
181
     * @param  array  $context
182
     * @throws InvalidArgumentException
183
     * @return void
184
     */
185 45
    public function log($level, $message, array $context = array())
186
    {
187
        /**
188
         */
189 45
        if ($this->isStringable($message)) {
190 42
            $message = (string) $message;
191 14
        } else {
192 3
            throw new InvalidArgumentException('Message must be a string or an object with a __toString() method');
193
        }
194
195 42
        if ($this->isLogLevel($level) && $this->shouldLog($level)) {
196
            // This doesn't work on PHP 5.3, which throws "PHP Fatal error: Function name must be a string"
197
            // $formatter = $this->getMessageFormat();
1 ignored issue
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
198
            // $this->log[] = $formatter($level, $message, $context);
1 ignored issue
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
199
            // Instead, the following works on 5.3 to 7.2 & HHVM :
200 39
            $this->log[] = call_user_func_array($this->getMessageFormat(), array($level, $message, $context));
201 13
        }
202 39
    }
203
    
204
205
    /**
206
     * @param  string $level
207
     * @throws InvalidArgumentException
208
     * @return bool
209
     */
210 75
    public function isLogLevel($level) {
211 75
        if (!array_key_exists($level, $this->log_levels)) {
212 6
            throw new InvalidArgumentException('Invalid Log Level');
213
        }
214
        
215 72
        return true;
216
    }
217
218
219
    /**
220
     * @return bool
221
     */
222 39
    public function shouldLog($level) {
223 39
        return $this->log_levels[$level] <= $this->log_levels[$this->level];
224
    }
225
226
227
    /**
228
     * As per PSR-3, messages can be a string, or an object with a __toString() method
229
     *
230
     * @return bool
231
     */
232 45
    public function isStringable($message) {
233 45
        if(gettype($message) == 'string') {
234 39
            return true;
235
        }
236
        
237 6
        if(gettype($message) == 'object' && method_exists($message, '__toString') !== false) {
238 3
            return true;
239
        }
240
        
241 3
        return false;
242
    }
243
244
245
    /**
246
     * @return array
247
     */
248 39
    public function getLog()
249
    {
250 39
        return $this->log;
251
    }
252
253
    /**
254
     * @param  string $level
255
     * @param  string $message
256
     * @param  array  $context
257
     * @return array
258
     */
259 36
    public function defaultFormat($level, $message, array $context = array())
260
    {
261 36
        $logged = array();
262 36
        $logged['timestamp'] = date('Y-m-d H:i:s');
263 36
        $logged['level'] = $level;
264 36
        $logged['message'] = $message;
265 36
        if (!empty($context)) {
266 6
            $logged = array_merge($logged, $this->formatContext($context));
267 2
        }
268
        
269 36
        return $logged;
270
    }
271
    
272
273
    /**
274
     * @param  array  $context
275
     * @return array
276
     */
277 6
    public function formatContext($context) {
278 6
        $parsed = array();
279
        
280
        // Format exception if applicable
281 6
        if (array_key_exists('exception', $context) === true && $context['exception'] instanceof \Exception === true) {
282 3
            $exception = $context['exception'];
283 3
            $parsed['exception'] = sprintf(
284 3
                'Exception %s; message: %s; trace: %s',
285 2
                get_class($exception),
286 3
                $exception->getMessage(),
287 3
                json_encode($exception->getTraceAsString())
288 1
            );
289
            
290 3
            unset($context['exception']);
291 1
        }
292
        
293
        // Format other context if applicable
294 6
        if (count($context)>0){
295 3
            $parsed['context'] = 'Context: ' . json_encode($context);
296 1
        }
297
        
298 6
        return $parsed;
299
    }
300
    
301
302
    /**
303
     * @param  callable $message_format
304
     * @return void
305
     */
306 72
    public function setMessageFormat($message_format)
307
    {
308 72
        $this->message_format = $message_format;
309 72
    }
310
311
312
    /**
313
     * @return callable
314
     */
315 42
    public function getMessageFormat()
316
    {
317 42
        return $this->message_format;
318
    }
319
320
321
    /**
322
     * @param  string $level
323
     * @return void
324
     */
325 3
    public function setLevel($level)
326
    {
327 3
        $this->level = $level;
328 3
    }
329
330
331
    /**
332
     * @return int
333
     */
334 24
    public function getLevel()
335
    {
336 24
        return $this->level;
337
    }
338
339
}
340