Skip to content

Commit

Permalink
feat: Add support for Monolog 3.x (#5334)
Browse files Browse the repository at this point in the history
* fix: Allow `ServiceException` creation with `null` as the message

Some tests explicitly set the message to `null` which breaks the
creation of parent exceptions with newer PHP versions.

Setting a default `$message = ''` does not prevent the problem, so
we declare it with `null` being allowed, and check and replace it in the
`ServiceException` constructor.

The change is made in the `ServiceException` instead of the tests
calling it incorrectly to reduce the scope of updated files in the
context of the PR that handles the problem.

* feat: Enable the usage of `"psr/log": "^2.0|^3.0"`

`phpdocumentor/reflection` started supporting `"psr/log": "^2.0|^3.0"`
with v5.3.

See phpDocumentor/Reflection#247

* feat: Enable the installation of Monolog V3

`psr/log` v1 included a TestLogger that was removed starting with v2.
`fig/log-test` support all current versions of `psr/log`.

* feat: Introduce V3 versions of AppEngine Formatters and Handlers

* feat: Introduce LogMessageProcessors and their factory

* add monolog 3 to root composer

* remove provide

* allow log-test 1.0

* remove log-test in favor of skipping tests

* ignore cs warning

Co-authored-by: Brent Shaffer <[email protected]>
  • Loading branch information
jeromegamez and bshaffer authored Dec 14, 2022
1 parent 613681f commit 3fc343f
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 15 deletions.
6 changes: 2 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
"yoast/phpunit-polyfills": "^1.0",
"phpspec/prophecy": "^1.10.3",
"squizlabs/php_codesniffer": "2.*",
"phpdocumentor/reflection": "^3.0||^4.0",
"phpdocumentor/reflection": "^3.0||^4.0||^5.3",
"erusev/parsedown": "^1.6",
"fig/log-test": "^1.0",
"google/cloud-storage": "^1.3",
"google/cloud-bigquery": "^1.0",
"google/cloud-pubsub": "^1.0",
Expand Down Expand Up @@ -48,8 +49,5 @@
"psr-4": {
"Google\\Cloud\\Logging\\Tests\\": "tests"
}
},
"conflict": {
"psr/log": ">=3"
}
}
58 changes: 58 additions & 0 deletions src/LogMessageProcessor/MonologMessageProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php
/**
* Copyright 2022 Google LLC
*
* 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
*
* http://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 Google\Cloud\Logging\LogMessageProcessor;

use Google\Cloud\Logging\LogMessageProcessorInterface;
use Monolog\Formatter\NormalizerFormatter;
use Monolog\Processor\PsrLogMessageProcessor;

/**
* Uses the Monolog 1/2 PsrLogMessageProcessor to process a
* record's message according to PSR-3 rules.
*/
final class MonologMessageProcessor implements LogMessageProcessorInterface
{
/**
* @var NormalizerFormatter
*/
private $formatter;

/**
* @var PsrLogMessageProcessor
*/
private $processor;

public function __construct()
{
$this->formatter = new NormalizerFormatter();
$this->processor = new PsrLogMessageProcessor();
}

/**
* {@inheritdoc}
*/
public function processLogMessage($message, $context)
{
$processor = $this->processor;

return $processor([
'message' => (string) $message,
'context' => $this->formatter->format($context)
]);
}
}
63 changes: 63 additions & 0 deletions src/LogMessageProcessor/MonologV3MessageProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php
/**
* Copyright 2022 Google LLC
*
* 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
*
* http://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 Google\Cloud\Logging\LogMessageProcessor;

use Google\Cloud\Logging\LogMessageProcessorInterface;
use Monolog\Level;
use Monolog\LogRecord;
use Monolog\Processor\PsrLogMessageProcessor;

/**
* Uses the Monolog 3 PsrLogMessageProcessor to process a
* record's message according to PSR-3 rules.
*/
final class MonologV3MessageProcessor implements LogMessageProcessorInterface
{
/**
* @var PsrLogMessageProcessor
*/
private $processor;

public function __construct()
{
$this->processor = new PsrLogMessageProcessor();
}

/**
* {@inheritdoc}
*/
public function processLogMessage($message, $context)
{
// The datetime, channel, and level are required but not relevant here
$logRecord = new LogRecord(
new \DateTimeImmutable(),
'channel',
Level::Info,
(string) $message,
$context
);

$processor = $this->processor;
$processed = $processor($logRecord);

return [
'message' => $processed['message'],
'context' => $processed['context'],
];
}
}
47 changes: 47 additions & 0 deletions src/LogMessageProcessorFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php
/**
* Copyright 2022 Google LLC
*
* 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
*
* http://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 Google\Cloud\Logging;

use Google\Cloud\Logging\LogMessageProcessor\MonologMessageProcessor;
use Google\Cloud\Logging\LogMessageProcessor\MonologV3MessageProcessor;
use Monolog\Logger as MonologLogger;
use RuntimeException;

/**
* Returns a LogMessageProcessor that can be used with the currently install Monolog version
*/
class LogMessageProcessorFactory
{
/**
* @return LogMessageProcessorInterface
*/
public static function build()
{
$version = defined('\Monolog\Logger::API') ? MonologLogger::API : 1;

switch ($version) {
case 1:
case 2:
return new MonologMessageProcessor();
case 3:
return new MonologV3MessageProcessor();
default:
throw new RuntimeException('Version not supported');
}
}
}
33 changes: 33 additions & 0 deletions src/LogMessageProcessorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
/**
* Copyright 2022 Google LLC
*
* 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
*
* http://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 Google\Cloud\Logging;

/**
* Interface representing a Log Message Processor used by the {@see PsrLogger}
*/
interface LogMessageProcessorInterface
{
/**
* @param string|\Stringable $message
* @param array $context
*
* @phpstan-return array{message: string, context: array}
* @return array
*/
public function processLogMessage($message, $context);
}
15 changes: 7 additions & 8 deletions src/PsrLogger.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
use Google\Cloud\Core\Report\MetadataProviderInterface;
use Google\Cloud\Core\Report\MetadataProviderUtils;
use Google\Cloud\Core\Timestamp;
use Monolog\Formatter\NormalizerFormatter;
use Monolog\Processor\PsrLogMessageProcessor;
use Psr\Log\InvalidArgumentException;
use Psr\Log\LoggerInterface;

