Skip to content

Commit c293d6e

Browse files
committed
Use driver spec levels in PsrLogAdapter::writeLog()
This also refactors writeLog() to call PSR loggers directly instead of forwarding to LogSubscriber::log().
1 parent 4370f91 commit c293d6e

File tree

3 files changed

+101
-30
lines changed

3 files changed

+101
-30
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@
1515
"ext-json": "*",
1616
"ext-mongodb": "^1.17.0",
1717
"jean85/pretty-package-versions": "^2.0.1",
18+
"psr/log": "^1.1.4|^2|^3",
1819
"symfony/polyfill-php73": "^1.27",
1920
"symfony/polyfill-php80": "^1.27",
2021
"symfony/polyfill-php81": "^1.27"
2122
},
2223
"require-dev": {
2324
"doctrine/coding-standard": "^11.1",
2425
"phpbench/phpbench": "^1.2",
25-
"psr/log": "^1.1.4|^2|^3",
2626
"rector/rector": "^0.16.0",
2727
"squizlabs/php_codesniffer": "^3.7",
2828
"symfony/phpunit-bridge": "^5.2",

src/PsrLogAdapter.php

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,36 @@
2929

3030
final class PsrLogAdapter implements LogSubscriber
3131
{
32+
/** @internal */
33+
public const LEVEL_EMERGENCY = 0;
34+
public const LEVEL_ALERT = 1;
35+
public const LEVEL_CRITICAL = 2;
36+
public const LEVEL_ERROR = 3;
37+
public const LEVEL_WARN = 4;
38+
public const LEVEL_NOTICE = 5;
39+
public const LEVEL_INFO = 6;
40+
public const LEVEL_DEBUG = 7;
41+
public const LEVEL_TRACE = 8;
42+
3243
private static ?self $instance = null;
3344

3445
/** @psalm-var SplObjectStorage<LoggerInterface, null> */
3546
private SplObjectStorage $loggers;
3647

37-
private const PSR_LEVELS = [
48+
private const SPEC_TO_PSR = [
49+
self::LEVEL_EMERGENCY => LogLevel::EMERGENCY,
50+
self::LEVEL_ALERT => LogLevel::ALERT,
51+
self::LEVEL_CRITICAL => LogLevel::CRITICAL,
52+
self::LEVEL_ERROR => LogLevel::ERROR,
53+
self::LEVEL_WARN => LogLevel::WARNING,
54+
self::LEVEL_NOTICE => LogLevel::NOTICE,
55+
self::LEVEL_INFO => LogLevel::INFO,
56+
self::LEVEL_DEBUG => LogLevel::DEBUG,
57+
// PSR does not define a "trace" level, so map it to "debug"
58+
self::LEVEL_TRACE => LogLevel::DEBUG,
59+
];
60+
61+
private const MONGOC_TO_PSR = [
3862
LogSubscriber::LEVEL_ERROR => LogLevel::ERROR,
3963
/* libmongoc considers "critical" less severe than "error" so map it to
4064
* "error" in the PSR logger. */
@@ -65,26 +89,26 @@ public static function removeLogger(LoggerInterface $logger): void
6589
}
6690

6791
/**
68-
* Pipes a log message from PHPC to all registered PSR loggers.
92+
* Forwards a log message from libmongoc/PHPC to all registered PSR loggers.
6993
*
7094
* @internal
7195
* @see LogSubscriber::log()
7296
*/
73-
public function log(int $level, string $domain, string $message): void
97+
public function log(int $mongocLevel, string $domain, string $message): void
7498
{
75-
if (! isset(self::PSR_LEVELS[$level])) {
99+
if (! isset(self::MONGOC_TO_PSR[$mongocLevel])) {
76100
throw new UnexpectedValueException(sprintf(
77101
'Expected level to be >= %d and <= %d, %d given for domain "%s" and message: %s',
78102
LogSubscriber::LEVEL_ERROR,
79103
LogSubscriber::LEVEL_DEBUG,
80-
$level,
104+
$mongocLevel,
81105
$domain,
82106
$message,
83107
));
84108
}
85109

86110
$instance = self::getInstance();
87-
$psrLevel = self::PSR_LEVELS[$level];
111+
$psrLevel = self::MONGOC_TO_PSR[$mongocLevel];
88112
$context = ['domain' => $domain];
89113

90114
foreach ($instance->loggers as $logger) {
@@ -97,9 +121,26 @@ public function log(int $level, string $domain, string $message): void
97121
*
98122
* @internal
99123
*/
100-
public static function writeLog(int $level, string $domain, string $message): void
124+
public static function writeLog(string $specLevel, string $domain, string $message): void
101125
{
102-
self::getInstance()->log($level, $domain, $message);
126+
if (! isset(self::SPEC_TO_PSR[$specLevel])) {
127+
throw new UnexpectedValueException(sprintf(
128+
'Expected level to be >= %d and <= %d, %d given for domain "%s" and message: %s',
129+
self::LEVEL_EMERGENCY,
130+
self::LEVEL_TRACE,
131+
$specLevel,
132+
$domain,
133+
$message,
134+
));
135+
}
136+
137+
$instance = self::getInstance();
138+
$psrLevel = self::SPEC_TO_PSR[$specLevel];
139+
$context = ['domain' => $domain];
140+
141+
foreach ($instance->loggers as $logger) {
142+
$logger->log($psrLevel, $message, $context);
143+
}
103144
}
104145

105146
private function __construct()

tests/PsrLogAdapterTest.php

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Psr\Log\LogLevel;
1212

1313
use function func_get_args;
14+
use function MongoDB\Driver\Monitoring\mongoc_log;
1415
use function sprintf;
1516

1617
class PsrLogAdapterTest extends BaseTestCase
@@ -20,47 +21,76 @@ class PsrLogAdapterTest extends BaseTestCase
2021
public function setUp(): void
2122
{
2223
$this->logger = $this->createTestPsrLogger();
24+
25+
PsrLogAdapter::addLogger($this->logger);
2326
}
2427

2528
public function tearDown(): void
2629
{
2730
PsrLogAdapter::removeLogger($this->logger);
2831
}
2932

33+
public function testLog(): void
34+
{
35+
/* This uses PHPC's internal mongoc_log() function to write messages
36+
* directly to libmongoc. Those messages are then relayed to
37+
* PsrLogAdapter and forwarded to each registered PSR logger.
38+
*
39+
* Note: it's not possible to test PsrLogAdapter::log() with an invalid
40+
* level since mongoc_log() already validates its level parameter. */
41+
mongoc_log(LogSubscriber::LEVEL_ERROR, 'domain1', 'error');
42+
mongoc_log(LogSubscriber::LEVEL_CRITICAL, 'domain2', 'critical');
43+
mongoc_log(LogSubscriber::LEVEL_WARNING, 'domain3', 'warning');
44+
mongoc_log(LogSubscriber::LEVEL_MESSAGE, 'domain4', 'message');
45+
mongoc_log(LogSubscriber::LEVEL_INFO, 'domain5', 'info');
46+
mongoc_log(LogSubscriber::LEVEL_DEBUG, 'domain6', 'debug');
47+
48+
$expectedLogs = [
49+
[LogLevel::ERROR, 'error', ['domain' => 'domain1']],
50+
[LogLevel::ERROR, 'critical', ['domain' => 'domain2']],
51+
[LogLevel::WARNING, 'warning', ['domain' => 'domain3']],
52+
[LogLevel::NOTICE, 'message', ['domain' => 'domain4']],
53+
[LogLevel::INFO, 'info', ['domain' => 'domain5']],
54+
[LogLevel::DEBUG, 'debug', ['domain' => 'domain6']],
55+
];
56+
57+
$this->assertSame($this->logger->logs, $expectedLogs);
58+
}
59+
3060
/**
3161
* @testWith [-1]
32-
* [6]
62+
* [9]
3363
*/
3464
public function testWriteLogWithInvalidLevel(int $level): void
3565
{
3666
$this->expectException(UnexpectedValueException::class);
37-
$this->expectExceptionMessage(sprintf('Expected level to be >= 0 and <= 5, %d given for domain "domain" and message: message', $level));
67+
$this->expectExceptionMessage(sprintf('Expected level to be >= 0 and <= 8, %d given for domain "domain" and message: message', $level));
3868

3969
PsrLogAdapter::writeLog($level, 'domain', 'message');
4070
}
4171

42-
public function testWriteLogMapsDriverLogLevelsToPsrLogLevels(): void
72+
public function testWriteLog(): void
4373
{
44-
PsrLogAdapter::addLogger($this->logger);
45-
46-
$domain = 'domain';
47-
48-
PsrLogAdapter::writeLog(LogSubscriber::LEVEL_ERROR, $domain, 'error');
49-
PsrLogAdapter::writeLog(LogSubscriber::LEVEL_CRITICAL, $domain, 'critical');
50-
PsrLogAdapter::writeLog(LogSubscriber::LEVEL_WARNING, $domain, 'warning');
51-
PsrLogAdapter::writeLog(LogSubscriber::LEVEL_MESSAGE, $domain, 'message');
52-
PsrLogAdapter::writeLog(LogSubscriber::LEVEL_INFO, $domain, 'info');
53-
PsrLogAdapter::writeLog(LogSubscriber::LEVEL_DEBUG, $domain, 'debug');
54-
55-
$context = ['domain' => $domain];
74+
PsrLogAdapter::writeLog(PsrLogAdapter::LEVEL_EMERGENCY, 'domain1', 'emergency');
75+
PsrLogAdapter::writeLog(PsrLogAdapter::LEVEL_ALERT, 'domain2', 'alert');
76+
PsrLogAdapter::writeLog(PsrLogAdapter::LEVEL_CRITICAL, 'domain3', 'critical');
77+
PsrLogAdapter::writeLog(PsrLogAdapter::LEVEL_ERROR, 'domain4', 'error');
78+
PsrLogAdapter::writeLog(PsrLogAdapter::LEVEL_WARN, 'domain5', 'warn');
79+
PsrLogAdapter::writeLog(PsrLogAdapter::LEVEL_NOTICE, 'domain6', 'notice');
80+
PsrLogAdapter::writeLog(PsrLogAdapter::LEVEL_INFO, 'domain7', 'info');
81+
PsrLogAdapter::writeLog(PsrLogAdapter::LEVEL_DEBUG, 'domain8', 'debug');
82+
PsrLogAdapter::writeLog(PsrLogAdapter::LEVEL_TRACE, 'domain9', 'trace');
5683

5784
$expectedLogs = [
58-
[LogLevel::ERROR, 'error', $context],
59-
[LogLevel::ERROR, 'critical', $context],
60-
[LogLevel::WARNING, 'warning', $context],
61-
[LogLevel::NOTICE, 'message', $context],
62-
[LogLevel::INFO, 'info', $context],
63-
[LogLevel::DEBUG, 'debug', $context],
85+
[LogLevel::EMERGENCY, 'emergency', ['domain' => 'domain1']],
86+
[LogLevel::ALERT, 'alert', ['domain' => 'domain2']],
87+
[LogLevel::CRITICAL, 'critical', ['domain' => 'domain3']],
88+
[LogLevel::ERROR, 'error', ['domain' => 'domain4']],
89+
[LogLevel::WARNING, 'warn', ['domain' => 'domain5']],
90+
[LogLevel::NOTICE, 'notice', ['domain' => 'domain6']],
91+
[LogLevel::INFO, 'info', ['domain' => 'domain7']],
92+
[LogLevel::DEBUG, 'debug', ['domain' => 'domain8']],
93+
[LogLevel::DEBUG, 'trace', ['domain' => 'domain9']],
6494
];
6595

6696
$this->assertSame($this->logger->logs, $expectedLogs);

0 commit comments

Comments
 (0)