Bladeren bron

Merge pull request #1587 from nicolas-grekas/psr-log2

Allow psr/log 2.0
Jordi Boggiano 4 jaren geleden
bovenliggende
commit
a4e10e8e9e

+ 11 - 5
.github/workflows/continuous-integration.yml

@@ -58,18 +58,24 @@ jobs:
       - name: Add require for mongodb/mongodb to make tests runnable
         run: 'composer require ${{ env.COMPOSER_FLAGS }} mongodb/mongodb --dev --no-update'
 
-      # This does not affect runtime, only tests were fixed in psr/log 1.1.2 so it's
-      # ok to require this only when running tests
-      - name: Bump required version of psr/log for tests purposes to fix the --prefer-lowest builds
-        run: 'composer require ${{ env.COMPOSER_FLAGS }} psr/log:^1.1.2 --no-update'
-
       - name: "Handle lowest dependencies update"
         if: "contains(matrix.dependencies, 'lowest')"
         run: "echo \"COMPOSER_FLAGS=$COMPOSER_FLAGS --prefer-lowest\" >> $GITHUB_ENV"
 
+      - name: "Ensure psr/log v2 is installed"
+        if: "contains(matrix.dependencies, 'highest') && matrix.php-version >= '8.0'"
+        run: composer require -W psr/log:^2
+
       - name: "Install latest dependencies"
         run: |
           composer update ${{ env.COMPOSER_FLAGS }}
 
       - name: "Run tests"
         run: "composer exec phpunit -- --verbose"
+
+      - name: "Run tests with rollbar"
+        run: |
+          composer require psr/log:'^1.1|^2' --no-update
+          composer require rollbar/rollbar:^1.3 --no-update
+          composer update -W ${{ env.COMPOSER_FLAGS }}
+          composer exec phpunit -- --verbose --filter Rollbar

+ 3 - 4
composer.json

@@ -14,7 +14,7 @@
     ],
     "require": {
         "php": ">=7.2",
-        "psr/log": "^1.0.1"
+        "psr/log": "^1.0.1 || ^2.0"
     },
     "require-dev": {
         "aws/aws-sdk-php": "^2.4.9 || ^3.0",
@@ -27,8 +27,7 @@
         "phpspec/prophecy": "^1.6.1",
         "phpunit/phpunit": "^8.5",
         "predis/predis": "^1.1",
-        "rollbar/rollbar": "^1.3",
-        "ruflin/elastica": ">=0.90 <7.0.1",
+        "ruflin/elastica": ">=0.90@dev",
         "swiftmailer/swiftmailer": "^5.3|^6.0",
         "phpstan/phpstan": "^0.12.91"
     },
