Skip to content

Commit 50b27c8

Browse files
authored
feat(log): emit MessageLogged when logs are written (#795)
1 parent 1cabe2d commit 50b27c8

File tree

8 files changed

+317
-120
lines changed

8 files changed

+317
-120
lines changed

src/Tempest/Log/src/GenericLogger.php

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44

55
namespace Tempest\Log;
66

7-
use Monolog\Level;
7+
use Monolog\Level as MonologLogLevel;
88
use Monolog\Logger as Monolog;
9+
use Psr\Log\LogLevel as PsrLogLevel;
910
use Stringable;
11+
use Tempest\EventBus\EventBus;
1012

1113
final class GenericLogger implements Logger
1214
{
@@ -15,64 +17,80 @@ final class GenericLogger implements Logger
1517

1618
public function __construct(
1719
private readonly LogConfig $logConfig,
20+
private readonly EventBus $eventBus,
1821
) {
1922
}
2023

2124
public function emergency(Stringable|string $message, array $context = []): void
2225
{
23-
$this->writeLog(Level::Emergency, $message, $context);
26+
$this->log(LogLevel::EMERGENCY, $message, $context);
2427
}
2528

2629
public function alert(Stringable|string $message, array $context = []): void
2730
{
28-
$this->writeLog(Level::Alert, $message, $context);
31+
$this->log(LogLevel::ALERT, $message, $context);
2932
}
3033

3134
public function critical(Stringable|string $message, array $context = []): void
3235
{
33-
$this->writeLog(Level::Critical, $message, $context);
36+
$this->log(LogLevel::CRITICAL, $message, $context);
3437
}
3538

3639
public function error(Stringable|string $message, array $context = []): void
3740
{
38-
$this->writeLog(Level::Error, $message, $context);
41+
$this->log(LogLevel::ERROR, $message, $context);
3942
}
4043

4144
public function warning(Stringable|string $message, array $context = []): void
4245
{
43-
$this->writeLog(Level::Warning, $message, $context);
46+
$this->log(LogLevel::WARNING, $message, $context);
4447
}
4548

4649
public function notice(Stringable|string $message, array $context = []): void
4750
{
48-
$this->writeLog(Level::Notice, $message, $context);
51+
$this->log(LogLevel::NOTICE, $message, $context);
4952
}
5053

5154
public function info(Stringable|string $message, array $context = []): void
5255
{
53-
$this->writeLog(Level::Info, $message, $context);
56+
$this->log(LogLevel::INFO, $message, $context);
5457
}
5558

5659
public function debug(Stringable|string $message, array $context = []): void
5760
{
58-
$this->writeLog(Level::Debug, $message, $context);
61+
$this->log(LogLevel::DEBUG, $message, $context);
5962
}
6063

64+
/** @param MonologLogLevel|LogLevel|string $level */
6165
public function log($level, Stringable|string $message, array $context = []): void
6266
{
63-
$level = Level::tryFrom($level) ?? Level::Info;
67+
if (! $level instanceof MonologLogLevel) {
68+
$level = match ($level) {
69+
LogLevel::EMERGENCY, PsrLogLevel::EMERGENCY => MonologLogLevel::Emergency,
70+
LogLevel::ALERT, PsrLogLevel::ALERT => MonologLogLevel::Alert,
71+
LogLevel::CRITICAL, PsrLogLevel::CRITICAL => MonologLogLevel::Critical,
72+
LogLevel::ERROR, PsrLogLevel::ERROR => MonologLogLevel::Error,
73+
LogLevel::WARNING, PsrLogLevel::WARNING => MonologLogLevel::Warning,
74+
LogLevel::NOTICE, PsrLogLevel::NOTICE => MonologLogLevel::Notice,
75+
LogLevel::INFO, PsrLogLevel::INFO => MonologLogLevel::Info,
76+
LogLevel::DEBUG, PsrLogLevel::DEBUG => MonologLogLevel::Debug,
77+
default => MonologLogLevel::Info
78+
};
79+
}
6480

6581
$this->writeLog($level, $message, $context);
82+
83+
$this->eventBus->dispatch(new MessageLogged(LogLevel::fromMonolog($level), $message, $context));
6684
}
6785

68-
private function writeLog(Level $level, string $message, array $context): void
86+
private function writeLog(MonologLogLevel $level, string $message, array $context): void
6987
{
7088
foreach ($this->logConfig->channels as $channel) {
7189
$this->resolveDriver($channel, $level)->log($level, $message, $context);
7290
}
7391
}
7492

75-
private function resolveDriver(LogChannel $channel, Level $level): Monolog
93+
private function resolveDriver(LogChannel $channel, MonologLogLevel $level): Monolog
7694
{
7795
if (! isset($this->drivers[spl_object_id($channel)])) {
7896
$this->drivers[spl_object_id($channel)] = new Monolog(

src/Tempest/Log/src/LogLevel.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Log;
6+
7+
use Monolog\Level;
8+
9+
enum LogLevel: string
10+
{
11+
/**
12+
* System is unusable.
13+
*/
14+
case EMERGENCY = 'emergency';
15+
16+
/**
17+
* Errors that require action immediately.
18+
*/
19+
case ALERT = 'alert';
20+
21+
/**
22+
* Important, unexpected errors that require attention.
23+
*/
24+
case CRITICAL = 'critical';
25+
26+
/**
27+
* Runtime errors that do not require immediate action but should be monitored.
28+
*/
29+
case ERROR = 'error';
30+
31+
/**
32+
* Exceptional occurrences that are not errors.
33+
*/
34+
case WARNING = 'warning';
35+
36+
/**
37+
* Uncommon events.
38+
*/
39+
case NOTICE = 'notice';
40+
41+
/**
42+
* Miscellaneous events.
43+
*/
44+
case INFO = 'info';
45+
46+
/**
47+
* Detailed debug information.
48+
*/
49+
case DEBUG = 'debug';
50+
51+
public static function fromMonolog(Level $level): self
52+
{
53+
return match ($level) {
54+
Level::Emergency => self::EMERGENCY,
55+
Level::Alert => self::ALERT,
56+
Level::Critical => self::CRITICAL,
57+
Level::Error => self::ERROR,
58+
Level::Warning => self::WARNING,
59+
Level::Notice => self::NOTICE,
60+
Level::Info => self::INFO,
61+
Level::Debug => self::DEBUG,
62+
};
63+
}
64+
}

src/Tempest/Log/src/LoggerInitializer.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Tempest\Container\Container;
99
use Tempest\Container\Initializer;
1010
use Tempest\Container\Singleton;
11+
use Tempest\EventBus\EventBus;
1112

1213
final readonly class LoggerInitializer implements Initializer
1314
{
@@ -16,6 +17,7 @@ public function initialize(Container $container): LoggerInterface|Logger
1617
{
1718
return new GenericLogger(
1819
$container->get(LogConfig::class),
20+
$container->get(EventBus::class),
1921
);
2022
}
2123
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Log;
6+
7+
use Stringable;
8+
9+
final class MessageLogged
10+
{
11+
public function __construct(
12+
public LogLevel $level,
13+
public Stringable|string $message,
14+
public array $context = [],
15+
) {
16+
}
17+
}

src/Tempest/Log/tests/GenericLoggerTest.php

Lines changed: 0 additions & 108 deletions
This file was deleted.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Log\Tests;
6+
7+
use Monolog\Level;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use PHPUnit\Framework\TestCase;
10+
use Tempest\Log\LogLevel;
11+
12+
/**
13+
* @internal
14+
*/
15+
final class LogLevelTest extends TestCase
16+
{
17+
#[DataProvider('levelsProvider')]
18+
public function test_from_monolog(Level $level, LogLevel $expected): void
19+
{
20+
$this->assertSame($expected, LogLevel::fromMonolog($level));
21+
}
22+
23+
public static function levelsProvider(): array
24+
{
25+
return [
26+
[Level::Emergency, LogLevel::EMERGENCY],
27+
[Level::Alert, LogLevel::ALERT],
28+
[Level::Critical, LogLevel::CRITICAL],
29+
[Level::Error, LogLevel::ERROR],
30+
[Level::Warning, LogLevel::WARNING],
31+
[Level::Notice, LogLevel::NOTICE],
32+
[Level::Info, LogLevel::INFO],
33+
[Level::Debug, LogLevel::DEBUG],
34+
];
35+
}
36+
}

0 commit comments

Comments
 (0)