Logger::getAdapters()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1.037

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 3
cp 0.6667
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1.037
1
<?php
2
3
/**
4
 * This file is part of the Phalcon Framework.
5
 *
6
 * (c) Phalcon Team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE.txt
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Phalcon;
15
16
use Phalcon\Helper\Arr;
17
use Phalcon\Logger\Adapter\AdapterInterface;
18
use Phalcon\Logger\Exception as LoggerException;
19
use Phalcon\Logger\Item;
20
use Psr\Log\LoggerInterface;
21
22
use function array_flip;
23
use function is_numeric;
24
use function is_string;
25
use function time;
26
27
/**
28
 * Class Logger
29
 *
30
 * @property AdapterInterface[] $adapters
31
 * @property int                $logLevel
32
 * @property string             $name
33
 * @property array              $excluded
34
 */
35
class Logger implements LoggerInterface
36
{
37
    public const ALERT     = 2;
38
    public const CRITICAL  = 1;
39
    public const CUSTOM    = 8;
40
    public const DEBUG     = 7;
41
    public const EMERGENCY = 0;
42
    public const ERROR     = 3;
43
    public const INFO      = 6;
44
    public const NOTICE    = 5;
45
    public const WARNING   = 4;
46
47
    /**
48
     * The adapter stack
49
     *
50
     * @var AdapterInterface[]
51
     */
52
    protected $adapters = [];
53
54
    /**
55
     * Minimum log level for the logger
56
     *
57
     * @var int
58
     */
59
    protected $logLevel = 8;
60
61
    /**
62
     * @var string
63
     */
64
    protected $name = "";
65
66
    /**
67
     * The excluded adapters for this log process
68
     *
69
     * @var array
70
     */
71
    protected $excluded = [];
72
73
    /**
74
     * Constructor.
75
     *
76
     * @param string $name     The name of the logger
77
     * @param array  $adapters The collection of adapters to be used for
78
     *                         logging (default [])
79
     */
80 27
    public function __construct(string $name, array $adapters = [])
81
    {
82 27
        $this->name = $name;
83
84 27
        $this->setAdapters($adapters);
85 27
    }
86
87
    /**
88
     * Add an adapter to the stack. For processing we use FIFO
89
     *
90
     * @param string           $name    The name of the adapter
91
     * @param AdapterInterface $adapter The adapter to add to the stack
92
     *
93
     * @return Logger
94
     */
95 1
    public function addAdapter(string $name, AdapterInterface $adapter): Logger
96
    {
97 1
        $this->adapters[$name] = $adapter;
98
99 1
        return $this;
100
    }
101
102
    /**
103
     * Action must be taken immediately.
104
     *
105
     * Example: Entire website down, database unavailable, etc. This should
106
     * trigger the SMS alerts and wake you up.
107
     *
108
     * @param string $message
109
     * @param array  $context
110
     *
111
     * @throws LoggerException
112
     */
113 1
    public function alert($message, array $context = []): void
114
    {
115 1
        $this->addMessage(self::ALERT, (string) $message, $context);
116 1
    }
117
118
    /**
119
     * Critical conditions.
120
     *
121
     * Example: Application component unavailable, unexpected exception.
122
     *
123
     * @param string $message
124
     * @param array  $context
125
     *
126
     * @throws LoggerException
127
     */
128 1
    public function critical($message, array $context = []): void
129
    {
130 1
        $this->addMessage(self::CRITICAL, (string) $message, $context);
131 1
    }
132
133
    /**
134
     * Detailed debug information.
135
     *
136
     * @param string $message
137
     * @param array  $context
138
     *
139
     * @throws LoggerException
140
     */
141 4
    public function debug($message, array $context = []): void
142
    {
143 4
        $this->addMessage(self::DEBUG, (string) $message, $context);
144 4
    }
145
146
    /**
147
     * Runtime errors that do not require immediate action but should typically
148
     * be logged and monitored.
149
     *
150
     * @param string $message
151
     * @param array  $context
152
     *
153
     * @throws LoggerException
154
     */
155 2
    public function error($message, array $context = []): void
156
    {
157 2
        $this->addMessage(self::ERROR, (string) $message, $context);
158 2
    }
159
160
    /**
161
     * System is unusable.
162
     *
163
     * @param string $message
164
     * @param array  $context
165
     *
166
     * @throws LoggerException
167
     */
168 1
    public function emergency($message, array $context = []): void
169
    {
170 1
        $this->addMessage(self::EMERGENCY, (string) $message, $context);
171 1
    }
172
173
    /**
174
     * Exclude certain adapters.
175
     *
176
     * @param array $adapters
177
     *
178
     * @return Logger
179
     */
180 1
    public function excludeAdapters(array $adapters = []): Logger
181
    {
182
        /**
183
         * Loop through what has been passed. Check these names with
184
         * the registered adapters. If they match, add them to the
185
         * this->excluded array
186
         */
187 1
        $registered = $this->adapters;
188
189
        /**
190
         * Loop through what has been passed. Check these names with
191
         * the registered adapters. If they match, add them to the
192
         * this->excluded array
193
         */
194 1
        foreach ($adapters as $adapter) {
195 1
            if (isset($registered[$adapter])) {
196 1
                $this->excluded[$adapter] = true;
197
            }
198
        }
199 1
        return $this;
200
    }
201
202
    /**
203
     * Returns an adapter from the stack
204
     *
205
     * @param string $name The name of the adapter
206
     *
207
     * @return AdapterInterface
208
     * @throws LoggerException
209
     */
210 11
    public function getAdapter(string $name): AdapterInterface
211
    {
212 11
        if (!isset($this->adapters[$name])) {
213 1
            throw new LoggerException("Adapter does not exist for this logger");
214
        }
215
216 10
        return $this->adapters[$name];
217
    }
218
219
    /**
220
     * Returns the adapter stack array
221
     *
222
     * @return AdapterInterface[]
223
     */
224 6
    public function getAdapters(): array
225
    {
226 6
        return $this->adapters;
227
    }
228
229
    /**
230
     * Returns the log level
231
     */
232 1
    public function getLogLevel(): int
233
    {
234 1
        return $this->logLevel;
235
    }
236
237
    /**
238
     * Returns the name of the logger
239
     */
240 1
    public function getName(): string
241
    {
242 1
        return $this->name;
243
    }
244
245
    /**
246
     * Interesting events.
247
     *
248
     * Example: User logs in, SQL logs.
249
     *
250
     * @param string $message
251
     * @param array  $context
252
     *
253
     * @throws LoggerException
254
     */
255 3
    public function info($message, array $context = []): void
256
    {
257 3
        $this->addMessage(self::INFO, (string) $message, $context);
258 2
    }
259
260
    /**
261
     * Logs with an arbitrary level.
262
     *
263
     * @param mixed  $level
264
     * @param string $message
265
     * @param array  $context
266
     *
267
     * @throws LoggerException
268
     */
269 4
    public function log($level, $message, array $context = []): void
270
    {
271 4
        $intLevel = $this->getLevelNumber($level);
272
273 4
        $this->addMessage($intLevel, (string) $message, $context);
274 4
    }
275
276
    /**
277
     * Normal but significant events.
278
     *
279
     * @param string $message
280
     * @param array  $context
281
     *
282
     * @throws LoggerException
283
     */
284 1
    public function notice($message, array $context = []): void
285
    {
286 1
        $this->addMessage(self::NOTICE, (string) $message, $context);
287 1
    }
288
289
    /**
290
     * Removes an adapter from the stack
291
     *
292
     * @param string $name The name of the adapter
293
     *
294
     * @return Logger
295
     * @throws LoggerException
296
     */
297 2
    public function removeAdapter(string $name): Logger
298
    {
299 2
        if (!isset($this->adapters[$name])) {
300 1
            throw new LoggerException("Adapter does not exist for this logger");
301
        }
302
303 1
        unset($this->adapters[$name]);
304
305 1
        return $this;
306
    }
307
308
    /**
309
     * Sets the adapters stack overriding what is already there
310
     *
311
     * @param array $adapters An array of adapters
312
     *
313
     * @return Logger
314
     */
315 27
    public function setAdapters(array $adapters): Logger
316
    {
317 27
        $this->adapters = $adapters;
318
319 27
        return $this;
320
    }
321
322
    /**
323
     * Sets the adapters stack overriding what is already there
324
     *
325
     * @param int $level
326
     *
327
     * @return Logger
328
     */
329 2
    public function setLogLevel(int $level): Logger
330
    {
331 2
        $levels         = $this->getLevels();
332 2
        $this->logLevel = isset($levels[$level]) ? $level : self::CUSTOM;
333
334 2
        return $this;
335
    }
336
337
    /**
338
     * LoggerExceptional occurrences that are not errors.
339
     *
340
     * Example: Use of deprecated APIs, poor use of an API, undesirable things
341
     * that are not necessarily wrong.
342
     *
343
     * @param string $message
344
     * @param array  $context
345
     *
346
     * @throws LoggerException
347
     */
348 1
    public function warning($message, array $context = []): void
349
    {
350 1
        $this->addMessage(self::WARNING, (string) $message, $context);
351 1
    }
352
353
    /**
354
     * Adds a message to each handler for processing
355
     *
356
     * @param int    $level
357
     * @param string $message
358
     * @param array  $context
359
     *
360
     * @return bool
361
     * @throws LoggerException
362
     */
363 16
    protected function addMessage(int $level, string $message, array $context = []): bool
364
    {
365 16
        if ($this->logLevel >= $level) {
366 16
            if (count($this->adapters) === 0) {
367 1
                throw new LoggerException("No adapters specified");
368
            }
369
370 15
            $levels    = $this->getLevels();
371 15
            $levelName = Arr::get($levels, $level, self::CUSTOM);
372
373 15
            $item = new Item($message, $levelName, $level, time(), $context);
374
375
            /**
376
             * Log only if the key does not exist in the excluded ones
377
             */
378 15
            foreach ($this->adapters as $name => $adapter) {
379 15
                if (!isset($this->excluded[$name])) {
380 15
                    if ($adapter->inTransaction()) {
381 1
                        $adapter->add($item);
382
                    } else {
383 15
                        $adapter->process($item);
384
                    }
385
                }
386
            }
387
388
            /**
389
             * Clear the excluded array since we made the call now
390
             */
391 15
            $this->excluded = [];
392
        }
393
394 15
        return true;
395
    }
396
397
    /**
398
     * Returns an array of log levels with integer to string conversion
399
     */
400 16
    protected function getLevels(): array
401
    {
402
        return [
403 16
            self::ALERT     => "alert",
404 16
            self::CRITICAL  => "critical",
405 16
            self::DEBUG     => "debug",
406 16
            self::EMERGENCY => "emergency",
407 16
            self::ERROR     => "error",
408 16
            self::INFO      => "info",
409 16
            self::NOTICE    => "notice",
410 16
            self::WARNING   => "warning",
411 16
            self::CUSTOM    => "custom",
412
        ];
413
    }
414
415
    /**
416
     * Converts the level from string/word to an integer
417
     *
418
     * @param mixed $level
419
     *
420
     * @return int
421
     */
422 4
    private function getLevelNumber($level): int
423
    {
424 4
        if (is_string($level)) {
425 2
            $levelName = mb_strtolower($level);
426 2
            $levels    = array_flip($this->getLevels());
427
428 2
            if (isset($levels[$levelName])) {
429 2
                return $levels[$levelName];
430
            }
431 4
        } elseif (is_numeric($level)) {
432 4
            $levels = $this->getLevels();
433
434 4
            if (isset($levels[$level])) {
435 4
                return (int) $level;
436
            }
437
        }
438
439 2
        return self::CUSTOM;
440
    }
441
}
442