@@ -56,7 +55,7 @@
         "psr-4": {"Monolog\\": "tests/Monolog"}
     },
     "provide": {
-        "psr/log-implementation": "1.0.0"
+        "psr/log-implementation": "1.0.0 || 2.0.0"
     },
     "extra": {
         "branch-alias": {

+ 3 - 0
phpstan.neon.dist

@@ -35,3 +35,6 @@ parameters:
         - '#::popProcessor\(\) should return callable#'
         - '#Parameter \#1 \$ of callable \(callable\(Monolog\\Handler\\Record\): Monolog\\Handler\\Record\)#'
         - '#is incompatible with native type array.#'
+
+        # can be removed when https://github.com/rollbar/rollbar-php/pull/536 will be merged
+        - '#Rollbar\\RollbarLogger#'

+ 2 - 0
tests/Monolog/Handler/RollbarHandlerTest.php

@@ -22,6 +22,8 @@ use Rollbar\RollbarLogger;
  * @see    https://rollbar.com/docs/notifier/rollbar-php/
  *
  * @coversDefaultClass Monolog\Handler\RollbarHandler
+ *
+ * @requires function \Rollbar\RollbarLogger::__construct
  */
 class RollbarHandlerTest extends TestCase
 {

+ 127 - 3
tests/Monolog/PsrLogCompatTest.php

@@ -11,16 +11,21 @@
 
 namespace Monolog;
 
+use DateTimeZone;
 use Monolog\Handler\TestHandler;
 use Monolog\Formatter\LineFormatter;
 use Monolog\Processor\PsrLogMessageProcessor;
+use PHPUnit\Framework\TestCase;
+use Psr\Log\InvalidArgumentException;
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
 use Psr\Log\Test\LoggerInterfaceTest;
 
-class PsrLogCompatTest extends LoggerInterfaceTest
+class PsrLogCompatTest extends TestCase
 {
     private $handler;
 
-    public function getLogger()
+    public function getLogger(): LoggerInterface
     {
         $logger = new Logger('foo');
         $logger->pushHandler($handler = new TestHandler);
@@ -32,7 +37,7 @@ class PsrLogCompatTest extends LoggerInterfaceTest
         return $logger;
     }
 
-    public function getLogs()
+    public function getLogs(): array
     {
         $convert = function ($record) {
             $lower = function ($match) {
@@ -44,4 +49,123 @@ class PsrLogCompatTest extends LoggerInterfaceTest
 
         return array_map($convert, $this->handler->getRecords());
     }
+
+    public function testImplements()
+    {
+        $this->assertInstanceOf(LoggerInterface::class, $this->getLogger());
+    }
+
+    /**
+     * @dataProvider provideLevelsAndMessages
+     */
+    public function testLogsAtAllLevels($level, $message)
+    {
+        $logger = $this->getLogger();
+        $logger->{$level}($message, array('user' => 'Bob'));
+        $logger->log($level, $message, array('user' => 'Bob'));
+
+        $expected = array(
+            "$level message of level $level with context: Bob",
+            "$level message of level $level with context: Bob",
+        );
+        $this->assertEquals($expected, $this->getLogs());
+    }
+
+    public function provideLevelsAndMessages()
+    {
+        return array(
+            LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'),
+            LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'),
+            LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'),
+            LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'),
+            LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'),
+            LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'),
+            LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'),
+            LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'),
+        );
+    }
+
+    public function testThrowsOnInvalidLevel()
+    {
+        $logger = $this->getLogger();
+
+        $this->expectException(InvalidArgumentException::class);
+        $logger->log('invalid level', 'Foo');
+    }
+
+    public function testContextReplacement()
+    {
+        $logger = $this->getLogger();
+        $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar'));
+
+        $expected = array('info {Message {nothing} Bob Bar a}');
+        $this->assertEquals($expected, $this->getLogs());
+    }
+
+    public function testObjectCastToString()
+    {
+        $string = uniqid('DUMMY');
+        $dummy = $this->createStringable($string);
+        $dummy->expects($this->once())
+            ->method('__toString');
+
+        $this->getLogger()->warning($dummy);
+
+        $expected = array("warning $string");
+        $this->assertEquals($expected, $this->getLogs());
+    }
+
+    public function testContextCanContainAnything()
+    {
+        $closed = fopen('php://memory', 'r');
+        fclose($closed);
+
+        $context = array(
+            'bool' => true,
+            'null' => null,
+            'string' => 'Foo',
+            'int' => 0,
+            'float' => 0.5,
+            'nested' => array('with object' => $this->createStringable()),
+            'object' => new \DateTime('now', new DateTimeZone('Europe/London')),
+            'resource' => fopen('php://memory', 'r'),
+            'closed' => $closed,
+        );
+
+        $this->getLogger()->warning('Crazy context data', $context);
+
+        $expected = array('warning Crazy context data');
+        $this->assertEquals($expected, $this->getLogs());
+    }
+
+    public function testContextExceptionKeyCanBeExceptionOrOtherValues()
+    {
+        $logger = $this->getLogger();
+        $logger->warning('Random message', array('exception' => 'oops'));
+        $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail')));
+
+        $expected = array(
+            'warning Random message',
+            'critical Uncaught Exception!'
+        );
+        $this->assertEquals($expected, $this->getLogs());
+    }
+
+    /**
+     * Creates a mock of a `Stringable`.
+     *
+     * @param string $string The string that must be represented by the stringable.
+     * @return \PHPUnit_Framework_MockObject_MockObject A mock of an object that has a `__toString()` method.
+     */
+    protected function createStringable($string = '')
+    {
+        $mock = $this->getMockBuilder('Stringable')
+            ->setMethods(array('__toString'))
+            ->getMock();
+
+        $mock->method('__toString')
+            ->will($this->returnValue($string));
+
+        return $mock;
+    }
 }