Lines 100.00% 18 / 18
Functions and Methods 100.00% 3 / 3
Classes and Traits 100.00% 1 / 1
Name Lines Functions and Methods CRAP Classes and Traits
LoggerFactory 100.00% 18 / 18 100.00% 3 / 3 5 100.00% 1 / 1
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 createStdoutLogger 100.00% 10 / 10 100.00% 1 / 1 1
 createFormatter 100.00% 7 / 7 100.00% 1 / 1 3
1<?php
2
3declare(strict_types=1);
4
5namespace Stewart\Runtime\Logging;
6
7use Monolog\Formatter\FormatterInterface;
8use Monolog\Formatter\JsonFormatter;
9use Monolog\Handler\FallbackGroupHandler;
10use Monolog\Handler\StreamHandler;
11use Monolog\Level;
12use Monolog\Logger;
13use Psr\Log\LoggerInterface;
14use Stewart\Runtime\Model\LogLevel;
15
16final readonly class LoggerFactory
17{
18    private const string LINE_FORMAT = "%datetime% %level_name% %message% %context% %extra%\n";
19
20    private const string LINE_DATE_FORMAT = 'Y-m-d H:i:s.vP';
21
22    public function __construct(
23        private string $logStreamUrl = 'php://stdout',
24        private string $logFallbackStreamUrl = 'php://stderr',
25    ) {}
26
27    public function createStdoutLogger(LogLevel $level = LogLevel::Info, LogFormat $format = LogFormat::Line): LoggerInterface
28    {
29        $threshold = Level::fromName($level->name);
30        // A failed write must not throw out of a log call, e.g. while the broker is stopping.
31        $handler = new FallbackGroupHandler([
32            new StreamHandler($this->logStreamUrl, $threshold),
33            new StreamHandler($this->logFallbackStreamUrl, $threshold),
34        ]);
35        $handler->setFormatter($this->createFormatter($format));
36
37        return new Logger('stewart')
38            ->pushHandler($handler)
39            ->pushProcessor(new ExceptionContextProcessor())
40            ->pushProcessor(new ProcessTimeZoneProcessor());
41    }
42
43    private function createFormatter(LogFormat $format): FormatterInterface
44    {
45        return match ($format) {
46            LogFormat::Json => new JsonFormatter(),
47            LogFormat::Line => new StackTraceLineFormatter(
48                format: self::LINE_FORMAT,
49                dateFormat: self::LINE_DATE_FORMAT,
50                allowInlineLineBreaks: true,
51                ignoreEmptyContextAndExtra: true,
52            ),
53        };
54    }
55}