1
0
mirror of https://github.com/Seldaek/monolog.git synced 2025-10-26 18:16:24 +01:00

Replace deprecated code in MongoDB classes and allow 2.0+ (#1998)

* Remove unused code path in MongoDBFormatter

Monolog already required mongodb/mongodb 1.8+ (and a related ext-mongodb version) so this code path was never used.

* Use Collection::getCollection() from mongodb/mongodb 1.21

The original selectCollection method is deprecated. Since Monolog itself requires PHP 8.1, it should be sane to rely on 1.21+, which shares the same requirement.

* Update class refs for MongoDB extension and library

* Conditionally use Collection getter by version

* Relax PHPLIB version requirement

* Use RequiresPhpExtension attribute to require ext-mongodb

* Import UTCDateTime class and revise var names
This commit is contained in:
Jeremy Mikola
2025-10-23 14:47:46 -04:00
committed by GitHub
parent fac282e8e7
commit 1297c4421b
5 changed files with 23 additions and 58 deletions

View File

@@ -24,7 +24,7 @@
"graylog2/gelf-php": "^1.4.2 || ^2.0",
"guzzlehttp/guzzle": "^7.4.5",
"guzzlehttp/psr7": "^2.2",
"mongodb/mongodb": "^1.8",
"mongodb/mongodb": "^1.8 || ^2.0",
"php-amqplib/php-amqplib": "~2.4 || ^3",
"php-console/php-console": "^3.1.8",
"phpstan/phpstan": "^2",

View File

@@ -25,7 +25,6 @@ class MongoDBFormatter implements FormatterInterface
{
private bool $exceptionTraceAsString;
private int $maxNestingLevel;
private bool $isLegacyMongoExt;
/**
* @param int $maxNestingLevel 0 means infinite nesting, the $record itself is level 1, $record->context is 2
@@ -35,8 +34,6 @@ class MongoDBFormatter implements FormatterInterface
{
$this->maxNestingLevel = max($maxNestingLevel, 0);
$this->exceptionTraceAsString = $exceptionTraceAsString;
$this->isLegacyMongoExt = \extension_loaded('mongodb') && version_compare((string) phpversion('mongodb'), '1.1.9', '<=');
}
/**
@@ -126,34 +123,7 @@ class MongoDBFormatter implements FormatterInterface
}
protected function formatDate(\DateTimeInterface $value, int $nestingLevel): UTCDateTime
{
if ($this->isLegacyMongoExt) {
return $this->legacyGetMongoDbDateTime($value);
}
return $this->getMongoDbDateTime($value);
}
private function getMongoDbDateTime(\DateTimeInterface $value): UTCDateTime
{
return new UTCDateTime((int) floor(((float) $value->format('U.u')) * 1000));
}
/**
* This is needed to support MongoDB Driver v1.19 and below
*
* See https://github.com/mongodb/mongo-php-driver/issues/426
*
* It can probably be removed in 2.1 or later once MongoDB's 1.2 is released and widely adopted
*/
private function legacyGetMongoDbDateTime(\DateTimeInterface $value): UTCDateTime
{
$milliseconds = floor(((float) $value->format('U.u')) * 1000);
$milliseconds = (PHP_INT_SIZE === 8) //64-bit OS?
? (int) $milliseconds
: (string) $milliseconds;
return new UTCDateTime($milliseconds);
}
}

View File

@@ -11,9 +11,10 @@
namespace Monolog\Handler;
use MongoDB\Client;
use MongoDB\Collection;
use MongoDB\Driver\BulkWrite;
use MongoDB\Driver\Manager;
use MongoDB\Client;
use Monolog\Level;
use Monolog\Formatter\FormatterInterface;
use Monolog\Formatter\MongoDBFormatter;
@@ -34,7 +35,7 @@ use Monolog\LogRecord;
*/
class MongoDBHandler extends AbstractProcessingHandler
{
private \MongoDB\Collection $collection;
private Collection $collection;
private Client|Manager $manager;
@@ -50,7 +51,7 @@ class MongoDBHandler extends AbstractProcessingHandler
public function __construct(Client|Manager $mongodb, string $database, string $collection, int|string|Level $level = Level::Debug, bool $bubble = true)
{
if ($mongodb instanceof Client) {
$this->collection = $mongodb->selectCollection($database, $collection);
$this->collection = method_exists($mongodb, 'getCollection') ? $mongodb->getCollection($database, $collection) : $mongodb->selectCollection($database, $collection);
} else {
$this->manager = $mongodb;
$this->namespace = $database . '.' . $collection;

View File

@@ -16,19 +16,14 @@ use MongoDB\BSON\Regex;
use MongoDB\BSON\UTCDateTime;
use Monolog\Level;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
/**
* @author Florian Plattner <me@florianplattner.de>
*/
#[RequiresPhpExtension('mongodb')]
class MongoDBFormatterTest extends \Monolog\Test\MonologTestCase
{
public function setUp(): void
{
if (!class_exists('MongoDB\BSON\UTCDateTime')) {
$this->markTestSkipped('ext-mongodb not installed');
}
}
public static function constructArgumentProvider()
{
return [
@@ -67,7 +62,7 @@ class MongoDBFormatterTest extends \Monolog\Test\MonologTestCase
$this->assertEquals(Level::Warning->value, $formattedRecord['level']);
$this->assertEquals(Level::Warning->getName(), $formattedRecord['level_name']);
$this->assertEquals('test', $formattedRecord['channel']);
$this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $formattedRecord['datetime']);
$this->assertInstanceOf(UTCDateTime::class, $formattedRecord['datetime']);
$this->assertEquals('1453410690123', $formattedRecord['datetime']->__toString());
$this->assertEquals([], $formattedRecord['extra']);
}
@@ -96,7 +91,7 @@ class MongoDBFormatterTest extends \Monolog\Test\MonologTestCase
$formattedRecord = $formatter->format($record);
$this->assertCount(5, $formattedRecord['context']);
$this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $formattedRecord['context']['stuff']);
$this->assertInstanceOf(UTCDateTime::class, $formattedRecord['context']['stuff']);
$this->assertEquals('-29731710213', $formattedRecord['context']['stuff']->__toString());
$this->assertEquals(
[

View File

@@ -11,11 +11,13 @@
namespace Monolog\Handler;
use MongoDB\BSON\UTCDateTime;
use MongoDB\Client;
use MongoDB\Collection;
use MongoDB\Driver\Manager;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
/**
* @requires extension mongodb
*/
#[RequiresPhpExtension('mongodb')]
class MongoDBHandlerTest extends \Monolog\Test\MonologTestCase
{
public function testConstructorShouldThrowExceptionForInvalidMongo()
@@ -27,42 +29,39 @@ class MongoDBHandlerTest extends \Monolog\Test\MonologTestCase
public function testHandleWithLibraryClient()
{
if (!(class_exists('MongoDB\Client'))) {
if (!class_exists(Client::class)) {
$this->markTestSkipped('mongodb/mongodb not installed');
}
$mongodb = $this->getMockBuilder('MongoDB\Client')
$client = $this->getMockBuilder(Client::class)
->disableOriginalConstructor()
->getMock();
$collection = $this->getMockBuilder('MongoDB\Collection')
$collection = $this->getMockBuilder(Collection::class)
->disableOriginalConstructor()
->getMock();
$mongodb->expects($this->once())
->method('selectCollection')
$client->expects($this->once())
->method('getCollection')
->with('db', 'collection')
->willReturn($collection);
$record = $this->getRecord();
$expected = $record->toArray();
$expected['datetime'] = new \MongoDB\BSON\UTCDateTime((int) floor(((float) $record->datetime->format('U.u')) * 1000));
$expected['datetime'] = new UTCDateTime((int) floor(((float) $record->datetime->format('U.u')) * 1000));
$collection->expects($this->once())
->method('insertOne')
->with($expected);
$handler = new MongoDBHandler($mongodb, 'db', 'collection');
$handler = new MongoDBHandler($client, 'db', 'collection');
$handler->handle($record);
}
public function testHandleWithDriverManager()
{
/* This can become a unit test once ManagerInterface can be mocked.
* See: https://jira.mongodb.org/browse/PHPC-378
*/
$mongodb = new Manager('mongodb://localhost:27017');
$handler = new MongoDBHandler($mongodb, 'test', 'monolog');
$manager = new Manager('mongodb://localhost:27017');
$handler = new MongoDBHandler($manager, 'test', 'monolog');
$record = $this->getRecord();
try {