From 508df120fac348c1e7ed6e590d83c549fa95434e Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 8 Apr 2022 17:32:03 +0200 Subject: [PATCH 1/5] Make AsMonologProcessor compatible with PHP 7.2 --- src/Monolog/Attribute/AsMonologProcessor.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Attribute/AsMonologProcessor.php b/src/Monolog/Attribute/AsMonologProcessor.php index b52d0776..188bbb0d 100644 --- a/src/Monolog/Attribute/AsMonologProcessor.php +++ b/src/Monolog/Attribute/AsMonologProcessor.php @@ -22,15 +22,25 @@ namespace Monolog\Attribute; #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class AsMonologProcessor { + /** @var string|null */ + public $channel = null; + /** @var string|null */ + public $handler = null; + /** @var string|null */ + public $method = null; + /** * @param string|null $channel The logging channel the processor should be pushed to. * @param string|null $handler The handler the processor should be pushed to. * @param string|null $method The method that processes the records (if the attribute is used at the class level). */ public function __construct( - public ?string $channel = null, - public ?string $handler = null, - public ?string $method = null, + ?string $channel = null, + ?string $handler = null, + ?string $method = null ) { + $this->channel = $channel; + $this->handler = $handler; + $this->method = $method; } -} \ No newline at end of file +} From 4c43f12548a7ed757ce78388ab61fcbca9bf4bd7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 8 Apr 2022 17:32:35 +0200 Subject: [PATCH 2/5] Link attribute file again --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index cd260475..9e20a03e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -29,4 +29,4 @@ jobs: php-version: "${{ matrix.php-version }}" - name: "Lint PHP files" - run: "find src/ -type f -name '*.php' -not -name AsMonologProcessor.php -print0 | xargs -0 -L1 -P4 -- php -l -f" + run: "find src/ -type f -name '*.php' -print0 | xargs -0 -L1 -P4 -- php -l -f" From 4192345e260f1d51b365536199744b987e160edc Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 8 Apr 2022 17:43:54 +0200 Subject: [PATCH 3/5] Update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dcc7a14..eb4963ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### 2.5.0 (2022-04-08) + +* Added `callType` to IntrospectionProcessor (#1612) +* Fixed AsMonologProcessor syntax to be compatible with PHP 7.2 (#1651) + ### 2.4.0 (2022-03-14) * Added [`Monolog\LogRecord`](src/Monolog/LogRecord.php) interface that can be used to type-hint records like `array|\Monolog\LogRecord $record` to be forward compatible with the upcoming Monolog 3 changes From 4c7a12b0264f5d073343d34ae6d8b59c38304371 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 7 May 2022 13:05:55 +0200 Subject: [PATCH 4/5] Add SymfonyMailerHandler, deprecate SwiftMailerHandler (#1663) --- composer.json | 8 +- src/Monolog/Handler/SwiftMailerHandler.php | 3 + src/Monolog/Handler/SymfonyMailerHandler.php | 111 ++++++++++++++++++ .../Handler/SymfonyMailerHandlerTest.php | 100 ++++++++++++++++ 4 files changed, 219 insertions(+), 3 deletions(-) create mode 100644 src/Monolog/Handler/SymfonyMailerHandler.php create mode 100644 tests/Monolog/Handler/SymfonyMailerHandlerTest.php diff --git a/composer.json b/composer.json index b151c654..1c0a5c22 100644 --- a/composer.json +++ b/composer.json @@ -20,17 +20,19 @@ "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", "elasticsearch/elasticsearch": "^7", - "mongodb/mongodb": "^1.8", "graylog2/gelf-php": "^1.4.2", + "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.3", - "phpspec/prophecy": "^1.6.1", + "phpspec/prophecy": "^1.15", + "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3 || ^2 || ^3", "ruflin/elastica": ">=0.90@dev", "swiftmailer/swiftmailer": "^5.3|^6.0", - "phpstan/phpstan": "^0.12.91" + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" }, "suggest": { "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index be7e2a58..fae92514 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -24,6 +24,7 @@ use Swift; * @author Gyula Sallai * * @phpstan-import-type Record from \Monolog\Logger + * @deprecated Since Monolog 2.6. Use SymfonyMailerHandler instead. */ class SwiftMailerHandler extends MailHandler { @@ -42,6 +43,8 @@ class SwiftMailerHandler extends MailHandler { parent::__construct($level, $bubble); + @trigger_error('The SwiftMailerHandler is deprecated since Monolog 2.6. Use SymfonyMailerHandler instead.', E_USER_DEPRECATED); + $this->mailer = $mailer; $this->messageTemplate = $message; } diff --git a/src/Monolog/Handler/SymfonyMailerHandler.php b/src/Monolog/Handler/SymfonyMailerHandler.php new file mode 100644 index 00000000..130e6f1f --- /dev/null +++ b/src/Monolog/Handler/SymfonyMailerHandler.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Utils; +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\LineFormatter; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Mime\Email; + +/** + * SymfonyMailerHandler uses Symfony's Mailer component to send the emails + * + * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger + */ +class SymfonyMailerHandler extends MailHandler +{ + /** @var MailerInterface|TransportInterface */ + protected $mailer; + /** @var Email|callable(string, Record[]): Email */ + private $emailTemplate; + + /** + * @psalm-param Email|callable(string, Record[]): Email $email + * + * @param MailerInterface|TransportInterface $mailer The mailer to use + * @param callable|Email $email An email template, the subject/body will be replaced + */ + public function __construct($mailer, $email, $level = Logger::ERROR, bool $bubble = true) + { + parent::__construct($level, $bubble); + + $this->mailer = $mailer; + $this->emailTemplate = $email; + } + + /** + * {@inheritDoc} + */ + protected function send(string $content, array $records): void + { + $this->mailer->send($this->buildMessage($content, $records)); + } + + /** + * Gets the formatter for the Swift_Message subject. + * + * @param string|null $format The format of the subject + */ + protected function getSubjectFormatter(?string $format): FormatterInterface + { + return new LineFormatter($format); + } + + /** + * Creates instance of Email to be sent + * + * @param string $content formatted email body to be sent + * @param array $records Log records that formed the content + * + * @phpstan-param Record[] $records + */ + protected function buildMessage(string $content, array $records): Email + { + $message = null; + if ($this->emailTemplate instanceof Email) { + $message = clone $this->emailTemplate; + } elseif (is_callable($this->emailTemplate)) { + $message = ($this->emailTemplate)($content, $records); + } + + if (!$message instanceof Email) { + $record = reset($records); + throw new \InvalidArgumentException('Could not resolve message as instance of Email or a callable returning it' . ($record ? Utils::getRecordMessageForException($record) : '')); + } + + if ($records) { + $subjectFormatter = $this->getSubjectFormatter($message->getSubject()); + $message->subject($subjectFormatter->format($this->getHighestRecord($records))); + } + + if ($this->isHtmlBody($content)) { + if (null !== ($charset = $message->getHtmlCharset())) { + $message->html($content, $charset); + } else { + $message->html($content); + } + } else { + if (null !== ($charset = $message->getTextCharset())) { + $message->text($content, $charset); + } else { + $message->text($content); + } + } + + return $message->date(new \DateTimeImmutable()); + } +} diff --git a/tests/Monolog/Handler/SymfonyMailerHandlerTest.php b/tests/Monolog/Handler/SymfonyMailerHandlerTest.php new file mode 100644 index 00000000..af1e926a --- /dev/null +++ b/tests/Monolog/Handler/SymfonyMailerHandlerTest.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Test\TestCase; +use PHPUnit\Framework\MockObject\MockObject; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mime\Email; + +class SymfonyMailerHandlerTest extends TestCase +{ + /** @var MailerInterface&MockObject */ + private $mailer; + + public function setUp(): void + { + $this->mailer = $this + ->getMockBuilder(MailerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + } + + public function testMessageCreationIsLazyWhenUsingCallback() + { + $this->mailer->expects($this->never()) + ->method('send'); + + $callback = function () { + throw new \RuntimeException('Email creation callback should not have been called in this test'); + }; + $handler = new SymfonyMailerHandler($this->mailer, $callback); + + $records = [ + $this->getRecord(Logger::DEBUG), + $this->getRecord(Logger::INFO), + ]; + $handler->handleBatch($records); + } + + public function testMessageCanBeCustomizedGivenLoggedData() + { + // Wire Mailer to expect a specific Email with a customized Subject + $expectedMessage = new Email(); + $this->mailer->expects($this->once()) + ->method('send') + ->with($this->callback(function ($value) use ($expectedMessage) { + return $value instanceof Email + && $value->getSubject() === 'Emergency' + && $value === $expectedMessage; + })); + + // Callback dynamically changes subject based on number of logged records + $callback = function ($content, array $records) use ($expectedMessage) { + $subject = count($records) > 0 ? 'Emergency' : 'Normal'; + return $expectedMessage->subject($subject); + }; + $handler = new SymfonyMailerHandler($this->mailer, $callback); + + // Logging 1 record makes this an Emergency + $records = [ + $this->getRecord(Logger::EMERGENCY), + ]; + $handler->handleBatch($records); + } + + public function testMessageSubjectFormatting() + { + // Wire Mailer to expect a specific Email with a customized Subject + $messageTemplate = new Email(); + $messageTemplate->subject('Alert: %level_name% %message%'); + $receivedMessage = null; + + $this->mailer->expects($this->once()) + ->method('send') + ->with($this->callback(function ($value) use (&$receivedMessage) { + $receivedMessage = $value; + + return true; + })); + + $handler = new SymfonyMailerHandler($this->mailer, $messageTemplate); + + $records = [ + $this->getRecord(Logger::EMERGENCY), + ]; + $handler->handleBatch($records); + + $this->assertEquals('Alert: EMERGENCY test', $receivedMessage->getSubject()); + } +} From bd247659176eb4031163090cf8a85757537d2179 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 8 May 2022 22:23:46 +0200 Subject: [PATCH 5/5] ElasticSearch v8 support (#1662) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ElasticSearch v8 support * CI updates Co-authored-by: Thomas Müller --- .github/workflows/continuous-integration.yml | 227 +++++++++++++++--- composer.json | 14 +- phpstan.neon.dist | 3 + src/Monolog/Handler/ElasticsearchHandler.php | 47 +++- src/Monolog/Test/TestCase.php | 9 + .../Monolog/Formatter/ScalarFormatterTest.php | 7 + tests/Monolog/Handler/AmqpHandlerTest.php | 2 +- tests/Monolog/Handler/DynamoDbHandlerTest.php | 7 + tests/Monolog/Handler/ElasticaHandlerTest.php | 77 ++---- .../Handler/ElasticsearchHandlerTest.php | 153 ++++++------ tests/Monolog/Handler/FlowdockHandlerTest.php | 7 + tests/Monolog/Handler/HandlerWrapperTest.php | 7 + .../Monolog/Handler/InsightOpsHandlerTest.php | 7 + .../Monolog/Handler/LogEntriesHandlerTest.php | 7 + tests/Monolog/Handler/LogmaticHandlerTest.php | 7 + .../Monolog/Handler/PHPConsoleHandlerTest.php | 7 + tests/Monolog/Handler/PushoverHandlerTest.php | 7 + tests/Monolog/Handler/RollbarHandlerTest.php | 7 + .../Handler/RotatingFileHandlerTest.php | 20 +- tests/Monolog/Handler/SlackHandlerTest.php | 7 + tests/Monolog/Handler/SocketHandlerTest.php | 7 + tests/Monolog/Handler/StreamHandlerTest.php | 37 +-- .../Handler/SwiftMailerHandlerTest.php | 7 + .../Handler/SymfonyMailerHandlerTest.php | 7 + .../Handler/ZendMonitorHandlerTest.php | 7 + tests/Monolog/PsrLogCompatTest.php | 7 + tests/Monolog/SignalHandlerTest.php | 6 +- 27 files changed, 510 insertions(+), 197 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 5cb0839c..9ed491d8 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -4,71 +4,242 @@ on: - push - pull_request -env: - COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" - jobs: tests: name: "CI" - runs-on: ubuntu-latest + runs-on: "${{ matrix.operating-system }}" strategy: + fail-fast: false + matrix: php-version: - "7.2" - "7.3" - "7.4" - "8.0" - # disabled for now as phpspec/prophecy does not allow 8.1 - # - "8.1" + - "8.1" + dependencies: [highest] + + operating-system: + - "ubuntu-latest" + include: - php-version: "7.2" dependencies: lowest - - php-version: "8.0" + operating-system: ubuntu-latest + - php-version: "8.1" dependencies: lowest + operating-system: ubuntu-latest steps: - name: "Checkout" uses: "actions/checkout@v2" + - name: Run CouchDB + timeout-minutes: 1 + continue-on-error: true + uses: "cobot/couchdb-action@master" + with: + couchdb version: '2.3.1' + + - name: Run MongoDB + uses: supercharge/mongodb-github-action@1.7.0 + with: + mongodb-version: 5.0 + - name: "Install PHP" uses: "shivammathur/setup-php@v2" with: coverage: "none" php-version: "${{ matrix.php-version }}" extensions: mongodb, redis, amqp - - - name: Get composer cache directory - id: composercache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composercache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-composer- + tools: "composer:v2" + ini-values: "memory_limit=-1" - name: Add require for mongodb/mongodb to make tests runnable - run: 'composer require ${{ env.COMPOSER_FLAGS }} mongodb/mongodb --dev --no-update' + run: 'composer require mongodb/mongodb --dev --no-update' - - name: "Handle lowest dependencies update" - if: "contains(matrix.dependencies, 'lowest')" - run: "echo \"COMPOSER_FLAGS=$COMPOSER_FLAGS --prefer-lowest\" >> $GITHUB_ENV" - - - name: "Install latest dependencies" + - name: "Change dependencies" run: | - composer update ${{ env.COMPOSER_FLAGS }} + composer require --no-update --no-interaction --dev elasticsearch/elasticsearch:^7 + composer config --no-plugins allow-plugins.ocramius/package-versions true + + - name: "Update dependencies with composer" + uses: "ramsey/composer-install@v1" + with: + dependency-versions: "${{ matrix.dependencies }}" - name: "Run tests" - run: "composer exec phpunit -- --verbose" + run: "composer exec phpunit -- --exclude-group Elasticsearch,Elastica --verbose" - name: "Run tests with psr/log 3" if: "contains(matrix.dependencies, 'highest') && matrix.php-version >= '8.0'" run: | composer remove --no-update --dev graylog2/gelf-php ruflin/elastica elasticsearch/elasticsearch rollbar/rollbar composer require --no-update psr/log:^3 - composer update -W ${{ env.COMPOSER_FLAGS }} - composer exec phpunit -- --verbose + composer update -W + composer exec phpunit -- --exclude-group Elasticsearch,Elastica --verbose + + tests-es-7: + name: "CI with ES ${{ matrix.es-version }} on PHP ${{ matrix.php-version }}" + + needs: "tests" + + runs-on: "${{ matrix.operating-system }}" + + strategy: + fail-fast: false + + matrix: + operating-system: + - "ubuntu-latest" + + php-version: + - "7.2" + - "7.3" + - "7.4" + - "8.0" + - "8.1" + + dependencies: + - "highest" + - "lowest" + + es-version: + - "7.0.0" + - "7.17.0" + + exclude: + # php 7.3 is required + - php-version: "7.2" + es-version: "7.17.0" + # tests failing due an error in deprecated guzzlehttp/ringphp + - php-version: "7.3" + es-version: "7.0.0" + - php-version: "7.4" + es-version: "7.0.0" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + # required for elasticsearch + - name: Configure sysctl limits + run: | + sudo swapoff -a + sudo sysctl -w vm.swappiness=1 + sudo sysctl -w fs.file-max=262144 + sudo sysctl -w vm.max_map_count=262144 + + - name: Run Elasticsearch + timeout-minutes: 1 + uses: elastic/elastic-github-actions/elasticsearch@master + with: + stack-version: "${{ matrix.es-version }}" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + extensions: mongodb, redis, amqp + tools: "composer:v2" + ini-values: "memory_limit=-1" + + - name: "Change dependencies" + run: "composer require --no-update --no-interaction --dev elasticsearch/elasticsearch:^${{ matrix.es-version }}" + + - name: "Update dependencies with composer" + uses: "ramsey/composer-install@v1" + with: + dependency-versions: "${{ matrix.dependencies }}" + + - name: "Run tests" + run: "composer exec phpunit -- --group Elasticsearch,Elastica --verbose" + + - name: "Run tests with psr/log 3" + if: "contains(matrix.dependencies, 'highest') && matrix.php-version >= '8.0'" + run: | + composer remove --no-update --dev graylog2/gelf-php ruflin/elastica elasticsearch/elasticsearch rollbar/rollbar + composer require --no-update --no-interaction --dev ruflin/elastica elasticsearch/elasticsearch:^7 + composer require --no-update psr/log:^3 + composer update -W + composer exec phpunit -- --group Elasticsearch,Elastica --verbose + + tests-es-8: + name: "CI with ES ${{ matrix.es-version }} on PHP ${{ matrix.php-version }}" + + needs: "tests" + + runs-on: "${{ matrix.operating-system }}" + + strategy: + fail-fast: false + + matrix: + operating-system: + - "ubuntu-latest" + + php-version: + # ES 8 requires PHP 7.4+ + - "7.4" + - "8.0" + - "8.1" + + dependencies: + - "highest" + - "lowest" + + es-version: + - "8.0.0" + - "8.2.0" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + # required for elasticsearch + - name: Configure sysctl limits + run: | + sudo swapoff -a + sudo sysctl -w vm.swappiness=1 + sudo sysctl -w fs.file-max=262144 + sudo sysctl -w vm.max_map_count=262144 + + - name: Run Elasticsearch + timeout-minutes: 1 + uses: elastic/elastic-github-actions/elasticsearch@master + with: + stack-version: "${{ matrix.es-version }}" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + extensions: mongodb, redis, amqp + tools: "composer:v2" + ini-values: "memory_limit=-1" + + - name: "Change dependencies" + run: | + composer remove --no-update --dev graylog2/gelf-php ruflin/elastica elasticsearch/elasticsearch rollbar/rollbar + composer require --no-update --no-interaction --dev elasticsearch/elasticsearch:^8 + + - name: "Update dependencies with composer" + uses: "ramsey/composer-install@v1" + with: + dependency-versions: "${{ matrix.dependencies }}" + + - name: "Run tests" + run: "composer exec phpunit -- --group Elasticsearch,Elastica --verbose" + + - name: "Run tests with psr/log 3" + if: "contains(matrix.dependencies, 'highest') && matrix.php-version >= '8.0'" + run: | + composer require --no-update psr/log:^3 + composer update -W + composer exec phpunit -- --group Elasticsearch,Elastica --verbose diff --git a/composer.json b/composer.json index 1c0a5c22..52cb35f6 100644 --- a/composer.json +++ b/composer.json @@ -17,19 +17,22 @@ "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "require-dev": { + "ext-json": "*", "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "elasticsearch/elasticsearch": "^7", + "elasticsearch/elasticsearch": "^7 || ^8", "graylog2/gelf-php": "^1.4.2", + "guzzlehttp/guzzle": "^7.4", + "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.15", "phpstan/phpstan": "^0.12.91", - "phpunit/phpunit": "^8.5", + "phpunit/phpunit": "^8.5.14", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3 || ^2 || ^3", - "ruflin/elastica": ">=0.90@dev", + "ruflin/elastica": "^7", "swiftmailer/swiftmailer": "^5.3|^6.0", "symfony/mailer": "^5.4 || ^6", "symfony/mime": "^5.4 || ^6" @@ -72,6 +75,9 @@ "config": { "lock": false, "sort-packages": true, - "platform-check": false + "platform-check": false, + "allow-plugins": { + "composer/package-versions-deprecated": true + } } } diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 961f7ce4..4a368cd2 100644 --- a/phpstan.neon.dist +++ b/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.#' + + # legacy elasticsearch namespace failures + - '# Elastic\\Elasticsearch\\#' diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index b9d323d8..e88375c0 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Elastic\Elasticsearch\Response\Elasticsearch; use Throwable; use RuntimeException; use Monolog\Logger; @@ -19,6 +20,8 @@ use Monolog\Formatter\ElasticsearchFormatter; use InvalidArgumentException; use Elasticsearch\Common\Exceptions\RuntimeException as ElasticsearchRuntimeException; use Elasticsearch\Client; +use Elastic\Elasticsearch\Exception\InvalidArgumentException as ElasticInvalidArgumentException; +use Elastic\Elasticsearch\Client as Client8; /** * Elasticsearch handler @@ -44,7 +47,7 @@ use Elasticsearch\Client; class ElasticsearchHandler extends AbstractProcessingHandler { /** - * @var Client + * @var Client|Client8 */ protected $client; @@ -54,11 +57,20 @@ class ElasticsearchHandler extends AbstractProcessingHandler protected $options = []; /** - * @param Client $client Elasticsearch Client object - * @param mixed[] $options Handler configuration + * @var bool */ - public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) + private $needsType; + + /** + * @param Client|Client8 $client Elasticsearch Client object + * @param mixed[] $options Handler configuration + */ + public function __construct($client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) { + if (!$client instanceof Client && !$client instanceof Client8) { + throw new \TypeError('Elasticsearch\Client or Elastic\Elasticsearch\Client instance required'); + } + parent::__construct($level, $bubble); $this->client = $client; $this->options = array_merge( @@ -69,6 +81,14 @@ class ElasticsearchHandler extends AbstractProcessingHandler ], $options ); + + if ($client instanceof Client8 || $client::VERSION[0] === '7') { + $this->needsType = false; + // force the type to _doc for ES8/ES7 + $this->options['type'] = '_doc'; + } else { + $this->needsType = true; + } } /** @@ -133,9 +153,11 @@ class ElasticsearchHandler extends AbstractProcessingHandler foreach ($records as $record) { $params['body'][] = [ - 'index' => [ + 'index' => $this->needsType ? [ '_index' => $record['_index'], '_type' => $record['_type'], + ] : [ + '_index' => $record['_index'], ], ]; unset($record['_index'], $record['_type']); @@ -143,6 +165,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler $params['body'][] = $record; } + /** @var Elasticsearch */ $responses = $this->client->bulk($params); if ($responses['errors'] === true) { @@ -160,9 +183,9 @@ class ElasticsearchHandler extends AbstractProcessingHandler * * Only the first error is converted into an exception. * - * @param mixed[] $responses returned by $this->client->bulk() + * @param mixed[]|Elasticsearch $responses returned by $this->client->bulk() */ - protected function createExceptionFromResponses(array $responses): ElasticsearchRuntimeException + protected function createExceptionFromResponses($responses): Throwable { foreach ($responses['items'] ?? [] as $item) { if (isset($item['index']['error'])) { @@ -170,6 +193,10 @@ class ElasticsearchHandler extends AbstractProcessingHandler } } + if (class_exists(ElasticInvalidArgumentException::class)) { + return new ElasticInvalidArgumentException('Elasticsearch failed to index one or more records.'); + } + return new ElasticsearchRuntimeException('Elasticsearch failed to index one or more records.'); } @@ -178,10 +205,14 @@ class ElasticsearchHandler extends AbstractProcessingHandler * * @param mixed[] $error */ - protected function createExceptionFromError(array $error): ElasticsearchRuntimeException + protected function createExceptionFromError(array $error): Throwable { $previous = isset($error['caused_by']) ? $this->createExceptionFromError($error['caused_by']) : null; + if (class_exists(ElasticInvalidArgumentException::class)) { + return new ElasticInvalidArgumentException($error['type'] . ': ' . $error['reason'], 0, $previous); + } + return new ElasticsearchRuntimeException($error['type'] . ': ' . $error['reason'], 0, $previous); } } diff --git a/src/Monolog/Test/TestCase.php b/src/Monolog/Test/TestCase.php index 1824fde4..c4e42496 100644 --- a/src/Monolog/Test/TestCase.php +++ b/src/Monolog/Test/TestCase.php @@ -25,6 +25,15 @@ use Monolog\Formatter\FormatterInterface; */ class TestCase extends \PHPUnit\Framework\TestCase { + public function tearDown(): void + { + parent::tearDown(); + + if (isset($this->handler)) { + unset($this->handler); + } + } + /** * @param mixed[] $context * diff --git a/tests/Monolog/Formatter/ScalarFormatterTest.php b/tests/Monolog/Formatter/ScalarFormatterTest.php index c72227f7..596ed78f 100644 --- a/tests/Monolog/Formatter/ScalarFormatterTest.php +++ b/tests/Monolog/Formatter/ScalarFormatterTest.php @@ -22,6 +22,13 @@ class ScalarFormatterTest extends \PHPUnit\Framework\TestCase $this->formatter = new ScalarFormatter(); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->formatter); + } + public function buildTrace(\Exception $e) { $data = []; diff --git a/tests/Monolog/Handler/AmqpHandlerTest.php b/tests/Monolog/Handler/AmqpHandlerTest.php index c2de874c..62d41a5e 100644 --- a/tests/Monolog/Handler/AmqpHandlerTest.php +++ b/tests/Monolog/Handler/AmqpHandlerTest.php @@ -78,7 +78,7 @@ class AmqpHandlerTest extends TestCase public function testHandlePhpAmqpLib() { - if (!class_exists('PhpAmqpLib\Connection\AMQPConnection')) { + if (!class_exists('PhpAmqpLib\Channel\AMQPChannel')) { $this->markTestSkipped("php-amqplib not installed"); } diff --git a/tests/Monolog/Handler/DynamoDbHandlerTest.php b/tests/Monolog/Handler/DynamoDbHandlerTest.php index 2b237bfa..92c9c4c3 100644 --- a/tests/Monolog/Handler/DynamoDbHandlerTest.php +++ b/tests/Monolog/Handler/DynamoDbHandlerTest.php @@ -45,6 +45,13 @@ class DynamoDbHandlerTest extends TestCase $this->client = $clientMockBuilder->getMock(); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->client); + } + public function testConstruct() { $this->assertInstanceOf('Monolog\Handler\DynamoDbHandler', new DynamoDbHandler($this->client, 'foo')); diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index 7fb9808e..c03fefd0 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -19,6 +19,9 @@ use Elastica\Client; use Elastica\Request; use Elastica\Response; +/** + * @group Elastica + */ class ElasticaHandlerTest extends TestCase { /** @@ -48,6 +51,13 @@ class ElasticaHandlerTest extends TestCase ->getMock(); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->client); + } + /** * @covers Monolog\Handler\ElasticaHandler::write * @covers Monolog\Handler\ElasticaHandler::handleBatch @@ -155,60 +165,6 @@ class ElasticaHandlerTest extends TestCase ]; } - /** - * Integration test using localhost Elastic Search server version <7 - * - * @covers Monolog\Handler\ElasticaHandler::__construct - * @covers Monolog\Handler\ElasticaHandler::handleBatch - * @covers Monolog\Handler\ElasticaHandler::bulkSend - * @covers Monolog\Handler\ElasticaHandler::getDefaultFormatter - */ - public function testHandleIntegration() - { - $msg = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; - - $expected = $msg; - $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); - $expected['context'] = [ - 'class' => '[object] (stdClass: {})', - 'foo' => 7, - 0 => 'bar', - ]; - - $client = new Client(); - $handler = new ElasticaHandler($client, $this->options); - - try { - $handler->handleBatch([$msg]); - } catch (\RuntimeException $e) { - $this->markTestSkipped("Cannot connect to Elastic Search server on localhost"); - } - - // check document id from ES server response - $documentId = $this->getCreatedDocId($client->getLastResponse()); - $this->assertNotEmpty($documentId, 'No elastic document id received'); - - // retrieve document source from ES and validate - $document = $this->getDocSourceFromElastic( - $client, - $this->options['index'], - $this->options['type'], - $documentId - ); - $this->assertEquals($expected, $document); - - // remove test index from ES - $client->request("/{$this->options['index']}", Request::DELETE); - } - /** * Integration test using localhost Elastic Search server version 7+ * @@ -237,7 +193,9 @@ class ElasticaHandlerTest extends TestCase 0 => 'bar', ]; - $client = new Client(); + $clientOpts = ['url' => 'http://elastic:changeme@127.0.0.1:9200']; + $client = new Client($clientOpts); + $handler = new ElasticaHandler($client, $this->options); try { @@ -271,9 +229,14 @@ class ElasticaHandlerTest extends TestCase protected function getCreatedDocId(Response $response) { $data = $response->getData(); - if (!empty($data['items'][0]['create']['_id'])) { - return $data['items'][0]['create']['_id']; + + if (!empty($data['items'][0]['index']['_id'])) { + return $data['items'][0]['index']['_id']; } + + var_dump('Unexpected response: ', $data); + + return null; } /** diff --git a/tests/Monolog/Handler/ElasticsearchHandlerTest.php b/tests/Monolog/Handler/ElasticsearchHandlerTest.php index 764c54c9..e84cdbd6 100644 --- a/tests/Monolog/Handler/ElasticsearchHandlerTest.php +++ b/tests/Monolog/Handler/ElasticsearchHandlerTest.php @@ -11,17 +11,22 @@ namespace Monolog\Handler; -use Elasticsearch\ClientBuilder; use Monolog\Formatter\ElasticsearchFormatter; use Monolog\Formatter\NormalizerFormatter; use Monolog\Test\TestCase; use Monolog\Logger; use Elasticsearch\Client; +use Elastic\Elasticsearch\Client as Client8; +use Elasticsearch\ClientBuilder; +use Elastic\Elasticsearch\ClientBuilder as ClientBuilder8; +/** + * @group Elasticsearch + */ class ElasticsearchHandlerTest extends TestCase { /** - * @var Client mock + * @var Client|Client8 mock */ protected $client; @@ -35,63 +40,23 @@ class ElasticsearchHandlerTest extends TestCase public function setUp(): void { - // Elasticsearch lib required - if (!class_exists('Elasticsearch\Client')) { - $this->markTestSkipped('elasticsearch/elasticsearch not installed'); - } + $hosts = ['http://elastic:changeme@127.0.0.1:9200']; + $this->client = $this->getClientBuilder() + ->setHosts($hosts) + ->build(); - // base mock Elasticsearch Client object - $this->client = $this->getMockBuilder('Elasticsearch\Client') - ->onlyMethods(['bulk']) - ->disableOriginalConstructor() - ->getMock(); + try { + $this->client->info(); + } catch (\Throwable $e) { + $this->markTestSkipped('Could not connect to Elasticsearch on 127.0.0.1:9200'); + } } - /** - * @covers Monolog\Handler\ElasticsearchHandler::write - * @covers Monolog\Handler\ElasticsearchHandler::handleBatch - * @covers Monolog\Handler\ElasticsearchHandler::bulkSend - * @covers Monolog\Handler\ElasticsearchHandler::getDefaultFormatter - */ - public function testHandle() + public function tearDown(): void { - // log message - $msg = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + parent::tearDown(); - // format expected result - $formatter = new ElasticsearchFormatter($this->options['index'], $this->options['type']); - $data = $formatter->format($msg); - unset($data['_index'], $data['_type']); - - $expected = [ - 'body' => [ - [ - 'index' => [ - '_index' => $this->options['index'], - '_type' => $this->options['type'], - ], - ], - $data, - ], - ]; - - // setup ES client mock - $this->client->expects($this->any()) - ->method('bulk') - ->with($expected); - - // perform tests - $handler = new ElasticsearchHandler($this->client, $this->options); - $handler->handle($msg); - $handler->handleBatch([$msg]); + unset($this->client); } /** @@ -108,7 +73,7 @@ class ElasticsearchHandlerTest extends TestCase } /** - * @covers Monolog\Handler\ElasticsearchHandler::setFormatter + * @covers Monolog\Handler\ElasticsearchHandler::setFormatter */ public function testSetFormatterInvalid() { @@ -132,6 +97,11 @@ class ElasticsearchHandlerTest extends TestCase 'type' => $this->options['type'], 'ignore_error' => false, ]; + + if ($this->client instanceof Client8 || $this->client::VERSION[0] === '7') { + $expected['type'] = '_doc'; + } + $handler = new ElasticsearchHandler($this->client, $this->options); $this->assertEquals($expected, $handler->getOptions()); } @@ -142,10 +112,10 @@ class ElasticsearchHandlerTest extends TestCase */ public function testConnectionErrors($ignore, $expectedError) { - $hosts = [['host' => '127.0.0.1', 'port' => 1]]; - $client = ClientBuilder::create() - ->setHosts($hosts) - ->build(); + $hosts = ['http://127.0.0.1:1']; + $client = $this->getClientBuilder() + ->setHosts($hosts) + ->build(); $handlerOpts = ['ignore_error' => $ignore]; $handler = new ElasticsearchHandler($client, $handlerOpts); @@ -178,7 +148,7 @@ class ElasticsearchHandlerTest extends TestCase * @covers Monolog\Handler\ElasticsearchHandler::bulkSend * @covers Monolog\Handler\ElasticsearchHandler::getDefaultFormatter */ - public function testHandleIntegration() + public function testHandleBatchIntegration() { $msg = [ 'level' => Logger::ERROR, @@ -198,21 +168,26 @@ class ElasticsearchHandlerTest extends TestCase 0 => 'bar', ]; - $hosts = [['host' => '127.0.0.1', 'port' => 9200]]; - $client = ClientBuilder::create() + $hosts = ['http://elastic:changeme@127.0.0.1:9200']; + $client = $this->getClientBuilder() ->setHosts($hosts) ->build(); $handler = new ElasticsearchHandler($client, $this->options); - - try { - $handler->handleBatch([$msg]); - } catch (\RuntimeException $e) { - $this->markTestSkipped('Cannot connect to Elasticsearch server on localhost'); - } + $handler->handleBatch([$msg]); // check document id from ES server response - $documentId = $this->getCreatedDocId($client->transport->getLastConnection()->getLastRequestInfo()); - $this->assertNotEmpty($documentId, 'No elastic document id received'); + if ($client instanceof Client8) { + $messageBody = $client->getTransport()->getLastResponse()->getBody(); + + $info = json_decode((string) $messageBody, true); + $this->assertNotNull($info, 'Decoding failed'); + + $documentId = $this->getCreatedDocIdV8($info); + $this->assertNotEmpty($documentId, 'No elastic document id received'); + } else { + $documentId = $this->getCreatedDocId($client->transport->getLastConnection()->getLastRequestInfo()); + $this->assertNotEmpty($documentId, 'No elastic document id received'); + } // retrieve document source from ES and validate $document = $this->getDocSourceFromElastic( @@ -241,25 +216,45 @@ class ElasticsearchHandlerTest extends TestCase if (!empty($data['items'][0]['index']['_id'])) { return $data['items'][0]['index']['_id']; } + + return null; + } + + /** + * Return last created document id from ES response + * + * @param array $data Elasticsearch last request info + * @return string|null + */ + protected function getCreatedDocIdV8(array $data) + { + if (!empty($data['items'][0]['index']['_id'])) { + return $data['items'][0]['index']['_id']; + } + + return null; } /** * Retrieve document by id from Elasticsearch * - * @param Client $client Elasticsearch client + * @param Client|Client8 $client Elasticsearch client * @param string $index * @param string $type * @param string $documentId * @return array */ - protected function getDocSourceFromElastic(Client $client, $index, $type, $documentId) + protected function getDocSourceFromElastic($client, $index, $type, $documentId) { $params = [ 'index' => $index, - 'type' => $type, 'id' => $documentId, ]; + if (!$client instanceof Client8 && $client::VERSION[0] !== '7') { + $params['type'] = $type; + } + $data = $client->get($params); if (!empty($data['_source'])) { @@ -268,4 +263,16 @@ class ElasticsearchHandlerTest extends TestCase return []; } + + /** + * @return ClientBuilder|ClientBuilder8 + */ + private function getClientBuilder() + { + if (class_exists(ClientBuilder8::class)) { + return ClientBuilder8::create(); + } + + return ClientBuilder::create(); + } } diff --git a/tests/Monolog/Handler/FlowdockHandlerTest.php b/tests/Monolog/Handler/FlowdockHandlerTest.php index 04bf063d..45c8799c 100644 --- a/tests/Monolog/Handler/FlowdockHandlerTest.php +++ b/tests/Monolog/Handler/FlowdockHandlerTest.php @@ -38,6 +38,13 @@ class FlowdockHandlerTest extends TestCase } } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->res); + } + public function testWriteHeader() { $this->createHandler(); diff --git a/tests/Monolog/Handler/HandlerWrapperTest.php b/tests/Monolog/Handler/HandlerWrapperTest.php index 87a117b1..67cc2a32 100644 --- a/tests/Monolog/Handler/HandlerWrapperTest.php +++ b/tests/Monolog/Handler/HandlerWrapperTest.php @@ -32,6 +32,13 @@ class HandlerWrapperTest extends TestCase $this->wrapper = new HandlerWrapper($this->handler); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->wrapper); + } + /** * @return array */ diff --git a/tests/Monolog/Handler/InsightOpsHandlerTest.php b/tests/Monolog/Handler/InsightOpsHandlerTest.php index 9c98d379..808084e8 100644 --- a/tests/Monolog/Handler/InsightOpsHandlerTest.php +++ b/tests/Monolog/Handler/InsightOpsHandlerTest.php @@ -30,6 +30,13 @@ class InsightOpsHandlerTest extends TestCase */ private $handler; + public function tearDown(): void + { + parent::tearDown(); + + unset($this->resource); + } + public function testWriteContent() { $this->createHandler(); diff --git a/tests/Monolog/Handler/LogEntriesHandlerTest.php b/tests/Monolog/Handler/LogEntriesHandlerTest.php index 034d6ab8..3d7273c8 100644 --- a/tests/Monolog/Handler/LogEntriesHandlerTest.php +++ b/tests/Monolog/Handler/LogEntriesHandlerTest.php @@ -29,6 +29,13 @@ class LogEntriesHandlerTest extends TestCase */ private $handler; + public function tearDown(): void + { + parent::tearDown(); + + unset($this->res); + } + public function testWriteContent() { $this->createHandler(); diff --git a/tests/Monolog/Handler/LogmaticHandlerTest.php b/tests/Monolog/Handler/LogmaticHandlerTest.php index c30a1794..1cb4254e 100644 --- a/tests/Monolog/Handler/LogmaticHandlerTest.php +++ b/tests/Monolog/Handler/LogmaticHandlerTest.php @@ -29,6 +29,13 @@ class LogmaticHandlerTest extends TestCase */ private $handler; + public function tearDown(): void + { + parent::tearDown(); + + unset($this->res); + } + public function testWriteContent() { $this->createHandler(); diff --git a/tests/Monolog/Handler/PHPConsoleHandlerTest.php b/tests/Monolog/Handler/PHPConsoleHandlerTest.php index 98d8a4b2..f1ffcf96 100644 --- a/tests/Monolog/Handler/PHPConsoleHandlerTest.php +++ b/tests/Monolog/Handler/PHPConsoleHandlerTest.php @@ -56,6 +56,13 @@ class PHPConsoleHandlerTest extends TestCase $this->connector->setErrorsDispatcher($this->errorDispatcher); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->connector, $this->debugDispatcher, $this->errorDispatcher); + } + protected function initDebugDispatcherMock(Connector $connector) { return $this->getMockBuilder('PhpConsole\Dispatcher\Debug') diff --git a/tests/Monolog/Handler/PushoverHandlerTest.php b/tests/Monolog/Handler/PushoverHandlerTest.php index 2c77d30c..8596e356 100644 --- a/tests/Monolog/Handler/PushoverHandlerTest.php +++ b/tests/Monolog/Handler/PushoverHandlerTest.php @@ -25,6 +25,13 @@ class PushoverHandlerTest extends TestCase private $res; private $handler; + public function tearDown(): void + { + parent::tearDown(); + + unset($this->res); + } + public function testWriteHeader() { $this->createHandler(); diff --git a/tests/Monolog/Handler/RollbarHandlerTest.php b/tests/Monolog/Handler/RollbarHandlerTest.php index 0aa7cbff..60e08d6d 100644 --- a/tests/Monolog/Handler/RollbarHandlerTest.php +++ b/tests/Monolog/Handler/RollbarHandlerTest.php @@ -44,6 +44,13 @@ class RollbarHandlerTest extends TestCase $this->setupRollbarLoggerMock(); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->rollbarLogger, $this->reportedExceptionArguments); + } + /** * When reporting exceptions to Rollbar the * level has to be set in the payload data diff --git a/tests/Monolog/Handler/RotatingFileHandlerTest.php b/tests/Monolog/Handler/RotatingFileHandlerTest.php index 5446f40e..dd77c853 100644 --- a/tests/Monolog/Handler/RotatingFileHandlerTest.php +++ b/tests/Monolog/Handler/RotatingFileHandlerTest.php @@ -39,6 +39,18 @@ class RotatingFileHandlerTest extends TestCase }); } + public function tearDown(): void + { + parent::tearDown(); + + foreach (glob(__DIR__.'/Fixtures/*.rot') as $file) { + unlink($file); + } + restore_error_handler(); + + unset($this->lastError); + } + private function assertErrorWasTriggered($code, $message) { if (empty($this->lastError)) { @@ -239,12 +251,4 @@ class RotatingFileHandlerTest extends TestCase $handler->handle($this->getRecord()); $this->assertEquals('footest', file_get_contents($log)); } - - public function tearDown(): void - { - foreach (glob(__DIR__.'/Fixtures/*.rot') as $file) { - unlink($file); - } - restore_error_handler(); - } } diff --git a/tests/Monolog/Handler/SlackHandlerTest.php b/tests/Monolog/Handler/SlackHandlerTest.php index c6e30a75..4e4d8220 100644 --- a/tests/Monolog/Handler/SlackHandlerTest.php +++ b/tests/Monolog/Handler/SlackHandlerTest.php @@ -39,6 +39,13 @@ class SlackHandlerTest extends TestCase } } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->res); + } + public function testWriteHeader() { $this->createHandler(); diff --git a/tests/Monolog/Handler/SocketHandlerTest.php b/tests/Monolog/Handler/SocketHandlerTest.php index 272dd704..ba5a1bad 100644 --- a/tests/Monolog/Handler/SocketHandlerTest.php +++ b/tests/Monolog/Handler/SocketHandlerTest.php @@ -30,6 +30,13 @@ class SocketHandlerTest extends TestCase */ private $res; + public function tearDown(): void + { + parent::tearDown(); + + unset($this->res); + } + public function testInvalidHostname() { $this->expectException(\UnexpectedValueException::class); diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index 43a520bc..8c69cc58 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -271,20 +271,20 @@ STRING; $this->markTestSkipped('We could not set a memory limit that would trigger the error.'); } - $stream = tmpfile(); + try { + $stream = tmpfile(); - if ($stream === false) { - $this->markTestSkipped('We could not create a temp file to be use as a stream.'); + if ($stream === false) { + $this->markTestSkipped('We could not create a temp file to be use as a stream.'); + } + + $handler = new StreamHandler($stream); + stream_get_contents($stream, 1024); + + $this->assertEquals($expectedChunkSize, $handler->getStreamChunkSize()); + } finally { + ini_set('memory_limit', $previousValue); } - - $exceptionRaised = false; - - $handler = new StreamHandler($stream); - stream_get_contents($stream, 1024); - - ini_set('memory_limit', $previousValue); - - $this->assertEquals($expectedChunkSize, $handler->getStreamChunkSize()); } /** @@ -298,10 +298,13 @@ STRING; $this->markTestSkipped('We could not set a memory limit that would trigger the error.'); } - $stream = tmpfile(); - new StreamHandler($stream); - stream_get_contents($stream); - ini_set('memory_limit', $previousValue); - $this->assertTrue(true); + try { + $stream = tmpfile(); + new StreamHandler($stream); + stream_get_contents($stream); + $this->assertTrue(true); + } finally { + ini_set('memory_limit', $previousValue); + } } } diff --git a/tests/Monolog/Handler/SwiftMailerHandlerTest.php b/tests/Monolog/Handler/SwiftMailerHandlerTest.php index 51596c39..9dd65e61 100644 --- a/tests/Monolog/Handler/SwiftMailerHandlerTest.php +++ b/tests/Monolog/Handler/SwiftMailerHandlerTest.php @@ -28,6 +28,13 @@ class SwiftMailerHandlerTest extends TestCase ->getMock(); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->mailer); + } + public function testMessageCreationIsLazyWhenUsingCallback() { $this->mailer->expects($this->never()) diff --git a/tests/Monolog/Handler/SymfonyMailerHandlerTest.php b/tests/Monolog/Handler/SymfonyMailerHandlerTest.php index af1e926a..ea4b9e26 100644 --- a/tests/Monolog/Handler/SymfonyMailerHandlerTest.php +++ b/tests/Monolog/Handler/SymfonyMailerHandlerTest.php @@ -30,6 +30,13 @@ class SymfonyMailerHandlerTest extends TestCase ->getMock(); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->mailer); + } + public function testMessageCreationIsLazyWhenUsingCallback() { $this->mailer->expects($this->never()) diff --git a/tests/Monolog/Handler/ZendMonitorHandlerTest.php b/tests/Monolog/Handler/ZendMonitorHandlerTest.php index e8fe55c5..e01c0db6 100644 --- a/tests/Monolog/Handler/ZendMonitorHandlerTest.php +++ b/tests/Monolog/Handler/ZendMonitorHandlerTest.php @@ -25,6 +25,13 @@ class ZendMonitorHandlerTest extends TestCase } } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->zendMonitorHandler); + } + /** * @covers Monolog\Handler\ZendMonitorHandler::write */ diff --git a/tests/Monolog/PsrLogCompatTest.php b/tests/Monolog/PsrLogCompatTest.php index eaeb3552..e22f6054 100644 --- a/tests/Monolog/PsrLogCompatTest.php +++ b/tests/Monolog/PsrLogCompatTest.php @@ -25,6 +25,13 @@ class PsrLogCompatTest extends TestCase { private $handler; + public function tearDown(): void + { + parent::tearDown(); + + unset($this->handler); + } + public function getLogger(): LoggerInterface { $logger = new Logger('foo'); diff --git a/tests/Monolog/SignalHandlerTest.php b/tests/Monolog/SignalHandlerTest.php index e73ad8fd..8c28fc14 100644 --- a/tests/Monolog/SignalHandlerTest.php +++ b/tests/Monolog/SignalHandlerTest.php @@ -39,8 +39,10 @@ class SignalHandlerTest extends TestCase } } - protected function tearDown(): void + public function tearDown(): void { + parent::tearDown(); + if ($this->asyncSignalHandling !== null) { pcntl_async_signals($this->asyncSignalHandling); } @@ -53,6 +55,8 @@ class SignalHandlerTest extends TestCase pcntl_signal($signo, $handler); } } + + unset($this->signalHandlers, $this->blockedSignals, $this->asyncSignalHandling); } private function setSignalHandler($signo, $handler = SIG_DFL)