-
Notifications
You must be signed in to change notification settings - Fork 263
Commit
Introduces an internal PsrLogAdapter class to connect PSR-3 loggers with PHPC. The internal class is exposed via addLogger and removeLogger functions. Bumps ext-mongodb dependency to 1.17-dev for PHPC-2180. Permit psr/log 1.x, 2.x, or 3.x for compatibility with PHP 7.4 and 8.0+.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
<?php | ||
/* | ||
* Copyright 2023-present MongoDB, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
namespace MongoDB; | ||
|
||
use MongoDB\Driver\Monitoring\LogSubscriber; | ||
use MongoDB\Exception\UnexpectedValueException; | ||
use Psr\Log\LoggerInterface; | ||
use Psr\Log\LogLevel; | ||
use SplObjectStorage; | ||
|
||
use function MongoDB\Driver\Monitoring\addSubscriber; | ||
use function MongoDB\Driver\Monitoring\removeSubscriber; | ||
use function sprintf; | ||
|
||
/** | ||
* Integrates libmongoc/PHPC logging with one or more PSR-3 loggers. | ||
* | ||
* This class is internal and should not be utilized by applications. Logging | ||
* should be configured via the add_logger() and remove_logger() functions. | ||
* | ||
* @internal | ||
*/ | ||
final class PsrLogAdapter implements LogSubscriber | ||
{ | ||
public const LEVEL_EMERGENCY = 0; | ||
public const LEVEL_ALERT = 1; | ||
public const LEVEL_CRITICAL = 2; | ||
Check failure on line 42 in src/PsrLogAdapter.php GitHub Actions / PsalmOverriddenInterfaceConstant
Check failure on line 42 in src/PsrLogAdapter.php GitHub Actions / PsalmInvalidClassConstantType
|
||
public const LEVEL_ERROR = 3; | ||
Check failure on line 43 in src/PsrLogAdapter.php GitHub Actions / PsalmOverriddenInterfaceConstant
Check failure on line 43 in src/PsrLogAdapter.php GitHub Actions / PsalmInvalidClassConstantType
|
||
public const LEVEL_WARN = 4; | ||
public const LEVEL_NOTICE = 5; | ||
public const LEVEL_INFO = 6; | ||
Check failure on line 46 in src/PsrLogAdapter.php GitHub Actions / PsalmOverriddenInterfaceConstant
Check failure on line 46 in src/PsrLogAdapter.php GitHub Actions / PsalmInvalidClassConstantType
|
||
public const LEVEL_DEBUG = 7; | ||
Check failure on line 47 in src/PsrLogAdapter.php GitHub Actions / PsalmOverriddenInterfaceConstant
Check failure on line 47 in src/PsrLogAdapter.php GitHub Actions / PsalmInvalidClassConstantType
|
||
public const LEVEL_TRACE = 8; | ||
|
||
private static ?self $instance = null; | ||
|
||
/** @psalm-var SplObjectStorage<LoggerInterface, null> */ | ||
private SplObjectStorage $loggers; | ||
|
||
private const SPEC_TO_PSR = [ | ||
self::LEVEL_EMERGENCY => LogLevel::EMERGENCY, | ||
self::LEVEL_ALERT => LogLevel::ALERT, | ||
self::LEVEL_CRITICAL => LogLevel::CRITICAL, | ||
self::LEVEL_ERROR => LogLevel::ERROR, | ||
self::LEVEL_WARN => LogLevel::WARNING, | ||
self::LEVEL_NOTICE => LogLevel::NOTICE, | ||
self::LEVEL_INFO => LogLevel::INFO, | ||
self::LEVEL_DEBUG => LogLevel::DEBUG, | ||
// PSR does not define a "trace" level, so map it to "debug" | ||
self::LEVEL_TRACE => LogLevel::DEBUG, | ||
]; | ||
|
||
private const MONGOC_TO_PSR = [ | ||
LogSubscriber::LEVEL_ERROR => LogLevel::ERROR, | ||
/* libmongoc considers "critical" less severe than "error" so map it to | ||
* "error" in the PSR logger. */ | ||
LogSubscriber::LEVEL_CRITICAL => LogLevel::ERROR, | ||
LogSubscriber::LEVEL_WARNING => LogLevel::WARNING, | ||
LogSubscriber::LEVEL_MESSAGE => LogLevel::NOTICE, | ||
LogSubscriber::LEVEL_INFO => LogLevel::INFO, | ||
LogSubscriber::LEVEL_DEBUG => LogLevel::DEBUG, | ||
]; | ||
|
||
public static function addLogger(LoggerInterface $logger): void | ||
{ | ||
$instance = self::getInstance(); | ||
|
||
$instance->loggers->attach($logger); | ||
|
||
addSubscriber($instance); | ||
} | ||
|
||
/** | ||
* Forwards a log message from libmongoc/PHPC to all registered PSR loggers. | ||
* | ||
* @see LogSubscriber::log() | ||
*/ | ||
public function log(int $mongocLevel, string $domain, string $message): void | ||
{ | ||
if (! isset(self::MONGOC_TO_PSR[$mongocLevel])) { | ||
throw new UnexpectedValueException(sprintf( | ||
'Expected level to be >= %d and <= %d, %d given for domain "%s" and message: %s', | ||
LogSubscriber::LEVEL_ERROR, | ||
LogSubscriber::LEVEL_DEBUG, | ||
$mongocLevel, | ||
$domain, | ||
$message, | ||
)); | ||
} | ||
|
||
$instance = self::getInstance(); | ||
$psrLevel = self::MONGOC_TO_PSR[$mongocLevel]; | ||
$context = ['domain' => $domain]; | ||
|
||
foreach ($instance->loggers as $logger) { | ||
$logger->log($psrLevel, $message, $context); | ||
} | ||
} | ||
|
||
public static function removeLogger(LoggerInterface $logger): void | ||
{ | ||
$instance = self::getInstance(); | ||
$instance->loggers->detach($logger); | ||
|
||
if ($instance->loggers->count() === 0) { | ||
removeSubscriber($instance); | ||
} | ||
} | ||
|
||
/** | ||
* Writes a log message to all registered PSR loggers. | ||
* | ||
* This function is intended for internal use within the library. | ||
*/ | ||
public static function writeLog(string $specLevel, string $domain, string $message): void | ||
{ | ||
if (! isset(self::SPEC_TO_PSR[$specLevel])) { | ||
Check failure on line 132 in src/PsrLogAdapter.php GitHub Actions / PsalmInvalidArrayOffset
|
||
throw new UnexpectedValueException(sprintf( | ||
'Expected level to be >= %d and <= %d, %d given for domain "%s" and message: %s', | ||
self::LEVEL_EMERGENCY, | ||
self::LEVEL_TRACE, | ||
$specLevel, | ||
$domain, | ||
$message, | ||
)); | ||
} | ||
|
||
$instance = self::getInstance(); | ||
$psrLevel = self::SPEC_TO_PSR[$specLevel]; | ||
$context = ['domain' => $domain]; | ||
|
||
foreach ($instance->loggers as $logger) { | ||
$logger->log($psrLevel, $message, $context); | ||
} | ||
} | ||
|
||
private function __construct() | ||
{ | ||
$this->loggers = new SplObjectStorage(); | ||
} | ||
|
||
private static function getInstance(): self | ||
{ | ||
return self::$instance ??= new self(); | ||
} | ||
} |