Passed
Push — main ( d71b68...a743f7 )
by Dimitri
08:12 queued 04:09
created

Logger::pushProcessor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 9
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 11
ccs 0
cts 0
cp 0
crap 2
rs 9.9666
1
<?php
2
3
/**
4
 * This file is part of Blitz PHP framework.
5
 *
6
 * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace BlitzPHP\Debug;
13
14
use InvalidArgumentException;
15
use Monolog\Formatter\HtmlFormatter;
16
use Monolog\Formatter\JsonFormatter;
17
use Monolog\Formatter\LineFormatter;
18
use Monolog\Formatter\NormalizerFormatter;
19
use Monolog\Formatter\ScalarFormatter;
20
use Monolog\Handler\BrowserConsoleHandler;
21
use Monolog\Handler\ChromePHPHandler;
22
use Monolog\Handler\ErrorLogHandler;
23
use Monolog\Handler\FirePHPHandler;
24
use Monolog\Handler\NativeMailerHandler;
25
use Monolog\Handler\RotatingFileHandler;
26
use Monolog\Handler\StreamHandler;
27
use Monolog\Handler\TelegramBotHandler;
28
use Monolog\Logger as MonologLogger;
29
use Monolog\Processor\HostnameProcessor;
30
use Monolog\Processor\IntrospectionProcessor;
31
use Monolog\Processor\MemoryUsageProcessor;
32
use Monolog\Processor\ProcessIdProcessor;
33
use Monolog\Processor\PsrLogMessageProcessor;
34
use Monolog\Processor\UidProcessor;
35
use Monolog\Processor\WebProcessor;
36
use Psr\Log\LoggerInterface;
37
use Psr\Log\LogLevel;
38
use stdClass;
39
use Stringable;
40
41
class Logger implements LoggerInterface
42
{
43
    /**
44
     * Options de configuration provenant de app/Config/log.php
45
     *
46
     * @var object
47
     */
48
    private $config;
49
50
    /**
51
     * Met en cache les appels de journalisation pour la barre de débogage.
52
     */
53
    public array $logCache = [];
54
55
    /**
56
     * Devrions-nous mettre en cache nos éléments enregistrés ?
57
     *
58
     * @var bool
59
     */
60
    protected $cacheLogs = false;
61
62
    /**
63
     * Instance monolog
64
     *
65
     * @var MonologLogger
66
     */
67
    private $monolog;
68
69
    public function __construct(bool $debug = BLITZ_DEBUG)
70
    {
71
        $this->config = (object) config('log');
72
73
        $this->monolog = new MonologLogger($this->config->name ?? 'application');
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on BlitzPHP\Config\Config.
Loading history...
74
75
        foreach (($this->config->handlers ?? []) as $handler => $options) {
0 ignored issues
show
Bug introduced by
The property handlers does not seem to exist on BlitzPHP\Config\Config.
Loading history...
76
            $this->pushHandler($handler, (object) $options);
77
        }
78
79
        foreach (($this->config->processors ?? []) as $processor) {
0 ignored issues
show
Bug introduced by
The property processors does not seem to exist on BlitzPHP\Config\Config.
Loading history...
80
            $this->pushProcessor($processor);
81
        }
82
83
        $this->cacheLogs = $debug;
84
        if ($this->cacheLogs) {
85
            $this->logCache = [];
86
        }
87
    }
88
89
    /**
90
     * {@inheritDoc}
91
     */
92
    public function emergency(string|Stringable $message, array $context = []): void
93
    {
94
        $this->log(LogLevel::EMERGENCY, $message, $context);
95
    }
96
97
    /**
98
     * {@inheritDoc}
99
     */
100
    public function alert(string|Stringable $message, array $context = []): void
101
    {
102
        $this->log(LogLevel::ALERT, $message, $context);
103
    }
104
105
    /**
106
     * {@inheritDoc}
107
     */
108
    public function critical(string|Stringable $message, array $context = []): void
109
    {
110
        $this->log(LogLevel::CRITICAL, $message, $context);
111
    }
112
113
    /**
114
     * {@inheritDoc}
115
     */
116
    public function error(string|Stringable $message, array $context = []): void
117
    {
118
        $this->log(LogLevel::ERROR, $message, $context);
119
    }
120
121
    /**
122
     * {@inheritDoc}
123
     */
124
    public function warning(string|Stringable $message, array $context = []): void
125
    {
126
        $this->log(LogLevel::WARNING, $message, $context);
127
    }
