From f9bf0787b9279c7690d27524e767ea180c1ba5aa Mon Sep 17 00:00:00 2001 From: Lee Rowlands <lee.rowlands@previousnext.com.au> Date: Fri, 28 Apr 2023 13:36:57 +1000 Subject: [PATCH] Issue #2932518 by kim.pepper, joachim, bradjones1, voleger, cliddell, gapple, Xano, andregp, andypost, neclimdul, rpayanm, Hardik_Patel_12, NWOM, smustgrave, dawehner, alexpott, daffie, larowlan, Berdir, mstrelan, xjm, dagmar: Deprecate watchdog_exception --- core/core.services.yml | 12 ++- core/includes/bootstrap.inc | 6 ++ core/includes/update.inc | 7 +- core/lib/Drupal/Core/Cron.php | 9 ++- core/lib/Drupal/Core/Database/Transaction.php | 6 +- .../lib/Drupal/Core/Database/database.api.php | 4 +- .../Entity/Sql/SqlContentEntityStorage.php | 11 +-- .../MenuRouterRebuildSubscriber.php | 14 +++- .../Drupal/Core/Extension/ModuleInstaller.php | 12 ++- .../lib/Drupal/Core/Routing/MatcherDumper.php | 28 ++++++- core/lib/Drupal/Core/Utility/Error.php | 20 +++++ core/modules/sdc/sdc.services.yml | 1 + .../sdc/src/Twig/TwigComponentLoader.php | 11 ++- .../SecurityAdvisoriesFetcher.php | 5 +- core/modules/system/system.install | 3 +- .../SecurityAdvisoriesFetcherTest.php | 8 +- .../update/src/ProjectSecurityData.php | 8 +- core/modules/update/src/UpdateFetcher.php | 12 ++- .../tests/src/Unit/UpdateFetcherTest.php | 48 +++++------- core/modules/update/update.compare.inc | 8 +- core/modules/update/update.services.yml | 5 +- .../workspaces/src/WorkspaceAssociation.php | 12 ++- .../workspaces/src/WorkspaceMerger.php | 12 ++- .../src/WorkspaceOperationFactory.php | 13 +++- .../workspaces/src/WorkspacePublisher.php | 12 ++- .../workspaces/workspaces.services.yml | 4 +- .../Core/Bootstrap/LegacyBootstrapTest.php | 37 ++++++++++ .../Core/Routing/LegacyMatcherDumperTest.php | 74 +++++++++++++++++++ .../Core/Routing/MatcherDumperTest.php | 23 ++++-- .../Core/Routing/RouteProviderTest.php | 40 ++++++---- .../Core/Cron/CronSuspendQueueDelayTest.php | 2 +- 31 files changed, 347 insertions(+), 120 deletions(-) create mode 100644 core/tests/Drupal/KernelTests/Core/Bootstrap/LegacyBootstrapTest.php create mode 100644 core/tests/Drupal/KernelTests/Core/Routing/LegacyMatcherDumperTest.php diff --git a/core/core.services.yml b/core/core.services.yml index 18b227280378..ed531f502701 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -494,6 +494,12 @@ services: logger.channel.security: parent: logger.channel_base arguments: ['security'] + logger.channel.menu: + parent: logger.channel_base + arguments: ['menu'] + logger.channel.router: + parent: logger.channel_base + arguments: ['router'] logger.log_message_parser: class: Drupal\Core\Logger\LogMessageParser Drupal\Core\Logger\LogMessageParserInterface: '@logger.log_message_parser' @@ -586,7 +592,7 @@ services: class: Drupal\Core\Extension\ModuleInstaller tags: - { name: service_collector, tag: 'module_install.uninstall_validator', call: addUninstallValidator } - arguments: ['%app.root%', '@module_handler', '@kernel', '@database', '@update.update_hook_registry'] + arguments: ['%app.root%', '@module_handler', '@kernel', '@database', '@update.update_hook_registry', '@logger.channel.default'] lazy: true Drupal\Core\Extension\ModuleInstallerInterface: '@module_installer' extension.list.module: @@ -1055,7 +1061,7 @@ services: arguments: ['@keyvalue'] router.dumper: class: Drupal\Core\Routing\MatcherDumper - arguments: ['@database', '@state'] + arguments: ['@database', '@state', '@logger.channel.router'] tags: - { name: backend_overridable } lazy: true @@ -1069,7 +1075,7 @@ services: Drupal\Core\Routing\RouteBuilderInterface: '@router.builder' menu.rebuild_subscriber: class: Drupal\Core\EventSubscriber\MenuRouterRebuildSubscriber - arguments: ['@lock', '@plugin.manager.menu.link', '@database', '@database.replica_kill_switch'] + arguments: ['@lock', '@plugin.manager.menu.link', '@database', '@database.replica_kill_switch', '@logger.channel.menu'] tags: - { name: event_subscriber } path.matcher: diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 332f40e1bb2c..fdbe3f238cf4 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -124,8 +124,14 @@ function t($string, array $args = [], array $options = []) { * A link to associate with the message. * * @see \Drupal\Core\Utility\Error::decodeException() + * + * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use + * Use \Drupal\Core\Utility\Error::logException() instead. + * + * @see https://www.drupal.org/node/2932520 */ function watchdog_exception($type, Exception $exception, $message = NULL, $variables = [], $severity = RfcLogLevel::ERROR, $link = NULL) { + @trigger_error('watchdog_exception() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use \Drupal\Core\Utility\Error::logException() instead. See https://www.drupal.org/node/2932520', E_USER_DEPRECATED); // Use a default value if $message is not set. if (empty($message)) { diff --git a/core/includes/update.inc b/core/includes/update.inc index dac375df909f..2549249253f1 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -175,9 +175,9 @@ function update_do_one($module, $number, $dependency_map, &$context) { // return the message for printing. // @see https://www.drupal.org/node/2564311 catch (Exception $e) { - watchdog_exception('update', $e); - $variables = Error::decodeException($e); + \Drupal::logger('update')->error(Error::DEFAULT_ERROR_MESSAGE, $variables); + unset($variables['backtrace'], $variables['exception'], $variables['severity_level']); $ret['#abort'] = ['success' => FALSE, 'query' => t(Error::DEFAULT_ERROR_MESSAGE, $variables)]; } @@ -244,9 +244,8 @@ function update_invoke_post_update($function, &$context) { // for printing. // @see https://www.drupal.org/node/2564311 catch (Exception $e) { - watchdog_exception('update', $e); - $variables = Error::decodeException($e); + \Drupal::logger('update')->error(Error::DEFAULT_ERROR_MESSAGE, $variables); unset($variables['backtrace'], $variables['exception'], $variables['severity_level']); $ret['#abort'] = [ 'success' => FALSE, diff --git a/core/lib/Drupal/Core/Cron.php b/core/lib/Drupal/Core/Cron.php index e48e7ef6a79d..146394341546 100644 --- a/core/lib/Drupal/Core/Cron.php +++ b/core/lib/Drupal/Core/Cron.php @@ -7,17 +7,18 @@ use Drupal\Component\Utility\Timer; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Lock\LockBackendInterface; -use Drupal\Core\Queue\QueueFactory; use Drupal\Core\Queue\DelayableQueueInterface; +use Drupal\Core\Queue\DelayedRequeueException; +use Drupal\Core\Queue\QueueFactory; use Drupal\Core\Queue\QueueInterface; use Drupal\Core\Queue\QueueWorkerInterface; use Drupal\Core\Queue\QueueWorkerManagerInterface; -use Drupal\Core\Queue\DelayedRequeueException; use Drupal\Core\Queue\RequeueException; use Drupal\Core\Queue\SuspendQueueException; use Drupal\Core\Session\AccountSwitcherInterface; use Drupal\Core\Session\AnonymousUserSession; use Drupal\Core\State\StateInterface; +use Drupal\Core\Utility\Error; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; @@ -298,7 +299,7 @@ protected function processQueue(QueueInterface $queue, QueueWorkerInterface $wor catch (\Exception $e) { // In case of any other kind of exception, log it and leave the item // in the queue to be processed again later. - watchdog_exception('cron', $e); + Error::logException($this->logger, $e); } } } @@ -334,7 +335,7 @@ protected function invokeCronHandlers() { $hook(); } catch (\Exception $e) { - watchdog_exception('cron', $e); + Error::logException($this->logger, $e); } Timer::stop('cron_' . $module); diff --git a/core/lib/Drupal/Core/Database/Transaction.php b/core/lib/Drupal/Core/Database/Transaction.php index 8aed8c8ae672..76d5fc8f5fac 100644 --- a/core/lib/Drupal/Core/Database/Transaction.php +++ b/core/lib/Drupal/Core/Database/Transaction.php @@ -84,12 +84,10 @@ public function name() { * * This is just a wrapper method to rollback whatever transaction stack we are * currently in, which is managed by the connection object itself. Note that - * logging (preferable with watchdog_exception()) needs to happen after a - * transaction has been rolled back or the log messages will be rolled back - * too. + * logging needs to happen after a transaction has been rolled back or the log + * messages will be rolled back too. * * @see \Drupal\Core\Database\Connection::rollBack() - * @see watchdog_exception() */ public function rollBack() { $this->rolledBack = TRUE; diff --git a/core/lib/Drupal/Core/Database/database.api.php b/core/lib/Drupal/Core/Database/database.api.php index e4e5a0b9be08..50e4bb506073 100644 --- a/core/lib/Drupal/Core/Database/database.api.php +++ b/core/lib/Drupal/Core/Database/database.api.php @@ -201,8 +201,8 @@ * $transaction->rollBack(); * } * - * // Log the exception to watchdog. - * watchdog_exception('type', $e); + * // Log the exception. + * Error::logException(\Drupal::logger('type'), $e); * } * * // $transaction goes out of scope here. Unless the transaction was rolled diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php index 01bf60ecd2bf..c65c623fef01 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php @@ -14,16 +14,17 @@ use Drupal\Core\Entity\EntityBundleListenerInterface; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Entity\EntityTypeBundleInfoInterface; -use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\EntityStorageException; +use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\Query\QueryInterface; use Drupal\Core\Entity\Schema\DynamicallyFieldableEntityStorageSchemaInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Language\LanguageManagerInterface; +use Drupal\Core\Utility\Error; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -758,7 +759,7 @@ public function delete(array $entities) { if (isset($transaction)) { $transaction->rollBack(); } - watchdog_exception($this->entityTypeId, $e); + Error::logException(\Drupal::logger($this->entityTypeId), $e); throw new EntityStorageException($e->getMessage(), $e->getCode(), $e); } } @@ -812,7 +813,7 @@ public function save(EntityInterface $entity) { if (isset($transaction)) { $transaction->rollBack(); } - watchdog_exception($this->entityTypeId, $e); + Error::logException(\Drupal::logger($this->entityTypeId), $e); throw new EntityStorageException($e->getMessage(), $e->getCode(), $e); } } @@ -861,7 +862,7 @@ public function restore(EntityInterface $entity) { if (isset($transaction)) { $transaction->rollBack(); } - watchdog_exception($this->entityTypeId, $e); + Error::logException(\Drupal::logger($this->entityTypeId), $e); throw new EntityStorageException($e->getMessage(), $e->getCode(), $e); } } diff --git a/core/lib/Drupal/Core/EventSubscriber/MenuRouterRebuildSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/MenuRouterRebuildSubscriber.php index 7d0d64c0ad30..a3aa52e863ef 100644 --- a/core/lib/Drupal/Core/EventSubscriber/MenuRouterRebuildSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/MenuRouterRebuildSubscriber.php @@ -3,11 +3,13 @@ namespace Drupal\Core\EventSubscriber; use Drupal\Core\Cache\Cache; +use Drupal\Core\Database\Connection; use Drupal\Core\Database\ReplicaKillSwitch; use Drupal\Core\Lock\LockBackendInterface; use Drupal\Core\Menu\MenuLinkManagerInterface; use Drupal\Core\Routing\RoutingEvents; -use Drupal\Core\Database\Connection; +use Drupal\Core\Utility\Error; +use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -52,12 +54,18 @@ class MenuRouterRebuildSubscriber implements EventSubscriberInterface { * The database connection. * @param \Drupal\Core\Database\ReplicaKillSwitch $replica_kill_switch * The replica kill switch. + * @param \Psr\Log\LoggerInterface|null $logger + * The logger. */ - public function __construct(LockBackendInterface $lock, MenuLinkManagerInterface $menu_link_manager, Connection $connection, ReplicaKillSwitch $replica_kill_switch) { + public function __construct(LockBackendInterface $lock, MenuLinkManagerInterface $menu_link_manager, Connection $connection, ReplicaKillSwitch $replica_kill_switch, protected ?LoggerInterface $logger = NULL) { $this->lock = $lock; $this->menuLinkManager = $menu_link_manager; $this->connection = $connection; $this->replicaKillSwitch = $replica_kill_switch; + if ($this->logger === NULL) { + @trigger_error('Calling ' . __METHOD__ . '() without the $logger argument is deprecated in drupal:10.1.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/2932520', E_USER_DEPRECATED); + $this->logger = \Drupal::service('logger.channel.menu'); + } } /** @@ -87,7 +95,7 @@ protected function menuLinksRebuild() { if (isset($transaction)) { $transaction->rollBack(); } - watchdog_exception('menu', $e); + Error::logException($this->logger, $e); } $this->lock->release(__FUNCTION__); diff --git a/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/core/lib/Drupal/Core/Extension/ModuleInstaller.php index a224491f6b02..7e53d711d59e 100644 --- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php @@ -12,6 +12,8 @@ use Drupal\Core\Installer\InstallerKernel; use Drupal\Core\Serialization\Yaml; use Drupal\Core\Update\UpdateHookRegistry; +use Drupal\Core\Utility\Error; +use Psr\Log\LoggerInterface; /** * Default implementation of the module installer. @@ -81,16 +83,22 @@ class ModuleInstaller implements ModuleInstallerInterface { * The database connection. * @param \Drupal\Core\Update\UpdateHookRegistry $update_registry * The update registry service. + * @param \Psr\Log\LoggerInterface|null $logger + * The logger. * * @see \Drupal\Core\DrupalKernel * @see \Drupal\Core\CoreServiceProvider */ - public function __construct($root, ModuleHandlerInterface $module_handler, DrupalKernelInterface $kernel, Connection $connection, UpdateHookRegistry $update_registry) { + public function __construct($root, ModuleHandlerInterface $module_handler, DrupalKernelInterface $kernel, Connection $connection, UpdateHookRegistry $update_registry, protected ?LoggerInterface $logger = NULL) { $this->root = $root; $this->moduleHandler = $module_handler; $this->kernel = $kernel; $this->connection = $connection; $this->updateRegistry = $update_registry; + if ($this->logger === NULL) { + @trigger_error('Calling ' . __METHOD__ . ' without the $logger argument is deprecated in drupal:10.1.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/2932520', E_USER_DEPRECATED); + $this->logger = \Drupal::service('logger.channel.system'); + } } /** @@ -302,7 +310,7 @@ public function install(array $module_list, $enable_dependencies = TRUE) { $update_manager->installFieldStorageDefinition($storage_definition->getName(), $entity_type->id(), $module, $storage_definition); } catch (EntityStorageException $e) { - watchdog_exception('system', $e, 'An error occurred while notifying the creation of the @name field storage definition: "@message" in %function (line %line of %file).', ['@name' => $storage_definition->getName(), '@message' => $e->getMessage()]); + Error::logException($this->logger, $e, 'An error occurred while notifying the creation of the @name field storage definition: "@message" in %function (line %line of %file).', ['@name' => $storage_definition->getName()]); } } } diff --git a/core/lib/Drupal/Core/Routing/MatcherDumper.php b/core/lib/Drupal/Core/Routing/MatcherDumper.php index 2757012f254b..cbd3aac0d048 100644 --- a/core/lib/Drupal/Core/Routing/MatcherDumper.php +++ b/core/lib/Drupal/Core/Routing/MatcherDumper.php @@ -4,6 +4,8 @@ use Drupal\Core\Database\DatabaseException; use Drupal\Core\State\StateInterface; +use Drupal\Core\Utility\Error; +use Psr\Log\LoggerInterface; use Symfony\Component\Routing\RouteCollection; use Drupal\Core\Database\Connection; @@ -43,6 +45,13 @@ class MatcherDumper implements MatcherDumperInterface { */ protected $tableName; + /** + * The logger. + * + * @var \Psr\Log\LoggerInterface + */ + protected LoggerInterface $logger; + /** * Construct the MatcherDumper. * @@ -51,14 +60,25 @@ class MatcherDumper implements MatcherDumperInterface { * information. * @param \Drupal\Core\State\StateInterface $state * The state. + * @param \Psr\Log\LoggerInterface|null $logger + * The logger. * @param string $table * (optional) The table to store the route info in. Defaults to 'router'. */ - public function __construct(Connection $connection, StateInterface $state, $table = 'router') { + public function __construct(Connection $connection, StateInterface $state, LoggerInterface|string|null $logger = NULL, $table = 'router') { $this->connection = $connection; $this->state = $state; - - $this->tableName = $table; + if (is_string($logger) || is_null($logger)) { + @trigger_error('Calling ' . __METHOD__ . '() without the $logger argument is deprecated in drupal:10.1.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/2932520', E_USER_DEPRECATED); + $this->logger = \Drupal::service('logger.channel.router'); + $this->tableName = $logger; + } + else { + $this->logger = $logger; + } + if (is_null($this->tableName)) { + $this->tableName = $table; + } } /** @@ -152,7 +172,7 @@ public function dump(array $options = []): string { if (isset($transaction)) { $transaction->rollBack(); } - watchdog_exception('Routing', $e); + Error::logException($this->logger, $e); throw $e; } // Sort the masks so they are in order of descending fit. diff --git a/core/lib/Drupal/Core/Utility/Error.php b/core/lib/Drupal/Core/Utility/Error.php index d5bb777f06f0..ab8c3bfa90bd 100644 --- a/core/lib/Drupal/Core/Utility/Error.php +++ b/core/lib/Drupal/Core/Utility/Error.php @@ -7,6 +7,8 @@ use Drupal\Core\Database\Connection; use Drupal\Core\Database\Database; use Drupal\Core\Database\DatabaseExceptionWrapper; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; /** * Drupal error utility class. @@ -75,6 +77,24 @@ public static function decodeException($exception) { ]; } + /** + * Log a formatted exception message to the provided logger. + * + * @param \Psr\Log\LoggerInterface $logger + * The logger. + * @param \Throwable $exception + * The exception. + * @param string $message + * (optional) The message. + * @param array $additional_variables + * (optional) Any additional variables. + * @param string $level + * The PSR log level. Must be valid constant in \Psr\Log\LogLevel. + */ + public static function logException(LoggerInterface $logger, \Throwable $exception, string $message = Error::DEFAULT_ERROR_MESSAGE, array $additional_variables = [], string $level = LogLevel::ERROR): void { + $logger->log($level, $message, static::decodeException($exception) + $additional_variables); + } + /** * Renders an exception error message without further exceptions. * diff --git a/core/modules/sdc/sdc.services.yml b/core/modules/sdc/sdc.services.yml index e9ad6726b9f9..519acef6100d 100644 --- a/core/modules/sdc/sdc.services.yml +++ b/core/modules/sdc/sdc.services.yml @@ -8,6 +8,7 @@ services: Drupal\sdc\Twig\TwigComponentLoader: arguments: - '@plugin.manager.sdc' + - '@logger.channel.default' tags: - { name: twig.loader, priority: 5 } diff --git a/core/modules/sdc/src/Twig/TwigComponentLoader.php b/core/modules/sdc/src/Twig/TwigComponentLoader.php index f530dbc714e8..baa069a7584a 100644 --- a/core/modules/sdc/src/Twig/TwigComponentLoader.php +++ b/core/modules/sdc/src/Twig/TwigComponentLoader.php @@ -2,9 +2,11 @@ namespace Drupal\sdc\Twig; +use Drupal\Core\Utility\Error; use Drupal\sdc\ComponentPluginManager; use Drupal\sdc\Exception\ComponentNotFoundException; use Drupal\Component\Discovery\YamlDirectoryDiscovery; +use Psr\Log\LoggerInterface; use Twig\Error\LoaderError; use Twig\Loader\LoaderInterface; use Twig\Source; @@ -21,8 +23,13 @@ final class TwigComponentLoader implements LoaderInterface { * * @param \Drupal\sdc\ComponentPluginManager $pluginManager * The plugin manager. + * @param \Psr\Log\LoggerInterface $logger + * The logger. */ - public function __construct(protected ComponentPluginManager $pluginManager) {} + public function __construct( + protected ComponentPluginManager $pluginManager, + protected LoggerInterface $logger, + ) {} /** * Finds a template in the file system based on the template name. @@ -69,7 +76,7 @@ public function exists($name): bool { return TRUE; } catch (ComponentNotFoundException $e) { - watchdog_exception('sdc', $e); + Error::logException($this->logger, $e); return FALSE; } } diff --git a/core/modules/system/src/SecurityAdvisories/SecurityAdvisoriesFetcher.php b/core/modules/system/src/SecurityAdvisories/SecurityAdvisoriesFetcher.php index b8b0a5323692..3b29384231a6 100644 --- a/core/modules/system/src/SecurityAdvisories/SecurityAdvisoriesFetcher.php +++ b/core/modules/system/src/SecurityAdvisories/SecurityAdvisoriesFetcher.php @@ -9,6 +9,7 @@ use Drupal\Core\Extension\ThemeExtensionList; use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface; use Drupal\Core\Site\Settings; +use Drupal\Core\Utility\Error; use Drupal\Core\Utility\ProjectInfo; use Drupal\Core\Extension\ExtensionVersion; use GuzzleHttp\ClientInterface; @@ -152,7 +153,7 @@ public function getSecurityAdvisories(bool $allow_outgoing_request = TRUE, int $ // Ignore items in the feed that are in an invalid format. Although // this is highly unlikely we should still display the items that are // in the correct format. - watchdog_exception('system', $unexpected_value_exception, 'Invalid security advisory format: ' . Json::encode($advisory_data)); + Error::logException($this->logger, $unexpected_value_exception, 'Invalid security advisory format: @advisory', ['@advisory' => Json::encode($advisory_data)]); continue; } @@ -321,7 +322,7 @@ protected function doRequest(int $timeout): string { $response = $this->httpClient->get('https://updates.drupal.org/psa.json', $options); } catch (TransferException $exception) { - watchdog_exception('system', $exception); + Error::logException($this->logger, $exception); $response = $this->httpClient->get('http://updates.drupal.org/psa.json', $options); } } diff --git a/core/modules/system/system.install b/core/modules/system/system.install index b7a7e10dad16..c6513010faa0 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -25,6 +25,7 @@ use Drupal\Core\StringTranslation\PluralTranslatableMarkup; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Url; +use Drupal\Core\Utility\Error; use GuzzleHttp\Exception\TransferException; use Symfony\Component\HttpFoundation\Request; @@ -1652,7 +1653,7 @@ function _system_advisories_requirements(array &$requirements): void { $requirements['system_advisories']['title'] = t('Critical security announcements'); $requirements['system_advisories']['severity'] = REQUIREMENT_WARNING; $requirements['system_advisories']['description'] = ['#theme' => 'system_security_advisories_fetch_error_message']; - watchdog_exception('system', $exception, 'Failed to retrieve security advisory data.'); + Error::logException(\Drupal::logger('system'), $exception, 'Failed to retrieve security advisory data.'); return; } diff --git a/core/modules/system/tests/src/Kernel/SecurityAdvisories/SecurityAdvisoriesFetcherTest.php b/core/modules/system/tests/src/Kernel/SecurityAdvisories/SecurityAdvisoriesFetcherTest.php index da258d42712e..c6cebd1201a6 100644 --- a/core/modules/system/tests/src/Kernel/SecurityAdvisories/SecurityAdvisoriesFetcherTest.php +++ b/core/modules/system/tests/src/Kernel/SecurityAdvisories/SecurityAdvisoriesFetcherTest.php @@ -26,11 +26,11 @@ class SecurityAdvisoriesFetcherTest extends KernelTestBase implements LoggerInte use RfcLoggerTrait; /** - * The log messages from watchdog_exception. + * The error messages. * * @var string[] */ - protected $watchdogExceptionMessages = []; + protected $errorMessages = []; /** * The log error log messages. @@ -658,7 +658,7 @@ public function testHttpFallback(): void { $this->assertCount(1, $advisories); $this->assertSame('http://example.com', $advisories[0]->getUrl()); $this->assertSame('SA title', $advisories[0]->getTitle()); - $this->assertSame(["Server error: `GET https://updates.drupal.org/psa.json` resulted in a `500 Internal Server Error` response:\nHTTPS failed\n"], $this->watchdogExceptionMessages); + $this->assertSame(["Server error: `GET https://updates.drupal.org/psa.json` resulted in a `500 Internal Server Error` response:\nHTTPS failed\n"], $this->errorMessages); } /** @@ -745,7 +745,7 @@ protected function assertServiceAdvisoryLoggedErrors(array $expected_messages): */ public function log($level, $message, array $context = []): void { if (isset($context['@message'])) { - $this->watchdogExceptionMessages[] = $context['@message']; + $this->errorMessages[] = $context['@message']; } if ($level === RfcLogLevel::ERROR) { $this->logErrorMessages[] = $message; diff --git a/core/modules/update/src/ProjectSecurityData.php b/core/modules/update/src/ProjectSecurityData.php index 6c927c5e0f3f..daa210568981 100644 --- a/core/modules/update/src/ProjectSecurityData.php +++ b/core/modules/update/src/ProjectSecurityData.php @@ -3,6 +3,7 @@ namespace Drupal\update; use Drupal\Core\Extension\ExtensionVersion; +use Drupal\Core\Utility\Error; /** * Calculates a project's security coverage information. @@ -224,12 +225,7 @@ private function getAdditionalSecurityCoveredMinors($security_covered_version) { // Ignore releases that are in an invalid format. Although this is // highly unlikely we should still process releases in the correct // format. - watchdog_exception( - 'update', - $exception, - 'Invalid project format: @release', - ['@release' => print_r($release_info, TRUE)] - ); + Error::logException(\Drupal::logger('update'), $exception, 'Invalid project format: @release', ['@release' => print_r($release_info, TRUE)]); continue; } $release_version = ExtensionVersion::createFromVersionString($release->getVersion()); diff --git a/core/modules/update/src/UpdateFetcher.php b/core/modules/update/src/UpdateFetcher.php index 6d7c71cc04dc..9a6704ac68f0 100644 --- a/core/modules/update/src/UpdateFetcher.php +++ b/core/modules/update/src/UpdateFetcher.php @@ -5,8 +5,10 @@ use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\DependencyInjection\DependencySerializationTrait; use Drupal\Core\Site\Settings; +use Drupal\Core\Utility\Error; use GuzzleHttp\ClientInterface; use GuzzleHttp\Exception\TransferException; +use Psr\Log\LoggerInterface; /** * Fetches project information from remote locations. @@ -57,12 +59,18 @@ class UpdateFetcher implements UpdateFetcherInterface { * A Guzzle client object. * @param \Drupal\Core\Site\Settings $settings * The settings instance. + * @param \Psr\Log\LoggerInterface|null $logger + * The logger. */ - public function __construct(ConfigFactoryInterface $config_factory, ClientInterface $http_client, Settings $settings) { + public function __construct(ConfigFactoryInterface $config_factory, ClientInterface $http_client, Settings $settings, protected ?LoggerInterface $logger = NULL) { $this->fetchUrl = $config_factory->get('update.settings')->get('fetch.url'); $this->httpClient = $http_client; $this->updateSettings = $config_factory->get('update.settings'); $this->withHttpFallback = $settings->get('update_fetch_with_http_fallback', FALSE); + if ($this->logger === NULL) { + @trigger_error('Calling ' . __METHOD__ . '() without the $logger argument is deprecated in drupal:10.1.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/2932520', E_USER_DEPRECATED); + $this->logger = \Drupal::service('logger.channel.update'); + } } /** @@ -97,7 +105,7 @@ protected function doRequest(string $url, array $options, bool $with_http_fallba ->getBody(); } catch (TransferException $exception) { - watchdog_exception('update', $exception); + Error::logException($this->logger, $exception); if ($with_http_fallback && !str_contains($url, "http://")) { $url = str_replace('https://', 'http://', $url); return $this->doRequest($url, $options, FALSE); diff --git a/core/modules/update/tests/src/Unit/UpdateFetcherTest.php b/core/modules/update/tests/src/Unit/UpdateFetcherTest.php index 325d687dee9c..cde0a60c3ded 100644 --- a/core/modules/update/tests/src/Unit/UpdateFetcherTest.php +++ b/core/modules/update/tests/src/Unit/UpdateFetcherTest.php @@ -2,8 +2,7 @@ namespace Drupal\Tests\update\Unit; -use Drupal\Core\Logger\LoggerChannelFactory; -use Drupal\Core\Logger\RfcLoggerTrait; +use ColinODell\PsrTestLogger\TestLogger; use Drupal\Core\Site\Settings; use Drupal\Tests\UnitTestCase; use Drupal\update\UpdateFetcher; @@ -21,8 +20,7 @@ * * @group update */ -class UpdateFetcherTest extends UnitTestCase implements LoggerInterface { - use RfcLoggerTrait; +class UpdateFetcherTest extends UnitTestCase { /** * The update fetcher to use. @@ -60,9 +58,11 @@ class UpdateFetcherTest extends UnitTestCase implements LoggerInterface { protected $testProject; /** - * @var array + * The logger. + * + * @var \Psr\Log\LoggerInterface */ - protected $logMessages = []; + protected LoggerInterface $logger; /** * {@inheritdoc} @@ -72,7 +72,8 @@ protected function setUp(): void { $this->mockConfigFactory = $this->getConfigFactoryStub(['update.settings' => ['fetch_url' => 'http://www.example.com']]); $this->mockHttpClient = $this->createMock('\GuzzleHttp\ClientInterface'); $settings = new Settings([]); - $this->updateFetcher = new UpdateFetcher($this->mockConfigFactory, $this->mockHttpClient, $settings); + $this->logger = new TestLogger(); + $this->updateFetcher = new UpdateFetcher($this->mockConfigFactory, $this->mockHttpClient, $settings, $this->logger); $this->testProject = [ 'name' => 'update_test', 'project_type' => '', @@ -82,17 +83,6 @@ protected function setUp(): void { ], 'includes' => ['module1' => 'Module 1', 'module2' => 'Module 2'], ]; - - // Set up logger factory so that watchdog_exception() does not break and - // register this class as the logger so we can test messages. - $container = $this->createMock('Symfony\Component\DependencyInjection\ContainerInterface'); - $logger_factory = new LoggerChannelFactory(); - $logger_factory->addLogger($this); - $container->expects($this->any()) - ->method('get') - ->with('logger.factory') - ->willReturn($logger_factory); - \Drupal::setContainer($container); } /** @@ -113,7 +103,7 @@ protected function setUp(): void { public function testUpdateBuildFetchUrl(array $project, $site_key, $expected) { $url = $this->updateFetcher->buildFetchUrl($project, $site_key); $this->assertEquals($url, $expected); - $this->assertSame([], $this->logMessages); + $this->assertFalse($this->logger->hasErrorRecords()); } /** @@ -190,7 +180,7 @@ public function testUpdateFetcherNoFallback() { $this->mockClient( new Response('500', [], 'HTTPS failed'), ); - $update_fetcher = new UpdateFetcher($this->mockConfigFactory, $this->mockHttpClient, $settings); + $update_fetcher = new UpdateFetcher($this->mockConfigFactory, $this->mockHttpClient, $settings, $this->logger); $data = $update_fetcher->fetchProjectData($this->testProject, ''); // There should only be one request / response pair. @@ -203,7 +193,10 @@ public function testUpdateFetcherNoFallback() { $response = $this->history[0]['response']; $this->assertEquals(500, $response->getStatusCode()); $this->assertEmpty($data); - $this->assertSame(["Server error: `GET https://www.example.com/update_test/current` resulted in a `500 Internal Server Error` response:\nHTTPS failed\n"], $this->logMessages); + + $this->assertTrue($this->logger->hasErrorThatPasses(function (array $record) { + return $record['context']['@message'] === "Server error: `GET https://www.example.com/update_test/current` resulted in a `500 Internal Server Error` response:\nHTTPS failed\n"; + })); } /** @@ -216,7 +209,7 @@ public function testUpdateFetcherHttpFallback() { new Response('500', [], 'HTTPS failed'), new Response('200', [], 'HTTP worked'), ); - $update_fetcher = new UpdateFetcher($this->mockConfigFactory, $this->mockHttpClient, $settings); + $update_fetcher = new UpdateFetcher($this->mockConfigFactory, $this->mockHttpClient, $settings, $this->logger); $data = $update_fetcher->fetchProjectData($this->testProject, ''); @@ -237,14 +230,9 @@ public function testUpdateFetcherHttpFallback() { // Although this is a bogus mocked response, it's what fetchProjectData() // should return in this case. $this->assertEquals('HTTP worked', $data); - $this->assertSame(["Server error: `GET https://www.example.com/update_test/current` resulted in a `500 Internal Server Error` response:\nHTTPS failed\n"], $this->logMessages); - } - - /** - * {@inheritdoc} - */ - public function log($level, string|\Stringable $message, array $context = []): void { - $this->logMessages[] = $context['@message']; + $this->assertTrue($this->logger->hasErrorThatPasses(function (array $record) { + return $record['context']['@message'] === "Server error: `GET https://www.example.com/update_test/current` resulted in a `500 Internal Server Error` response:\nHTTPS failed\n"; + })); } } diff --git a/core/modules/update/update.compare.inc b/core/modules/update/update.compare.inc index 7b8fc6899cfd..d1b5a8e73de9 100644 --- a/core/modules/update/update.compare.inc +++ b/core/modules/update/update.compare.inc @@ -6,6 +6,7 @@ */ use Drupal\Core\Extension\ExtensionVersion; +use Drupal\Core\Utility\Error; use Drupal\update\ProjectRelease; use Drupal\update\UpdateFetcherInterface; use Drupal\update\UpdateManagerInterface; @@ -363,12 +364,7 @@ function update_calculate_project_update_status(&$project_data, $available) { catch (UnexpectedValueException $exception) { // Ignore releases that are in an invalid format. Although this is highly // unlikely we should still process releases in the correct format. - watchdog_exception( - 'update', - $exception, - 'Invalid project format: @release', - ['@release' => print_r($release_info, TRUE)] - ); + Error::logException(\Drupal::logger('update'), $exception, 'Invalid project format: @release', ['@release' => print_r($release_info, TRUE)]); continue; } diff --git a/core/modules/update/update.services.yml b/core/modules/update/update.services.yml index d243fedcdbeb..545612dcb35b 100644 --- a/core/modules/update/update.services.yml +++ b/core/modules/update/update.services.yml @@ -12,7 +12,10 @@ services: arguments: ['@config.factory', '@queue', '@update.fetcher', '@state', '@private_key', '@keyvalue', '@keyvalue.expirable'] update.fetcher: class: Drupal\update\UpdateFetcher - arguments: ['@config.factory', '@http_client', '@settings'] + arguments: ['@config.factory', '@http_client', '@settings', '@logger.channel.update'] update.root: class: Drupal\update\UpdateRoot arguments: ['@kernel', '@request_stack'] + logger.channel.update: + parent: logger.channel_base + arguments: [ 'update' ] diff --git a/core/modules/workspaces/src/WorkspaceAssociation.php b/core/modules/workspaces/src/WorkspaceAssociation.php index aa6f8078a24a..c9bcee9219ec 100644 --- a/core/modules/workspaces/src/WorkspaceAssociation.php +++ b/core/modules/workspaces/src/WorkspaceAssociation.php @@ -6,8 +6,10 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\RevisionableInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorage; +use Drupal\Core\Utility\Error; use Drupal\workspaces\Event\WorkspacePostPublishEvent; use Drupal\workspaces\Event\WorkspacePublishEvent; +use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -50,11 +52,17 @@ class WorkspaceAssociation implements WorkspaceAssociationInterface, EventSubscr * The entity type manager for querying revisions. * @param \Drupal\workspaces\WorkspaceRepositoryInterface $workspace_repository * The Workspace repository service. + * @param \Psr\Log\LoggerInterface|null $logger + * The logger. */ - public function __construct(Connection $connection, EntityTypeManagerInterface $entity_type_manager, WorkspaceRepositoryInterface $workspace_repository) { + public function __construct(Connection $connection, EntityTypeManagerInterface $entity_type_manager, WorkspaceRepositoryInterface $workspace_repository, protected ?LoggerInterface $logger = NULL) { $this->database = $connection; $this->entityTypeManager = $entity_type_manager; $this->workspaceRepository = $workspace_repository; + if ($this->logger === NULL) { + @trigger_error('Calling ' . __METHOD__ . '() without the $logger argument is deprecated in drupal:10.1.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/2932520', E_USER_DEPRECATED); + $this->logger = \Drupal::service('logger.channel.workspaces'); + } } /** @@ -116,7 +124,7 @@ public function trackEntity(RevisionableInterface $entity, WorkspaceInterface $w if (isset($transaction)) { $transaction->rollBack(); } - watchdog_exception('workspaces', $e); + Error::logException($this->logger, $e); throw $e; } } diff --git a/core/modules/workspaces/src/WorkspaceMerger.php b/core/modules/workspaces/src/WorkspaceMerger.php index afdabc755ada..2500ea157748 100644 --- a/core/modules/workspaces/src/WorkspaceMerger.php +++ b/core/modules/workspaces/src/WorkspaceMerger.php @@ -5,6 +5,8 @@ use Drupal\Core\Cache\CacheTagsInvalidatorInterface; use Drupal\Core\Database\Connection; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Utility\Error; +use Psr\Log\LoggerInterface; /** * Default implementation of the workspace merger. @@ -70,14 +72,20 @@ class WorkspaceMerger implements WorkspaceMergerInterface { * The source workspace. * @param \Drupal\workspaces\WorkspaceInterface $target * The target workspace. + * @param \Psr\Log\LoggerInterface|null $logger + * The logger. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, WorkspaceAssociationInterface $workspace_association, CacheTagsInvalidatorInterface $cache_tags_invalidator, WorkspaceInterface $source, WorkspaceInterface $target) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, WorkspaceAssociationInterface $workspace_association, CacheTagsInvalidatorInterface $cache_tags_invalidator, WorkspaceInterface $source, WorkspaceInterface $target, protected ?LoggerInterface $logger = NULL) { $this->entityTypeManager = $entity_type_manager; $this->database = $database; $this->workspaceAssociation = $workspace_association; $this->cacheTagsInvalidator = $cache_tags_invalidator; $this->sourceWorkspace = $source; $this->targetWorkspace = $target; + if ($this->logger === NULL) { + @trigger_error('Calling ' . __METHOD__ . '() without the $logger argument is deprecated in drupal:10.1.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/2932520', E_USER_DEPRECATED); + $this->logger = \Drupal::service('logger.channel.workspaces'); + } } /** @@ -116,7 +124,7 @@ public function merge() { if (isset($transaction)) { $transaction->rollBack(); } - watchdog_exception('workspaces', $e); + Error::logException($this->logger, $e); throw $e; } } diff --git a/core/modules/workspaces/src/WorkspaceOperationFactory.php b/core/modules/workspaces/src/WorkspaceOperationFactory.php index 4310243ff206..1f4474cd4e54 100644 --- a/core/modules/workspaces/src/WorkspaceOperationFactory.php +++ b/core/modules/workspaces/src/WorkspaceOperationFactory.php @@ -5,6 +5,7 @@ use Drupal\Core\Cache\CacheTagsInvalidatorInterface; use Drupal\Core\Database\Connection; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Psr\Log\LoggerInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** @@ -74,8 +75,10 @@ class WorkspaceOperationFactory { * The cache tags invalidator service. * @param \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $event_dispatcher * The event dispatcher. + * @param \Psr\Log\LoggerInterface|null $logger + * The logger. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, WorkspaceManagerInterface $workspace_manager, WorkspaceAssociationInterface $workspace_association, CacheTagsInvalidatorInterface $cache_tags_invalidator, EventDispatcherInterface $event_dispatcher = NULL) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, WorkspaceManagerInterface $workspace_manager, WorkspaceAssociationInterface $workspace_association, CacheTagsInvalidatorInterface $cache_tags_invalidator, EventDispatcherInterface $event_dispatcher = NULL, protected ?LoggerInterface $logger = NULL) { $this->entityTypeManager = $entity_type_manager; $this->database = $database; $this->workspaceManager = $workspace_manager; @@ -86,6 +89,10 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Con $event_dispatcher = \Drupal::service('event_dispatcher'); } $this->eventDispatcher = $event_dispatcher; + if ($this->logger === NULL) { + @trigger_error('Calling ' . __METHOD__ . '() without the $logger argument is deprecated in drupal:10.1.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/2932520', E_USER_DEPRECATED); + $this->logger = \Drupal::service('logger.channel.workspaces'); + } } /** @@ -98,7 +105,7 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Con * A workspace publisher object. */ public function getPublisher(WorkspaceInterface $source) { - return new WorkspacePublisher($this->entityTypeManager, $this->database, $this->workspaceManager, $this->workspaceAssociation, $this->eventDispatcher, $source); + return new WorkspacePublisher($this->entityTypeManager, $this->database, $this->workspaceManager, $this->workspaceAssociation, $this->eventDispatcher, $source, $this->logger); } /** @@ -113,7 +120,7 @@ public function getPublisher(WorkspaceInterface $source) { * A workspace merger object. */ public function getMerger(WorkspaceInterface $source, WorkspaceInterface $target) { - return new WorkspaceMerger($this->entityTypeManager, $this->database, $this->workspaceAssociation, $this->cacheTagsInvalidator, $source, $target); + return new WorkspaceMerger($this->entityTypeManager, $this->database, $this->workspaceAssociation, $this->cacheTagsInvalidator, $source, $target, $this->logger); } } diff --git a/core/modules/workspaces/src/WorkspacePublisher.php b/core/modules/workspaces/src/WorkspacePublisher.php index a05b894318e4..79cd067f0e2a 100644 --- a/core/modules/workspaces/src/WorkspacePublisher.php +++ b/core/modules/workspaces/src/WorkspacePublisher.php @@ -5,8 +5,10 @@ use Drupal\Core\Database\Connection; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Core\Utility\Error; use Drupal\workspaces\Event\WorkspacePostPublishEvent; use Drupal\workspaces\Event\WorkspacePrePublishEvent; +use Psr\Log\LoggerInterface; /** * Default implementation of the workspace publisher. @@ -74,8 +76,10 @@ class WorkspacePublisher implements WorkspacePublisherInterface { * The event dispatcher. * @param \Drupal\workspaces\WorkspaceInterface $source * The source workspace entity. + * @param \Psr\Log\LoggerInterface|null $logger + * The logger. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, WorkspaceManagerInterface $workspace_manager, WorkspaceAssociationInterface $workspace_association, $event_dispatcher, WorkspaceInterface $source = NULL) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, WorkspaceManagerInterface $workspace_manager, WorkspaceAssociationInterface $workspace_association, $event_dispatcher, WorkspaceInterface $source = NULL, protected ?LoggerInterface $logger = NULL) { $this->entityTypeManager = $entity_type_manager; $this->database = $database; $this->workspaceManager = $workspace_manager; @@ -87,6 +91,10 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Con } $this->eventDispatcher = $event_dispatcher; $this->sourceWorkspace = $source; + if ($this->logger === NULL) { + @trigger_error('Calling ' . __METHOD__ . '() without the $logger argument is deprecated in drupal:10.1.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/2932520', E_USER_DEPRECATED); + $this->logger = \Drupal::service('logger.channel.workspaces'); + } } /** @@ -142,7 +150,7 @@ public function publish() { if (isset($transaction)) { $transaction->rollBack(); } - watchdog_exception('workspaces', $e); + Error::logException($this->logger, $e); throw $e; } diff --git a/core/modules/workspaces/workspaces.services.yml b/core/modules/workspaces/workspaces.services.yml index 57b02cd82649..4aa7de957aa1 100644 --- a/core/modules/workspaces/workspaces.services.yml +++ b/core/modules/workspaces/workspaces.services.yml @@ -6,10 +6,10 @@ services: - { name: service_id_collector, tag: workspace_negotiator } workspaces.operation_factory: class: Drupal\workspaces\WorkspaceOperationFactory - arguments: ['@entity_type.manager', '@database', '@workspaces.manager', '@workspaces.association', '@cache_tags.invalidator', '@event_dispatcher'] + arguments: ['@entity_type.manager', '@database', '@workspaces.manager', '@workspaces.association', '@cache_tags.invalidator', '@event_dispatcher', '@logger.channel.workspaces'] workspaces.association: class: Drupal\workspaces\WorkspaceAssociation - arguments: ['@database', '@entity_type.manager', '@workspaces.repository'] + arguments: ['@database', '@entity_type.manager', '@workspaces.repository', '@logger.channel.workspaces'] tags: - { name: backend_overridable } - { name: event_subscriber } diff --git a/core/tests/Drupal/KernelTests/Core/Bootstrap/LegacyBootstrapTest.php b/core/tests/Drupal/KernelTests/Core/Bootstrap/LegacyBootstrapTest.php new file mode 100644 index 000000000000..a9f506bad28f --- /dev/null +++ b/core/tests/Drupal/KernelTests/Core/Bootstrap/LegacyBootstrapTest.php @@ -0,0 +1,37 @@ +<?php + +namespace Drupal\KernelTests\Core\Bootstrap; + +use ColinODell\PsrTestLogger\TestLogger; +use Drupal\Core\Logger\RfcLogLevel; +use Drupal\Core\Utility\Error; +use Drupal\KernelTests\KernelTestBase; + +/** + * Tests legacy bootstrap functions. + * + * @group Bootstrap + * @group legacy + */ +class LegacyBootstrapTest extends KernelTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = ['system']; + + /** + * Tests watchdog_exception() deprecation. + */ + public function testWatchdogException(): void { + $logger = new TestLogger(); + /** @var \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerFactory */ + $loggerFactory = \Drupal::service('logger.factory'); + $loggerFactory->addLogger($logger); + $this->expectDeprecation('watchdog_exception() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use \Drupal\Core\Utility\Error::logException() instead. See https://www.drupal.org/node/2932520'); + $e = new \RuntimeException("foo"); + watchdog_exception('test', $e); + $this->assertTrue($logger->hasRecordThatContains(Error::DEFAULT_ERROR_MESSAGE, RfcLogLevel::ERROR)); + } + +} diff --git a/core/tests/Drupal/KernelTests/Core/Routing/LegacyMatcherDumperTest.php b/core/tests/Drupal/KernelTests/Core/Routing/LegacyMatcherDumperTest.php new file mode 100644 index 000000000000..e43bc5e436d4 --- /dev/null +++ b/core/tests/Drupal/KernelTests/Core/Routing/LegacyMatcherDumperTest.php @@ -0,0 +1,74 @@ +<?php + +namespace Drupal\KernelTests\Core\Routing; + +use Drupal\Core\Database\Connection; +use Drupal\Core\Routing\MatcherDumper; +use Drupal\Core\State\State; +use Drupal\KernelTests\KernelTestBase; +use Psr\Log\LoggerInterface; + +/** + * Tests deprecations in MatcherDumper. + * + * @group Routing + * @group legacy + * @coversDefaultClass \Drupal\Core\Routing\MatcherDumper + */ +class LegacyMatcherDumperTest extends KernelTestBase { + + /** + * The connection. + * + * @var \Drupal\Core\Database\Connection + */ + protected Connection $connection; + + /** + * The state. + * + * @var \Drupal\Core\State\State + */ + protected State $state; + + /** + * {@inheritdoc} + */ + protected function setUp():void { + parent::setUp(); + $this->connection = $this->createMock(Connection::class); + $this->state = $this->createMock(State::class); + } + + /** + * Tests the constructor deprecations. + */ + public function testConstructorDeprecationNoLogger() { + $this->expectDeprecation('Calling Drupal\Core\Routing\MatcherDumper::__construct() without the $logger argument is deprecated in drupal:10.1.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/2932520'); + $dumper = new MatcherDumper($this->connection, $this->state); + $this->assertNotNull($dumper); + } + + /** + * Tests the constructor deprecations. + */ + public function testConstructorDeprecationWithLegacyTableNameParam() { + $this->expectDeprecation('Calling Drupal\Core\Routing\MatcherDumper::__construct() without the $logger argument is deprecated in drupal:10.1.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/2932520'); + $dumper = new MatcherDumper($this->connection, $this->state, 'foo'); + $this->assertNotNull($dumper); + } + + /** + * Tests the constructor deprecations. + */ + public function testConstructorDeprecationWithLogger() { + $logger = $this->createMock(LoggerInterface::class); + $dumper = new MatcherDumper($this->connection, $this->state, $logger); + $this->assertNotNull($dumper); + + $logger = $this->createMock(LoggerInterface::class); + $dumper = new MatcherDumper($this->connection, $this->state, $logger, 'foo'); + $this->assertNotNull($dumper); + } + +} diff --git a/core/tests/Drupal/KernelTests/Core/Routing/MatcherDumperTest.php b/core/tests/Drupal/KernelTests/Core/Routing/MatcherDumperTest.php index 4efddf25c1a0..cb36c66f3b60 100644 --- a/core/tests/Drupal/KernelTests/Core/Routing/MatcherDumperTest.php +++ b/core/tests/Drupal/KernelTests/Core/Routing/MatcherDumperTest.php @@ -2,15 +2,16 @@ namespace Drupal\KernelTests\Core\Routing; +use ColinODell\PsrTestLogger\TestLogger; +use Drupal\Core\Database\Database; use Drupal\Core\KeyValueStore\KeyValueMemoryFactory; +use Drupal\Core\Routing\MatcherDumper; use Drupal\Core\Routing\RouteCompiler; use Drupal\Core\State\State; use Drupal\KernelTests\KernelTestBase; +use Drupal\Tests\Core\Routing\RoutingFixtures; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; -use Drupal\Core\Database\Database; -use Drupal\Core\Routing\MatcherDumper; -use Drupal\Tests\Core\Routing\RoutingFixtures; /** * Confirm that the matcher dumper is functioning properly. @@ -33,6 +34,11 @@ class MatcherDumperTest extends KernelTestBase { */ protected $state; + /** + * The logger. + */ + protected TestLogger $logger; + /** * {@inheritdoc} */ @@ -41,6 +47,7 @@ protected function setUp(): void { $this->fixtures = new RoutingFixtures(); $this->state = new State(new KeyValueMemoryFactory()); + $this->logger = new TestLogger(); } /** @@ -48,7 +55,7 @@ protected function setUp(): void { */ public function testCreate() { $connection = Database::getConnection(); - $dumper = new MatcherDumper($connection, $this->state); + $dumper = new MatcherDumper($connection, $this->state, $this->logger); $class_name = 'Drupal\Core\Routing\MatcherDumper'; $this->assertInstanceOf($class_name, $dumper); @@ -59,7 +66,7 @@ public function testCreate() { */ public function testAddRoutes() { $connection = Database::getConnection(); - $dumper = new MatcherDumper($connection, $this->state); + $dumper = new MatcherDumper($connection, $this->state, $this->logger); $route = new Route('test'); $collection = new RouteCollection(); @@ -80,7 +87,7 @@ public function testAddRoutes() { */ public function testAddAdditionalRoutes() { $connection = Database::getConnection(); - $dumper = new MatcherDumper($connection, $this->state); + $dumper = new MatcherDumper($connection, $this->state, $this->logger); $route = new Route('test'); $collection = new RouteCollection(); @@ -108,7 +115,7 @@ public function testAddAdditionalRoutes() { */ public function testDump() { $connection = Database::getConnection(); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $route = new Route('/test/{my}/path'); $route->setOption('compiler_class', RouteCompiler::class); @@ -143,7 +150,7 @@ public function testDump() { */ public function testMenuMasksGeneration() { $connection = Database::getConnection(); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $collection = new RouteCollection(); $collection->add('test_route_1', new Route('/test-length-3/{my}/path')); diff --git a/core/tests/Drupal/KernelTests/Core/Routing/RouteProviderTest.php b/core/tests/Drupal/KernelTests/Core/Routing/RouteProviderTest.php index dc3b90c07d62..cb30230de412 100644 --- a/core/tests/Drupal/KernelTests/Core/Routing/RouteProviderTest.php +++ b/core/tests/Drupal/KernelTests/Core/Routing/RouteProviderTest.php @@ -7,6 +7,7 @@ namespace Drupal\KernelTests\Core\Routing; +use ColinODell\PsrTestLogger\TestLogger; use Drupal\Core\Cache\MemoryBackend; use Drupal\Core\Database\Database; use Drupal\Core\DependencyInjection\ContainerBuilder; @@ -87,6 +88,13 @@ class RouteProviderTest extends KernelTestBase { */ protected $cacheTagsInvalidator; + /** + * The test logger. + * + * @var \ColinODell\PsrTestLogger\TestLogger + */ + protected TestLogger $logger; + /** * {@inheritdoc} */ @@ -99,6 +107,8 @@ protected function setUp(): void { $this->pathProcessor = \Drupal::service('path_processor_manager'); $this->cacheTagsInvalidator = \Drupal::service('cache_tags.invalidator'); $this->installEntitySchema('path_alias'); + + $this->logger = new TestLogger(); } /** @@ -165,7 +175,7 @@ public function testExactPathMatch() { $this->fixtures->createTables($connection); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($this->fixtures->sampleRouteCollection()); $dumper->dump(); @@ -189,7 +199,7 @@ public function testOutlinePathMatch() { $this->fixtures->createTables($connection); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($this->fixtures->complexRouteCollection()); $dumper->dump(); @@ -242,7 +252,7 @@ public function testMixedCasePaths($path, $expected_route_name, $method = 'GET') $this->fixtures->createTables($connection); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($this->fixtures->mixedCaseRouteCollection()); $dumper->dump(); @@ -286,7 +296,7 @@ public function testDuplicateRoutePaths($path, $number, $expected_route_name = N $this->fixtures->createTables($connection); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($this->fixtures->duplicatePathsRouteCollection()); $dumper->dump(); @@ -308,7 +318,7 @@ public function testGetAllRoutes() { $this->fixtures->createTables($connection); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($this->fixtures->SampleRouteCollection()); $dumper->dump(); @@ -334,7 +344,7 @@ public function testOutlinePathMatchTrailingSlash() { $this->fixtures->createTables($connection); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($this->fixtures->complexRouteCollection()); $dumper->dump(); @@ -368,7 +378,7 @@ public function testOutlinePathMatchDefaults() { 'value' => 'poink', ])); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($collection); $dumper->dump(); @@ -407,7 +417,7 @@ public function testOutlinePathMatchDefaultsCollision() { ])); $collection->add('narf', new Route('/some/path/here')); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($collection); $dumper->dump(); @@ -447,7 +457,7 @@ public function testOutlinePathMatchDefaultsCollision2() { $collection->add('narf', new Route('/some/path/here')); $collection->add('eep', new Route('/something/completely/different')); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($collection); $dumper->dump(); @@ -486,7 +496,7 @@ public function testOutlinePathMatchDefaultsCollision3() { $collection->add('narf', new Route('/some/here/path')); $collection->add('eep', new Route('/something/completely/different')); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($collection); $dumper->dump(); @@ -521,7 +531,7 @@ public function testOutlinePathMatchZero() { $collection = new RouteCollection(); $collection->add('poink', new Route('/some/path/{value}')); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($collection); $dumper->dump(); @@ -553,7 +563,7 @@ public function testOutlinePathNoMatch() { $this->fixtures->createTables($connection); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($this->fixtures->complexRouteCollection()); $dumper->dump(); @@ -578,7 +588,7 @@ public function testRouteCaching() { $this->fixtures->createTables($connection); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($this->fixtures->sampleRouteCollection()); $dumper->addRoutes($this->fixtures->complexRouteCollection()); $dumper->dump(); @@ -653,7 +663,7 @@ public function testRouteByName() { $this->fixtures->createTables($connection); - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $dumper->addRoutes($this->fixtures->sampleRouteCollection()); $dumper->dump(); @@ -702,7 +712,7 @@ public function testGetRoutesByPatternWithLongPatterns() { $this->assertCount(0, $candidates); // Add a matching route and dump it. - $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); + $dumper = new MatcherDumper($connection, $this->state, $this->logger, 'test_routes'); $collection = new RouteCollection(); $collection->add('long_pattern', new Route('/test/{v1}/test2/{v2}/test3/{v3}/{v4}/{v5}/{v6}/test4')); $dumper->addRoutes($collection); diff --git a/core/tests/Drupal/Tests/Core/Cron/CronSuspendQueueDelayTest.php b/core/tests/Drupal/Tests/Core/Cron/CronSuspendQueueDelayTest.php index f74ef7676eff..6ac8367a995d 100644 --- a/core/tests/Drupal/Tests/Core/Cron/CronSuspendQueueDelayTest.php +++ b/core/tests/Drupal/Tests/Core/Cron/CronSuspendQueueDelayTest.php @@ -70,7 +70,7 @@ protected function setUp(): void { 'queue_config' => [], ]; - // Capture logs to watchdog_exception(). + // Capture error logs. $config = $this->createMock(ImmutableConfig::class); $config->expects($this->any()) ->method('get') -- GitLab