Expand Down Expand Up @@ -89,6 +87,11 @@ class PsrLogger implements LoggerInterface, \Serializable
*/
private $logName;

/**
* @var LogMessageProcessorInterface
*/
private $logMessageProcessor;

/**
* @param Logger $logger The logger used to write entries.
* @param string $messageKey The key in the `jsonPayload` used to contain
Expand Down Expand Up @@ -138,6 +141,7 @@ public function __construct(
) {
$this->logger = $logger;
$this->logName = $logger->name();
$this->logMessageProcessor = LogMessageProcessorFactory::build();
$this->messageKey = $messageKey ?: 'message';
$this->metadataProvider = isset($options['metadataProvider'])
? $options['metadataProvider']
Expand Down Expand Up @@ -383,12 +387,7 @@ public function log($level, $message, array $context = [])
unset($context['stackdriverOptions']);
}

$formatter = new NormalizerFormatter();
$processor = new PsrLogMessageProcessor();
$processedData = $processor([
'message' => (string) $message,
'context' => $formatter->format($context)
]);
$processedData = $this->logMessageProcessor->processLogMessage($message, $context);
$jsonPayload = [$this->messageKey => $processedData['message']];

// Adding labels for log request correlation.
Expand Down
10 changes: 10 additions & 0 deletions tests/Unit/PsrLoggerCompatibilityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@
use Prophecy\Argument;
use Yoast\PHPUnitPolyfills\Polyfills\ExpectException;

// phpcs:disable
if (!class_exists(LoggerInterfaceTest::class)) {
// We have to do this because fig/log-test does not support PHP 7.3 and below,
// but is required when using psr/log v2 (PHP 8.0 and above).
// This means that we cannot add that dependency to require-dev in the root
// composer.json file. As a result, these tests are skipped on PHP 8.0 and above.
return;
}
// phpcs:enable

/**
* @group logging
*/
Expand Down
3 changes: 0 additions & 3 deletions tests/Unit/PsrLoggerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,10 @@

namespace Google\Cloud\Logging\Tests\Unit;

use Google\Cloud\Core\Batch\BatchRunner;
use Google\Cloud\Core\Batch\OpisClosureSerializer;
use Google\Cloud\Core\Report\EmptyMetadataProvider;
use Google\Cloud\Logging\Logger;
use Google\Cloud\Logging\PsrLogger;
use Google\Cloud\Logging\Connection\ConnectionInterface;
use Prophecy\Argument;
use Yoast\PHPUnitPolyfills\TestCases\TestCase;
use Yoast\PHPUnitPolyfills\Polyfills\ExpectException;

Expand Down

0 comments on commit 3fc343f

Please sign in to comment.