128
129
    /**
130
     * {@inheritDoc}
131
     */
132
    public function notice(string|Stringable $message, array $context = []): void
133
    {
134
        $this->log(LogLevel::NOTICE, $message, $context);
135
    }
136
137
    /**
138
     * {@inheritDoc}
139
     */
140
    public function info(string|Stringable $message, array $context = []): void
141
    {
142 19
        $this->log(LogLevel::INFO, $message, $context);
143
    }
144
145
    /**
146
     * {@inheritDoc}
147
     */
148
    public function debug(string|Stringable $message, array $context = []): void
149
    {
150
        $this->log(LogLevel::DEBUG, $message, $context);
151
    }
152
153
    /**
154
     * {@inheritDoc}
155
     */
156
    public function log($level, string|Stringable $message, array $context = []): void
157
    {
158 19
        $this->monolog->log($level, $message, $context);
159
160
        if ($this->cacheLogs) {
161
            $this->logCache[] = [
162
                'level' => $level,
163
                'msg'   => $message,
164 19
            ];
165
        }
166
    }
167
168
    /**
169
     * Ajoute les differents gestionnaires prise en charge par la configuration /app/Config/log.php
170
     */
171
    private function pushHandler(string $handler, stdClass $options)
172
    {
173
        match ($handler) {
174
            'error'    => $this->pushErrorHandler($options),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->pushErrorHandler($options) targeting BlitzPHP\Debug\Logger::pushErrorHandler() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
175
            'email'    => $this->pushEmailHandler($options),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->pushEmailHandler($options) targeting BlitzPHP\Debug\Logger::pushEmailHandler() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
176
            'telegram' => $this->pushTelegramHandler($options),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->pushTelegramHandler($options) targeting BlitzPHP\Debug\Logger::pushTelegramHandler() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
177
            'chrome'   => $this->pushChromeHandler($options),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->pushChromeHandler($options) targeting BlitzPHP\Debug\Logger::pushChromeHandler() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
178
            'firebug'  => $this->pushFirebugHandler($options),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->pushFirebugHandler($options) targeting BlitzPHP\Debug\Logger::pushFirebugHandler() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
179
            'browser'  => $this->pushBrowserHandler($options),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->pushBrowserHandler($options) targeting BlitzPHP\Debug\Logger::pushBrowserHandler() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
180
            default    => $this->pushFileHandler($options),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->pushFileHandler($options) targeting BlitzPHP\Debug\Logger::pushFileHandler() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
181
        };
182
    }
183
184
    /**
185
     * Ajoute un gestionnaire de log de type Fichier
186
     *
187
     * Enregistre les problèmes dans des fichiers de journalisation
188
     */
189
    private function pushFileHandler(stdClass $options): void
190
    {
191
        $directory = rtrim($options->path ?: LOG_PATH, DS) . DS;
192
        $filename  = strtolower($this->config->name ?: 'application');
193
        $extension = $options->extension ?: '.log';
194
195
        if (($options->dayly_rotation ?: true) === true) {
196
            $handler = new RotatingFileHandler($directory . $filename . $extension, $options->max_files ?: 0, $options->level ?: LogLevel::DEBUG, true, $options->permissions ?: 644);
197
        } else {
198
            $handler = new StreamHandler($directory . $filename . $extension, $options->level ?: LogLevel::DEBUG, true, $options->permissions ?: 644);
199
        }
200
201
        $this->monolog->pushHandler(
202
            $this->setFormatter($handler, ['json', 'line', 'scalar', 'normalizer'], $options->format)
203
        );
204
    }
205
206
    /**
207
     * Ajoute un gestionnaire de log de type PHP error_log
208
     *
209
     * Enregistre les problèmes dans la fonction PHP error_log().
210
     */
211
    private function pushErrorHandler(stdClass $options): void
212
    {
213
        $handler = new ErrorLogHandler($options->type ?: ErrorLogHandler::OPERATING_SYSTEM, $options->level ?: LogLevel::DEBUG);
214
215
        $this->monolog->pushHandler(
216
            $this->setFormatter($handler, ['json', 'line'], $options->format)
217
        );
218
    }
219
220
    /**
221
     * Ajoute un gestionnaire de log de type Email
222
     *
223
     * Envoi un email à l'administrateur en cas de problème
224
     */
225
    private function pushEmailHandler(stdClass $options): void
226
    {
227
        $handler = new NativeMailerHandler($options->to, $options->subject, $options->from, $options->level ?: LogLevel::ERROR);
228
229
        $this->monolog->pushHandler(
230
            $this->setFormatter($handler, ['html', 'json', 'line'], $options->format)
231
        );
232
    }
233
234
    private function pushTelegramHandler(stdClass $options): void
235
    {
236
        $handler = new TelegramBotHandler($options->api_key, $options->channel, $options->level ?: LogLevel::DEBUG);
237
238
        $this->monolog->pushHandler(
239
            $this->setFormatter($handler, [], $options->format)
240
        );
241
    }
242
243
    /**
244
     * Ajoute un gestionnaire de log pour chrome
245
     *
246
     * Affichera les log dans la console de chrome
247
     */
248
    private function pushChromeHandler(stdClass $options): void
249
    {
250
        $handler = new ChromePHPHandler($options->level ?: LogLevel::DEBUG);
251
252
        $this->monolog->pushHandler(
253
            $this->setFormatter($handler, [], $options->format)
254
        );
255
    }
256
257
    /**
258
     * Ajoute un gestionnaire de log pour firebug
259
     *
260
     * Affichera les log dans la console firebug
261
     */
262
    private function pushFirebugHandler(stdClass $options): void
263
    {
264
        $handler = new FirePHPHandler();
265
266
        $this->monolog->pushHandler(
267
            $this->setFormatter($handler, [], $options->format)
268
        );
269
    }
270
271
    /**
272
     * Ajoute un gestionnaire de log pour les navigateurs
273
     *
274
     * Affichera les log dans la console des navigateurs
275
     */
276
    private function pushBrowserHandler(stdClass $options): void
277
    {
278
        $handler = new BrowserConsoleHandler();
279
280
        $this->monolog->pushHandler(
281
            $this->setFormatter($handler, [], $options->format)
282
        );
283
    }
284
285
    /**
286
     * Ajoute les processeur au gestionnaire de log
287
     *
288
     * Un processor permet d'ajouter des méta données aux log générés
289
     */
290
    private function pushProcessor(string $processor)
291
    {
292
        match ($processor) {
293
            'web'           => $this->monolog->pushProcessor(new WebProcessor()),
294
            'introspection' => $this->monolog->pushProcessor(new IntrospectionProcessor()),
295
            'hostname'      => $this->monolog->pushProcessor(new HostnameProcessor()),
296
            'process_id'    => $this->monolog->pushProcessor(new ProcessIdProcessor()),
297
            'uid'           => $this->monolog->pushProcessor(new UidProcessor()),
298
            'memory_usage'  => $this->monolog->pushProcessor(new MemoryUsageProcessor()),
299
            'psr'           => $this->monolog->pushProcessor(new PsrLogMessageProcessor()),
300
            default         => throw new InvalidArgumentException('Invalid formatter for log processor. Accepts values: web/introspection/hostname/process_id/uid/memory_usage/psr'),
301
        };
302
    }
303
304
    /**
305
     * Definit le formateur des gestionnaire
306
     *
307
     * @param array $allowed Formats autorisés
308
     */
309
    private function setFormatter(object $handler, array $allowed, ?string $format = 'json'): object
310
    {
311
        if (! method_exists($handler, 'setFormatter')) {
312
            return $handler;
313
        }
314
315
        if ($format === null || $format === '') {
316
            $format = 'json';
317
        }
318
        if ($allowed !== [] && ! in_array($format, $allowed, true)) {
319
            throw new InvalidArgumentException('Invalid formatter for log file handler. Accepts values: ' . implode('/', $allowed));
320
        }
321
322
        switch ($format) {
323
            case 'json':
324
                $handler->setFormatter(new JsonFormatter());
325
                break;
326
327
            case 'line':
328
                $handler->setFormatter(new LineFormatter(null, $this->config->date_format ?? 'Y-m-d H:i:s'));
329
                break;
330
331
            case 'normalizer':
332
                $handler->setFormatter(new NormalizerFormatter($this->config->date_format ?? 'Y-m-d H:i:s'));
333
                break;
334
335
            case 'scalar':
336
                $handler->setFormatter(new ScalarFormatter($this->config->date_format ?? 'Y-m-d H:i:s'));
337
                break;
338
339
            case 'html':
340
                $handler->setFormatter(new HtmlFormatter($this->config->date_format ?? 'Y-m-d H:i:s'));
341
                break;
342
343
            default:
344
                break;
345
        }
346
347
        return $handler;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $handler returns the type object which is incompatible with the type-hinted return object.
Loading history...
348
    }
349
}
350