Database logging stopped after 10.3 upgrade

Created on 17 October 2024, 2 months ago

After upgrading from 10.2.6 to 10.3.6, database logging no longer works. I tried uninstalling and reinstalling the core "Database Logging" module and resaving the "Logging and errors" configuration. Reverting back to 10.2.10 restores the logging.

🐛 Bug report
Status

Active

Version

10.3

Component

database system

Created by

🇺🇸United States kkaya

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @kkaya
  • This isn't something we've experienced. There must be additional steps to reproduce outside of upgrading Core.

  • Below are the commits and the differences between those versions. Researching a bug will mean:

    • Reproducing it. What is the setup of Drupal Core that exhibits the bug?
    • What is the specific version of Drupal Core that introduced the bug?
    • Identifying the commit that broke the module. A git bisect operation on a Drupal Core Git working copy that is set up to exhibit the bug will quickly find the regression commit.
    $ git log --oneline 10.2.10...10.3.6 core/modules/dblog
    8c274c9f87 Issue #3467294 by quietone, nod_, smustgrave, catch, longwave: Change string 'Modules to enable' to {@inheritdoc} in comments
    21396c951e Issue #3469716 by catch, smustgrave: Optimize dblog tests
    f4930ff629 Issue #3421418 by mstrelan, Spokje, xjm, mondrake, longwave, acbramley: Add void return typehints to all test methods
    24e197de0b Issue #3427999 by andypost, Ayesh, bbrala: [PHP 8.4] Fix implicitly nullable type declarations
    2c3cb5e89f Issue #3427564 by phenaproxima, Wim Leers, alexpott, omkar.podey, Berdir, smustgrave, larowlan: Require `langcode: …` only for simple config that contains translatable values
    442b47177d Issue #3399388 by mstrelan: Add declare(strict_types=1) to all Kernel tests
    5786e6e83b Issue #3421000 by sorlov, quietone, smustgrave, larowlan, alexpott: Convert ViewsWizard plugin discovery to attributes
    a15b012100 Issue #3436671 by narendraR, Wim Leers, phenaproxima: Add validation constraints to system.cron
    2ed3680d12 Issue #3426957 by sorlov, smustgrave, mstrelan: Convert ViewsFilter plugin discovery to attributes
    fc15d5ee53 Issue #3426955 by mstrelan, sorlov, alexpott, smustgrave, godotislate: Convert ViewsField plugin discovery to attributes
    67c22284ec Issue #3420994 by kim.pepper: Convert RestResource plugin discovery to attributes
    a23b6d6768 Issue #3399746 by mstrelan, acbramley: Add declare(strict_types=1) to all Functional tests
    e5e61dc566 Issue #3309104 by Bhanu951, acbramley, mondrake, ravi.shankar, smustgrave, daffie, alexpott, quietone, mstrelan: Replace REQUEST_TIME in Functional and FunctionalJavascript tests
    47e76cea08 Issue #3395631 by phenaproxima, hdnag, borisson_, marvil07, Spokje, Wim Leers, catch, dagmar: Add validation constraints to dblog.settings
    bf4e65cf04 Revert "Issue #3395631 by hdnag, borisson_, marvil07, dagmar, Wim Leers: Add validation constraints to dblog.settings"
    421ade1c80 Issue #3395631 by hdnag, borisson_, marvil07, dagmar, Wim Leers: Add validation constraints to dblog.settings
    a335588be2 Issue #2481349 by mfb, dagmar, jofitz, smustgrave, vasi, neclimdul, ziomizar, quietone, _utsavsharma, littlepixiez, xjm, fgm, Todd Zebert, hass, dawehner, heddn, webchick, catch: Prevent the use of placeholders that cannot be converted into strings when creating logs
    367e57e7bc Issue #2481349 by mfb, dagmar, jofitz, smustgrave, vasi, neclimdul, ziomizar, quietone, _utsavsharma, littlepixiez, xjm, fgm, Todd Zebert, hass, dawehner, heddn, webchick, catch: Prevent the use of placeholders that cannot be converted into strings when creating logs
    362a5f61d9 Issue #3412464 by mstrelan, smustgrave, quietone: Fix strict type errors: Convert FormattableMarkup to strings (complex replacement) in core Functional tests
    503192fcfe Issue #3412464 by mstrelan, smustgrave: Fix strict type errors: Convert FormattableMarkup to strings (complex replacement) in core Functional tests
    526d8ef95e Issue #3415811 by catch: Add @group #slow to more functional tests
    379968c4ac Issue #3414263 by quietone, andypost: Change help headings for WCAG 2.0
    1e8ae69e1d Issue #3414263 by quietone, andypost: Change help headings for WCAG 2.0
    828b4be30c Issue #3404273 by mstrelan, smustgrave: Fix strict type errors: Convert FormattableMarkup to strings (simple replacement) in core Functional tests
    061989d481 Issue #3404273 by mstrelan, smustgrave: Fix strict type errors: Convert FormattableMarkup to strings (simple replacement) in core Functional tests
    79b5436806 Issue #3333401 by nicxvan, tsquared212, xjm, larowlan, smustgrave, andrewmacpherson, bnjmnm, lauriii, itmaybejj, xurizaemon: Pager h4 causes accessibility flag on many pages
    d39fc2255a Issue #3402293 by dww, mstrelan, smustgrave: Fix strict type errors: Convert FormattableMarkup to strings (simple replacement) in core/modules/*/tests/src/Kernel/*
    df70716e5a Issue #3402293 by dww, mstrelan, smustgrave: Fix strict type errors: Convert FormattableMarkup to strings (simple replacement) in core/modules/*/tests/src/Kernel/*
    538c90fb10 Issue #3370560 by quietone, bogdog400, daffie: Update failed: dblog_update_10101  (TINYINT)
    cd9dd26637 Issue #3370560 by quietone, bogdog400, daffie: Update failed: dblog_update_10101  (TINYINT)
    83752e6bc0 Issue #3396310 by longwave, Spokje, smustgrave: Use autowiring for core controllers
    d15c431465 Issue #3391786 by quietone, xjm, smustgrave: Fix spelling of words only misspelled in tests, variable names, part 5
    6dc9ce0b01 Issue #3391786 by quietone, xjm, smustgrave: Fix spelling of words only misspelled in tests, variable names, part 5
    72d9d9ba16 Issue #3175449 by mfb, super_romeo, smustgrave, _pratik_, Medha Kumari, Nitin shrivastava, quietone, alexpott, xjm, dagmar, longwave: Display backtrace for logged throwables on log message details page
    d5e0610510 Issue #3175449 by mfb, super_romeo, smustgrave, _pratik_, Medha Kumari, Nitin shrivastava, quietone, alexpott, xjm, dagmar, longwave: Display backtrace for logged throwables on log message details page
    14bf457fbf Issue #3398891 by alexpott, Wim Leers: Do not require the config in #config_target to be listed in getEditableConfigNames()
    c1a42fda67 Issue #3398891 by alexpott, Wim Leers: Do not require the config in #config_target to be listed in getEditableConfigNames()
    
    $ git diff 10.2.10...10.3.6 core/modules/dblog
    diff --git a/core/modules/dblog/config/optional/views.view.watchdog.yml b/core/modules/dblog/config/optional/views.view.watchdog.yml
    index a21b0ea386..f6bf0905aa 100644
    --- a/core/modules/dblog/config/optional/views.view.watchdog.yml
    +++ b/core/modules/dblog/config/optional/views.view.watchdog.yml
    @@ -437,6 +437,7 @@ display:
             type: mini
             options:
               offset: 0
    +          pagination_heading_level: h4
               items_per_page: 50
               total_pages: null
               id: 0
    diff --git a/core/modules/dblog/config/schema/dblog.schema.yml b/core/modules/dblog/config/schema/dblog.schema.yml
    index d7196da6da..cd59a5dd89 100644
    --- a/core/modules/dblog/config/schema/dblog.schema.yml
    +++ b/core/modules/dblog/config/schema/dblog.schema.yml
    @@ -7,3 +7,8 @@ dblog.settings:
         row_limit:
           type: integer
           label: 'Database log messages to keep'
    +      constraints:
    +        Range:
    +          min: 0
    +  constraints:
    +    FullyValidatable: ~
    diff --git a/core/modules/dblog/dblog.install b/core/modules/dblog/dblog.install
    index 2a9f05dd39..0a581226b4 100644
    --- a/core/modules/dblog/dblog.install
    +++ b/core/modules/dblog/dblog.install
    @@ -5,8 +5,6 @@
      * Install, update and uninstall functions for the dblog module.
      */
     
    -use Drupal\Core\Database\Database;
    -
     /**
      * Implements hook_schema().
      */
    @@ -123,15 +121,15 @@ function dblog_update_10100(&$sandbox = NULL) {
      * Converts the 'wid' of the 'watchdog' table to a big integer.
      */
     function dblog_update_10101(&$sandbox = NULL) {
    -  $schema = Database::getConnection()->schema();
    -
    -  // Increase the size of the field.
    -  $new_specification = [
    -    'size' => 'big',
    -    'type' => 'serial',
    -    'not null' => TRUE,
    -    'description' => 'Primary Key: Unique watchdog event ID.',
    -  ];
    -  $schema->changeField('watchdog', 'wid', 'wid', $new_specification);
    -
    +  $connection = \Drupal::database();
    +  if ($connection->databaseType() != 'sqlite') {
    +    // Increase the size of the field.
    +    $new_specification = [
    +      'size' => 'big',
    +      'type' => 'serial',
    +      'not null' => TRUE,
    +      'description' => 'Primary Key: Unique watchdog event ID.',
    +    ];
    +    $connection->schema()->changeField('watchdog', 'wid', 'wid', $new_specification);
    +  }
     }
    diff --git a/core/modules/dblog/dblog.module b/core/modules/dblog/dblog.module
    index aa3f910f9f..ef11460c2c 100644
    --- a/core/modules/dblog/dblog.module
    +++ b/core/modules/dblog/dblog.module
    @@ -22,9 +22,9 @@ function dblog_help($route_name, RouteMatchInterface $route_match) {
       switch ($route_name) {
         case 'help.page.dblog':
           $output = '';
    -      $output .= '<h3>' . t('About') . '</h3>';
    +      $output .= '<h2>' . t('About') . '</h2>';
           $output .= '<p>' . t('The Database Logging module logs system events in the Drupal database. For more information, see the <a href=":dblog">online documentation for the Database Logging module</a>.', [':dblog' => 'https://www.drupal.org/documentation/modules/dblog']) . '</p>';
    -      $output .= '<h3>' . t('Uses') . '</h3>';
    +      $output .= '<h2>' . t('Uses') . '</h2>';
           $output .= '<dl>';
           $output .= '<dt>' . t('Monitoring your site') . '</dt>';
           $output .= '<dd>' . t('The Database Logging module allows you to view an event log on the <a href=":dblog">Recent log messages</a> page. The log is a chronological list of recorded events containing usage data, performance data, errors, warnings and operational information. Administrators should check the log on a regular basis to ensure their site is working properly.', [':dblog' => Url::fromRoute('dblog.overview')->toString()]) . '</dd>';
    @@ -104,21 +104,10 @@ function dblog_form_system_logging_settings_alter(&$form, FormStateInterface $fo
       $form['dblog_row_limit'] = [
         '#type' => 'select',
         '#title' => t('Database log messages to keep'),
    -    '#default_value' => \Drupal::configFactory()->getEditable('dblog.settings')->get('row_limit'),
    +    '#config_target' => 'dblog.settings:row_limit',
         '#options' => [0 => t('All')] + array_combine($row_limits, $row_limits),
         '#description' => t('The maximum number of messages to keep in the database log. Requires a <a href=":cron">cron maintenance task</a>.', [':cron' => Url::fromRoute('system.status')->toString()]),
       ];
    -
    -  $form['#submit'][] = 'dblog_logging_settings_submit';
    -}
    -
    -/**
    - * Form submission handler for system_logging_settings().
    - *
    - * @see dblog_form_system_logging_settings_alter()
    - */
    -function dblog_logging_settings_submit($form, FormStateInterface $form_state) {
    -  \Drupal::configFactory()->getEditable('dblog.settings')->set('row_limit', $form_state->getValue('dblog_row_limit'))->save();
     }
     
     /**
    diff --git a/core/modules/dblog/src/Controller/DbLogController.php b/core/modules/dblog/src/Controller/DbLogController.php
    index b52ed5015a..134bc22580 100644
    --- a/core/modules/dblog/src/Controller/DbLogController.php
    +++ b/core/modules/dblog/src/Controller/DbLogController.php
    @@ -17,7 +17,6 @@
     use Drupal\Core\Logger\RfcLogLevel;
     use Drupal\Core\Url;
     use Drupal\user\Entity\User;
    -use Symfony\Component\DependencyInjection\ContainerInterface;
     use Symfony\Component\HttpFoundation\Request;
     use Drupal\Core\Link;
     use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
    @@ -48,18 +47,6 @@ class DbLogController extends ControllerBase {
        */
       protected $userStorage;
     
    -  /**
    -   * {@inheritdoc}
    -   */
    -  public static function create(ContainerInterface $container) {
    -    return new static(
    -      $container->get('database'),
    -      $container->get('module_handler'),
    -      $container->get('date.formatter'),
    -      $container->get('form_builder')
    -    );
    -  }
    -
       /**
        * Constructs a DbLogController object.
        *
    @@ -291,6 +278,12 @@ public function eventDetails($event_id) {
             ['data' => ['#markup' => $dblog->link]],
           ],
         ];
    +    if (isset($dblog->backtrace)) {
    +      $rows[] = [
    +        ['data' => $this->t('Backtrace'), 'header' => TRUE],
    +        $dblog->backtrace,
    +      ];
    +    }
         $build['dblog_table'] = [
           '#type' => 'table',
           '#rows' => $rows,
    @@ -350,6 +343,10 @@ protected function buildFilterQuery(Request $request) {
        *   The record from the watchdog table. The object properties are: wid, uid,
        *   severity, type, timestamp, message, variables, link, name.
        *
    +   *   If the variables contain a @backtrace_string placeholder which is not
    +   *   used in the message, the formatted backtrace will be assigned to a new
    +   *   backtrace property on the row object which can be displayed separately.
    +   *
        * @return string|\Drupal\Core\StringTranslation\TranslatableMarkup|false
        *   The formatted log message or FALSE if the message or variables properties
        *   are not set.
    @@ -372,6 +369,10 @@ public function formatMessage($row) {
               $variables['@backtrace_string'] = new FormattableMarkup(
                 '<pre class="backtrace">@backtrace_string</pre>', $variables
               );
    +          // Save a reference so the backtrace can be displayed separately.
    +          if (!str_contains($row->message, '@backtrace_string')) {
    +            $row->backtrace = $variables['@backtrace_string'];
    +          }
             }
             $message = $this->t(Xss::filterAdmin($row->message), $variables);
           }
    diff --git a/core/modules/dblog/src/Plugin/rest/resource/DbLogResource.php b/core/modules/dblog/src/Plugin/rest/resource/DbLogResource.php
    index b1a617b3e1..c3174469e5 100644
    --- a/core/modules/dblog/src/Plugin/rest/resource/DbLogResource.php
    +++ b/core/modules/dblog/src/Plugin/rest/resource/DbLogResource.php
    @@ -3,6 +3,8 @@
     namespace Drupal\dblog\Plugin\rest\resource;
     
     use Drupal\Core\Database\Database;
    +use Drupal\Core\StringTranslation\TranslatableMarkup;
    +use Drupal\rest\Attribute\RestResource;
     use Drupal\rest\Plugin\ResourceBase;
     use Drupal\rest\ResourceResponse;
     use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
    @@ -10,15 +12,14 @@
     
     /**
      * Provides a resource for database watchdog log entries.
    - *
    - * @RestResource(
    - *   id = "dblog",
    - *   label = @Translation("Watchdog database log"),
    - *   uri_paths = {
    - *     "canonical" = "/dblog/{id}"
    - *   }
    - * )
      */
    +#[RestResource(
    +  id: "dblog",
    +  label: new TranslatableMarkup("Watchdog database log"),
    +  uri_paths: [
    +    "canonical" => "/dblog/{id}",
    +  ]
    +)]
     class DbLogResource extends ResourceBase {
     
       /**
    diff --git a/core/modules/dblog/src/Plugin/views/field/DblogMessage.php b/core/modules/dblog/src/Plugin/views/field/DblogMessage.php
    index fd18779f04..2725098332 100644
    --- a/core/modules/dblog/src/Plugin/views/field/DblogMessage.php
    +++ b/core/modules/dblog/src/Plugin/views/field/DblogMessage.php
    @@ -4,6 +4,7 @@
     
     use Drupal\Component\Render\FormattableMarkup;
     use Drupal\Core\Form\FormStateInterface;
    +use Drupal\views\Attribute\ViewsField;
     use Drupal\views\Plugin\views\field\FieldPluginBase;
     use Drupal\views\ResultRow;
     use Drupal\views\ViewExecutable;
    @@ -13,15 +14,14 @@
      * Provides a field handler that renders a log event with replaced variables.
      *
      * @ingroup views_field_handlers
    - *
    - * @ViewsField("dblog_message")
      */
    +#[ViewsField("dblog_message")]
     class DblogMessage extends FieldPluginBase {
     
       /**
        * {@inheritdoc}
        */
    -  public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
    +  public function init(ViewExecutable $view, DisplayPluginBase $display, ?array &$options = NULL) {
         parent::init($view, $display, $options);
     
         if ($this->options['replace_variables']) {
    diff --git a/core/modules/dblog/src/Plugin/views/field/DblogOperations.php b/core/modules/dblog/src/Plugin/views/field/DblogOperations.php
    index 49a47fda81..15fc083374 100644
    --- a/core/modules/dblog/src/Plugin/views/field/DblogOperations.php
    +++ b/core/modules/dblog/src/Plugin/views/field/DblogOperations.php
    @@ -2,6 +2,7 @@
     
     namespace Drupal\dblog\Plugin\views\field;
     
    +use Drupal\views\Attribute\ViewsField;
     use Drupal\views\Plugin\views\field\FieldPluginBase;
     use Drupal\views\ResultRow;
     
    @@ -9,9 +10,8 @@
      * Provides a field handler that renders operation link markup.
      *
      * @ingroup views_field_handlers
    - *
    - * @ViewsField("dblog_operations")
      */
    +#[ViewsField("dblog_operations")]
     class DblogOperations extends FieldPluginBase {
     
       /**
    diff --git a/core/modules/dblog/src/Plugin/views/filter/DblogTypes.php b/core/modules/dblog/src/Plugin/views/filter/DblogTypes.php
    index ed8f547166..b95f5f1038 100644
    --- a/core/modules/dblog/src/Plugin/views/filter/DblogTypes.php
    +++ b/core/modules/dblog/src/Plugin/views/filter/DblogTypes.php
    @@ -3,13 +3,13 @@
     namespace Drupal\dblog\Plugin\views\filter;
     
     use Drupal\Core\Form\FormStateInterface;
    +use Drupal\views\Attribute\ViewsFilter;
     use Drupal\views\Plugin\views\filter\InOperator;
     
     /**
      * Exposes log types to views module.
    - *
    - * @ViewsFilter("dblog_types")
      */
    +#[ViewsFilter("dblog_types")]
     class DblogTypes extends InOperator {
     
       /**
    diff --git a/core/modules/dblog/src/Plugin/views/wizard/Watchdog.php b/core/modules/dblog/src/Plugin/views/wizard/Watchdog.php
    index 3a0dad5c86..ac78fe828b 100644
    --- a/core/modules/dblog/src/Plugin/views/wizard/Watchdog.php
    +++ b/core/modules/dblog/src/Plugin/views/wizard/Watchdog.php
    @@ -2,18 +2,18 @@
     
     namespace Drupal\dblog\Plugin\views\wizard;
     
    +use Drupal\Core\StringTranslation\TranslatableMarkup;
    +use Drupal\views\Attribute\ViewsWizard;
     use Drupal\views\Plugin\views\wizard\WizardPluginBase;
     
     /**
      * Defines a wizard for the watchdog table.
    - *
    - * @ViewsWizard(
    - *   id = "watchdog",
    - *   module = "dblog",
    - *   base_table = "watchdog",
    - *   title = @Translation("Log entries")
    - * )
      */
    +#[ViewsWizard(
    +  id: 'watchdog',
    +  title: new TranslatableMarkup('Log entries'),
    +  base_table: 'watchdog'
    +)]
     class Watchdog extends WizardPluginBase {
     
       /**
    diff --git a/core/modules/dblog/tests/src/Functional/DbLogResourceTest.php b/core/modules/dblog/tests/src/Functional/DbLogResourceTest.php
    index f7845bf605..efd97a84aa 100644
    --- a/core/modules/dblog/tests/src/Functional/DbLogResourceTest.php
    +++ b/core/modules/dblog/tests/src/Functional/DbLogResourceTest.php
    @@ -1,5 +1,7 @@
     <?php
     
    +declare(strict_types=1);
    +
     namespace Drupal\Tests\dblog\Functional;
     
     use Drupal\Component\Serialization\Json;
    diff --git a/core/modules/dblog/tests/src/Functional/DbLogTest.php b/core/modules/dblog/tests/src/Functional/DbLogTest.php
    index b4ef303d04..b68ce85ad6 100644
    --- a/core/modules/dblog/tests/src/Functional/DbLogTest.php
    +++ b/core/modules/dblog/tests/src/Functional/DbLogTest.php
    @@ -1,5 +1,7 @@
     <?php
     
    +declare(strict_types=1);
    +
     namespace Drupal\Tests\dblog\Functional;
     
     use Drupal\Component\Render\FormattableMarkup;
    @@ -23,9 +25,7 @@ class DbLogTest extends BrowserTestBase {
       use AssertBreadcrumbTrait;
     
       /**
    -   * Modules to enable.
    -   *
    -   * @var array
    +   * {@inheritdoc}
        */
       protected static $modules = [
         'dblog',
    @@ -80,7 +80,7 @@ protected function setUp(): void {
        * Database Logging module functionality through both the admin and user
        * interfaces.
        */
    -  public function testDbLog() {
    +  public function testDbLog(): void {
         // Log in the admin user.
         $this->drupalLogin($this->adminUser);
     
    @@ -102,12 +102,18 @@ public function testDbLog() {
         // Log in the regular user.
         $this->drupalLogin($this->webUser);
         $this->verifyReports(403);
    +
    +    $this->testLogEventNotFoundPage();
    +    $this->testLogEventPageWithMissingInfo();
    +    $this->test403LogEventPage();
    +    $this->testMessageParsing();
    +    $this->testOverviewLinks();
       }
     
       /**
        * Tests individual log event page.
        */
    -  public function testLogEventPage() {
    +  public function testLogEventPage(): void {
         // Login the admin user.
         $this->drupalLogin($this->adminUser);
     
    @@ -120,7 +126,7 @@ public function testLogEventPage() {
           'channel' => 'testing',
           'link' => 'foo/bar',
           'ip' => '0.0.1.0',
    -      'timestamp' => REQUEST_TIME,
    +      'timestamp' => \Drupal::time()->getRequestTime(),
         ];
         \Drupal::service('logger.dblog')->log(RfcLogLevel::NOTICE, 'Test message', $context);
         $query = Database::getConnection()->select('watchdog');
    @@ -142,10 +148,40 @@ public function testLogEventPage() {
         $this->assertSession()->pageTextContains('Notice');
       }
     
    +  /**
    +   * Tests that the details page displays the backtrace for a logged \Throwable.
    +   */
    +  public function testOnError(): void {
    +    // Log in as the admin user.
    +    $this->drupalLogin($this->adminUser);
    +
    +    // Load a page that throws an exception in the controller, and includes its
    +    // function arguments in the exception backtrace.
    +    $this->drupalGet('error-test/trigger-exception');
    +
    +    // Load the details page for the most recent event logged by the "php"
    +    // logger.
    +    $query = Database::getConnection()->select('watchdog')
    +      ->condition('type', 'php');
    +    $query->addExpression('MAX([wid])');
    +    $wid = $query->execute()->fetchField();
    +    $this->drupalGet('admin/reports/dblog/event/' . $wid);
    +
    +    // Verify the page displays a dblog-event table with a "Type" header.
    +    $table = $this->assertSession()->elementExists('xpath', "//table[@class='dblog-event']");
    +    $type = "//tr/th[contains(text(), 'Type')]/../td";
    +    $this->assertSession()->elementsCount('xpath', $type, 1, $table);
    +
    +    // Verify that the backtrace row exists and is HTML-encoded.
    +    $backtrace = "//tr//pre[contains(@class, 'backtrace')]";
    +    $this->assertCount(1, $table->findAll('xpath', $backtrace));
    +    $this->assertSession()->responseContains('&lt;script&gt;alert(&#039;xss&#039;)&lt;/script&gt;');
    +  }
    +
       /**
        * Tests that a 403 event is logged with the exception triggering it.
        */
    -  public function test403LogEventPage() {
    +  protected function test403LogEventPage(): void {
         $assert_session = $this->assertSession();
         $uri = 'admin/reports';
     
    @@ -185,7 +221,7 @@ public function test403LogEventPage() {
       /**
        * Tests not-existing log event page.
        */
    -  public function testLogEventNotFoundPage() {
    +  protected function testLogEventNotFoundPage(): void {
         // Login the admin user.
         $this->drupalLogin($this->adminUser);
     
    @@ -204,7 +240,7 @@ public function testLogEventNotFoundPage() {
        * - Incorrect location: When location attribute is incorrect uri which can
        *   not be used to generate a valid link.
        */
    -  public function testLogEventPageWithMissingInfo() {
    +  protected function testLogEventPageWithMissingInfo(): void {
         $this->drupalLogin($this->adminUser);
         $connection = Database::getConnection();
     
    @@ -247,7 +283,7 @@ public function testLogEventPageWithMissingInfo() {
       /**
        * Test that twig errors are displayed correctly.
        */
    -  public function testMessageParsing() {
    +  protected function testMessageParsing(): void {
         $this->drupalLogin($this->adminUser);
         // Log a common twig error with {{ }} and { } variables.
         \Drupal::service('logger.factory')->get("php")
    @@ -273,11 +309,12 @@ private function verifyRowLimit($row_limit) {
         $edit['dblog_row_limit'] = $row_limit;
         $this->drupalGet('admin/config/development/logging');
         $this->submitForm($edit, 'Save configuration');
    +    $this->assertSession()->statusMessageContains('The configuration options have been saved.');
         $this->assertSession()->statusCodeEquals(200);
     
         // Check row limit variable.
         $current_limit = $this->config('dblog.settings')->get('row_limit');
    -    $this->assertEquals($current_limit, $row_limit, new FormattableMarkup('[Cache] Row limit variable of @count equals row limit of @limit', ['@count' => $current_limit, '@limit' => $row_limit]));
    +    $this->assertEquals($current_limit, $row_limit, "[Cache] Row limit variable of $current_limit equals row limit of $row_limit");
       }
     
       /**
    @@ -399,7 +436,7 @@ private function verifyEvents() {
        * @param string $order
        *   The order by which the table should be sorted.
        */
    -  public function verifySort($sort = 'asc', $order = 'Date') {
    +  protected function verifySort($sort = 'asc', $order = 'Date') {
         $this->drupalGet('admin/reports/dblog', ['query' => ['sort' => $sort, 'order' => $order]]);
         $this->assertSession()->statusCodeEquals(200);
         $this->assertSession()->pageTextContains('Recent log messages');
    @@ -443,7 +480,7 @@ private function doUser() {
         $this->assertSession()->statusCodeEquals(200);
         // Retrieve the user object.
         $user = user_load_by_name($name);
    -    $this->assertNotNull($user, new FormattableMarkup('User @name was loaded', ['@name' => $name]));
    +    $this->assertNotNull($user, "User $name was loaded");
         // pass_raw property is needed by drupalLogin.
         $user->passRaw = $pass;
         // Log in user.
    @@ -456,7 +493,7 @@ private function doUser() {
           $ids[] = $row->wid;
         }
         $count_before = (isset($ids)) ? count($ids) : 0;
    -    $this->assertGreaterThan(0, $count_before, new FormattableMarkup('DBLog contains @count records for @name', ['@count' => $count_before, '@name' => $user->getAccountName()]));
    +    $this->assertGreaterThan(0, $count_before, "DBLog contains $count_before records for {$user->getAccountName()}");
     
         // Log in the admin user.
         $this->drupalLogin($this->adminUser);
    @@ -531,7 +568,7 @@ private function doNode($type) {
         $this->assertSession()->statusCodeEquals(200);
         // Retrieve the node object.
         $node = $this->drupalGetNodeByTitle($title);
    -    $this->assertNotNull($node, new FormattableMarkup('Node @title was loaded', ['@title' => $title]));
    +    $this->assertNotNull($node, "Node $title was loaded");
         // Edit the node.
         $edit = [
           'body[0][value]' => $this->randomMachineName(32),
    @@ -583,7 +620,7 @@ private function doNode($type) {
        * Logs in the admin user, creates a database log event, and tests the
        * functionality of clearing the database log through the admin interface.
        */
    -  public function testDBLogAddAndClear() {
    +  public function testDBLogAddAndClear(): void {
         global $base_root;
         $connection = Database::getConnection();
         // Get a count of how many watchdog entries already exist.
    @@ -598,12 +635,12 @@ public function testDBLogAddAndClear() {
           'request_uri' => $base_root . \Drupal::request()->getRequestUri(),
           'referer'     => \Drupal::request()->server->get('HTTP_REFERER'),
           'ip'          => '127.0.0.1',
    -      'timestamp'   => REQUEST_TIME,
    +      'timestamp'   => \Drupal::time()->getRequestTime(),
         ];
         // Add a watchdog entry.
         $this->container->get('logger.dblog')->log($log['severity'], $log['message'], $log);
         // Make sure the table count has actually been incremented.
    -    $this->assertEquals($count + 1, (int) $connection->select('watchdog')->countQuery()->execute()->fetchField(), new FormattableMarkup('\Drupal\dblog\Logger\DbLog->log() added an entry to the dblog :count', [':count' => $count]));
    +    $this->assertEquals($count + 1, (int) $connection->select('watchdog')->countQuery()->execute()->fetchField(), '\Drupal\dblog\Logger\DbLog->log() added an entry to the dblog ' . $count);
         // Log in the admin user.
         $this->drupalLogin($this->adminUser);
         // Post in order to clear the database table.
    @@ -612,13 +649,13 @@ public function testDBLogAddAndClear() {
         $this->submitForm([], 'Confirm');
         // Count the rows in watchdog that previously related to the deleted user.
         $count = $connection->select('watchdog')->countQuery()->execute()->fetchField();
    -    $this->assertEquals(0, $count, new FormattableMarkup('DBLog contains :count records after a clear.', [':count' => $count]));
    +    $this->assertEquals(0, $count, "DBLog contains $count records after a clear.");
       }
     
       /**
        * Tests the database log filter functionality at admin/reports/dblog.
        */
    -  public function testFilter() {
    +  public function testFilter(): void {
         $this->drupalLogin($this->adminUser);
     
         // Clear the log to ensure that only generated entries will be found.
    @@ -794,16 +831,16 @@ protected function assertLogMessage(string $log_message, string $message): void
       /**
        * Tests that the details page displays correctly for a temporary user.
        */
    -  public function testTemporaryUser() {
    +  public function testTemporaryUser(): void {
         // Create a temporary user.
    -    $tempuser = $this->drupalCreateUser();
    -    $tempuser_uid = $tempuser->id();
    +    $temporary_user = $this->drupalCreateUser();
    +    $temporary_user_uid = $temporary_user->id();
     
         // Log in as the admin user.
         $this->drupalLogin($this->adminUser);
     
         // Generate a single watchdog entry.
    -    $this->generateLogEntries(1, ['user' => $tempuser, 'uid' => $tempuser_uid]);
    +    $this->generateLogEntries(1, ['user' => $temporary_user, 'uid' => $temporary_user_uid]);
         $query = Database::getConnection()->select('watchdog');
         $query->addExpression('MAX([wid])');
         $wid = $query->execute()->fetchField();
    @@ -813,8 +850,8 @@ public function testTemporaryUser() {
         $this->assertSession()->pageTextContains('Dblog test log message');
     
         // Delete the user.
    -    $tempuser->delete();
    -    $this->drupalGet('user/' . $tempuser_uid);
    +    $temporary_user->delete();
    +    $this->drupalGet('user/' . $temporary_user_uid);
         $this->assertSession()->statusCodeEquals(404);
     
         // Check if the full message displays on the details page.
    @@ -825,7 +862,7 @@ public function testTemporaryUser() {
       /**
        * Make sure HTML tags are filtered out in the log overview links.
        */
    -  public function testOverviewLinks() {
    +  protected function testOverviewLinks(): void {
         $this->drupalLogin($this->adminUser);
         // cSpell:disable-next-line
         $this->generateLogEntries(1, ['message' => "&lt;script&gt;alert('foo');&lt;/script&gt;<strong>Lorem</strong> ipsum dolor sit amet, consectetur adipiscing & elit."]);
    @@ -848,7 +885,7 @@ public function testOverviewLinks() {
       /**
        * Tests sorting for entries with the same timestamp.
        */
    -  public function testSameTimestampEntries() {
    +  public function testSameTimestampEntries(): void {
         $this->drupalLogin($this->adminUser);
     
         $this->generateLogEntries(1, ['timestamp' => 1498062000, 'type' => 'same_time', 'message' => 'First']);
    @@ -866,7 +903,7 @@ public function testSameTimestampEntries() {
       /**
        * Tests that the details page displays correctly backtrace.
        */
    -  public function testBacktrace() {
    +  public function testBacktrace(): void {
         $this->drupalLogin($this->adminUser);
         $this->drupalGet('/error-test/generate-warnings');
     
    diff --git a/core/modules/dblog/tests/src/Functional/DbLogViewsTest.php b/core/modules/dblog/tests/src/Functional/DbLogViewsTest.php
    index d6794a01c4..284803fb29 100644
    --- a/core/modules/dblog/tests/src/Functional/DbLogViewsTest.php
    +++ b/core/modules/dblog/tests/src/Functional/DbLogViewsTest.php
    @@ -1,5 +1,7 @@
     <?php
     
    +declare(strict_types=1);
    +
     namespace Drupal\Tests\dblog\Functional;
     
     use Drupal\views\Views;
    @@ -14,9 +16,7 @@
     class DbLogViewsTest extends DbLogTest {
     
       /**
    -   * Modules to enable.
    -   *
    -   * @var array
    +   * {@inheritdoc}
        */
       protected static $modules = [
         'dblog',
    @@ -56,7 +56,7 @@ protected function filterLogsEntries($type = NULL, $severity = NULL) {
       /**
        * Tests the empty text for the watchdog view is not using an input format.
        */
    -  public function testEmptyText() {
    +  public function testEmptyText(): void {
         $view = Views::getView('watchdog');
         $data = $view->storage->toArray();
         $area = $data['display']['default']['display_options']['empty']['area'];
    diff --git a/core/modules/dblog/tests/src/Functional/FakeLogEntries.php b/core/modules/dblog/tests/src/Functional/FakeLogEntries.php
    index fa44d55939..66c8777d85 100644
    --- a/core/modules/dblog/tests/src/Functional/FakeLogEntries.php
    +++ b/core/modules/dblog/tests/src/Functional/FakeLogEntries.php
    @@ -1,5 +1,7 @@
     <?php
     
    +declare(strict_types=1);
    +
     namespace Drupal\Tests\dblog\Functional;
     
     use Drupal\Core\Logger\RfcLogLevel;
    @@ -50,7 +52,7 @@ private function generateLogEntries($count, $options = []) {
           'request_uri' => $base_root . \Drupal::request()->getRequestUri(),
           'referer'     => \Drupal::request()->server->get('HTTP_REFERER'),
           'ip'          => '127.0.0.1',
    -      'timestamp'   => REQUEST_TIME,
    +      'timestamp'   => \Drupal::time()->getRequestTime(),
         ];
     
         $logger = $this->container->get('logger.dblog');
    diff --git a/core/modules/dblog/tests/src/Functional/GenericTest.php b/core/modules/dblog/tests/src/Functional/GenericTest.php
    index 4a05f749ed..c6bfe5e608 100644
    --- a/core/modules/dblog/tests/src/Functional/GenericTest.php
    +++ b/core/modules/dblog/tests/src/Functional/GenericTest.php
    @@ -1,5 +1,7 @@
     <?php
     
    +declare(strict_types=1);
    +
     namespace Drupal\Tests\dblog\Functional;
     
     use Drupal\Tests\system\Functional\Module\GenericModuleTestBase;
    diff --git a/core/modules/dblog/tests/src/Functional/UpdatePathTest.php b/core/modules/dblog/tests/src/Functional/UpdatePathTest.php
    index 165a394864..6d76590b88 100644
    --- a/core/modules/dblog/tests/src/Functional/UpdatePathTest.php
    +++ b/core/modules/dblog/tests/src/Functional/UpdatePathTest.php
    @@ -1,5 +1,7 @@
     <?php
     
    +declare(strict_types=1);
    +
     namespace Drupal\Tests\dblog\Functional;
     
     use Drupal\Core\Database\Database;
    @@ -25,7 +27,7 @@ protected function setDatabaseDumpFiles() {
       /**
        * Tests that, after update 10101, the 'wid' column can be a 64-bit integer.
        */
    -  public function testLogEntryWithBigId() {
    +  public function testLogEntryWithBigId(): void {
         if (PHP_INT_SIZE < 8) {
           $this->markTestSkipped('This test can only be run on a system that supports 64-bit integers (i.e., PHP_INT_SIZE is 8).');
         }
    diff --git a/core/modules/dblog/tests/src/Kernel/ConnectionFailureTest.php b/core/modules/dblog/tests/src/Kernel/ConnectionFailureTest.php
    index 5364e134de..afb79e42b2 100644
    --- a/core/modules/dblog/tests/src/Kernel/ConnectionFailureTest.php
    +++ b/core/modules/dblog/tests/src/Kernel/ConnectionFailureTest.php
    @@ -1,5 +1,7 @@
     <?php
     
    +declare(strict_types=1);
    +
     namespace Drupal\Tests\dblog\Kernel;
     
     use Drupal\Core\Database\Database;
    @@ -20,7 +22,7 @@ class ConnectionFailureTest extends KernelTestBase {
       /**
        * Tests logging of connection failures.
        */
    -  public function testConnectionFailureLogging() {
    +  public function testConnectionFailureLogging(): void {
         $this->installSchema('dblog', ['watchdog']);
     
         // MySQL errors like "1153 - Got a packet bigger than 'max_allowed_packet'
    diff --git a/core/modules/dblog/tests/src/Kernel/DbLogControllerTest.php b/core/modules/dblog/tests/src/Kernel/DbLogControllerTest.php
    index 8c74084544..327751f651 100644
    --- a/core/modules/dblog/tests/src/Kernel/DbLogControllerTest.php
    +++ b/core/modules/dblog/tests/src/Kernel/DbLogControllerTest.php
    @@ -1,5 +1,7 @@
     <?php
     
    +declare(strict_types=1);
    +
     namespace Drupal\Tests\dblog\Kernel;
     
     use Drupal\dblog\Controller\DbLogController;
    @@ -29,7 +31,7 @@ protected function setUp(): void {
       /**
        * Tests links with non latin characters.
        */
    -  public function testNonLatinCharacters() {
    +  public function testNonLatinCharacters(): void {
     
         $link = 'hello-
           科州的小九寨沟绝美高山湖泊酱凉拌素鸡照烧鸡黄玫瑰
    @@ -62,7 +64,7 @@ public function testNonLatinCharacters() {
       /**
        * Tests corrupted log entries can still display available data.
        */
    -  public function testDbLogCorrupted() {
    +  public function testDbLogCorrupted(): void {
         $dblog_controller = DbLogController::create($this->container);
     
         // Check message with properly serialized data.
    diff --git a/core/modules/dblog/tests/src/Kernel/DbLogFormInjectionTest.php b/core/modules/dblog/tests/src/Kernel/DbLogFormInjectionTest.php
    index 778315048c..bb5251b730 100644
    --- a/core/modules/dblog/tests/src/Kernel/DbLogFormInjectionTest.php
    +++ b/core/modules/dblog/tests/src/Kernel/DbLogFormInjectionTest.php
    @@ -1,5 +1,7 @@
     <?php
     
    +declare(strict_types=1);
    +
     namespace Drupal\Tests\dblog\Kernel;
     
     use Drupal\Core\DependencyInjection\DependencySerializationTrait;
    @@ -26,9 +28,7 @@ class DbLogFormInjectionTest extends KernelTestBase implements FormInterface {
       protected $logger;
     
       /**
    -   * Modules to enable.
    -   *
    -   * @var array
    +   * {@inheritdoc}
        */
       protected static $modules = ['system', 'dblog', 'user'];
     
    @@ -91,7 +91,7 @@ protected function setUp(): void {
       /**
        * Tests db log injection serialization.
        */
    -  public function testLoggerSerialization() {
    +  public function testLoggerSerialization(): void {
         $form_state = new FormState();
     
         // Forms are only serialized during POST requests.
    diff --git a/core/modules/dblog/tests/src/Kernel/DbLogTest.php b/core/modules/dblog/tests/src/Kernel/DbLogTest.php
    index 08d4c37173..9bdc36cb98 100644
    --- a/core/modules/dblog/tests/src/Kernel/DbLogTest.php
    +++ b/core/modules/dblog/tests/src/Kernel/DbLogTest.php
    @@ -1,8 +1,9 @@
     <?php
     
    +declare(strict_types=1);
    +
     namespace Drupal\Tests\dblog\Kernel;
     
    -use Drupal\Component\Render\FormattableMarkup;
     use Drupal\Core\Database\Database;
     use Drupal\KernelTests\KernelTestBase;
     use Drupal\Tests\dblog\Functional\FakeLogEntries;
    @@ -34,13 +35,13 @@ protected function setUp(): void {
       /**
        * Tests that cron correctly applies the database log row limit.
        */
    -  public function testDbLogCron() {
    +  public function testDbLogCron(): void {
         $row_limit = 100;
         // Generate additional log entries.
         $this->generateLogEntries($row_limit + 10);
         // Verify that the database log row count exceeds the row limit.
         $count = Database::getConnection()->select('watchdog')->countQuery()->execute()->fetchField();
    -    $this->assertGreaterThan($row_limit, $count, new FormattableMarkup('Dblog row count of @count exceeds row limit of @limit', ['@count' => $count, '@limit' => $row_limit]));
    +    $this->assertGreaterThan($row_limit, $count, "Dblog row count of $count exceeds row limit of $row_limit");
     
         // Get the number of enabled modules. Cron adds a log entry for each module.
         $implementation_count = 0;
    @@ -52,12 +53,28 @@ function (callable $hook, string $module) use (&$implementation_count) {
         );
     
         $cron_detailed_count = $this->runCron();
    -    $this->assertEquals($implementation_count + 2, $cron_detailed_count, new FormattableMarkup('Cron added @count of @expected new log entries', ['@count' => $cron_detailed_count, '@expected' => $implementation_count + 2]));
    +    $expected_count = $implementation_count + 2;
    +    $this->assertEquals($expected_count, $cron_detailed_count, "Cron added $cron_detailed_count of $expected_count new log entries");
     
         // Test disabling of detailed cron logging.
    -    $this->config('system.cron')->set('logging', 0)->save();
    +    $this->config('system.cron')->set('logging', FALSE)->save();
         $cron_count = $this->runCron();
    -    $this->assertEquals(1, $cron_count, new FormattableMarkup('Cron added @count of @expected new log entries', ['@count' => $cron_count, '@expected' => 1]));
    +    $this->assertEquals(1, $cron_count, "Cron added $cron_count of 1 new log entries");
    +  }
    +
    +  /**
    +   * Tests that only valid placeholders are stored in the variables column.
    +   */
    +  public function testInvalidPlaceholders(): void {
    +    \Drupal::logger('my_module')->warning('Hello @string @array @object', ['@string' => '', '@array' => [], '@object' => new \stdClass()]);
    +    $variables = \Drupal::database()
    +      ->select('watchdog', 'w')
    +      ->fields('w', ['variables'])
    +      ->orderBy('wid', 'DESC')
    +      ->range(0, 1)
    +      ->execute()
    +      ->fetchField();
    +    $this->assertSame(serialize(['@string' => '']), $variables);
       }
     
       /**
    diff --git a/core/modules/dblog/tests/src/Kernel/Migrate/d6/MigrateDblogConfigsTest.php b/core/modules/dblog/tests/src/Kernel/Migrate/d6/MigrateDblogConfigsTest.php
    index 1856d5cc75..0e02c879c0 100644
    --- a/core/modules/dblog/tests/src/Kernel/Migrate/d6/MigrateDblogConfigsTest.php
    +++ b/core/modules/dblog/tests/src/Kernel/Migrate/d6/MigrateDblogConfigsTest.php
    @@ -1,5 +1,7 @@
     <?php
     
    +declare(strict_types=1);
    +
     namespace Drupal\Tests\dblog\Kernel\Migrate\d6;
     
     use Drupal\Tests\SchemaCheckTestTrait;
    @@ -35,7 +37,7 @@ protected function setUp(): void {
       /**
        * Tests migration of dblog variables to dblog.settings.yml.
        */
    -  public function testDblogSettings() {
    +  public function testDblogSettings(): void {
         $config = $this->config('dblog.settings');
         $this->assertSame(10000, $config->get('row_limit'));
         $this->assertConfigSchema(\Drupal::service('config.typed'), 'dblog.settings', $config->get());
    diff --git a/core/modules/dblog/tests/src/Kernel/Migrate/d7/MigrateDblogConfigsTest.php b/core/modules/dblog/tests/src/Kernel/Migrate/d7/MigrateDblogConfigsTest.php
    index f88dbd3543..92e338cebc 100644
    --- a/core/modules/dblog/tests/src/Kernel/Migrate/d7/MigrateDblogConfigsTest.php
    +++ b/core/modules/dblog/tests/src/Kernel/Migrate/d7/MigrateDblogConfigsTest.php
    @@ -1,5 +1,7 @@
     <?php
     
    +declare(strict_types=1);
    +
     namespace Drupal\Tests\dblog\Kernel\Migrate\d7;
     
     use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
    @@ -28,7 +30,7 @@ protected function setUp(): void {
       /**
        * Tests migration of dblog variables to dblog.settings.yml.
        */
    -  public function testDblogSettings() {
    +  public function testDblogSettings(): void {
         $config = $this->config('dblog.settings');
         $this->assertSame(10000, $config->get('row_limit'));
       }
    diff --git a/core/modules/dblog/tests/src/Kernel/Views/ViewsIntegrationTest.php b/core/modules/dblog/tests/src/Kernel/Views/ViewsIntegrationTest.php
    index 6ab50e91ec..ee75d0738b 100644
    --- a/core/modules/dblog/tests/src/Kernel/Views/ViewsIntegrationTest.php
    +++ b/core/modules/dblog/tests/src/Kernel/Views/ViewsIntegrationTest.php
    @@ -1,5 +1,7 @@
     <?php
     
    +declare(strict_types=1);
    +
     namespace Drupal\Tests\dblog\Kernel\Views;
     
     use Drupal\Component\Render\FormattableMarkup;
    @@ -48,7 +50,7 @@ protected function setUp($import_test_views = TRUE): void {
       /**
        * Tests the messages escaping functionality.
        */
    -  public function testMessages() {
    +  public function testMessages(): void {
     
         // Remove the watchdog entries added by the potential batch process.
         $this->container->get('database')->truncate('watchdog')->execute();
    @@ -92,7 +94,7 @@ public function testMessages() {
       /**
        * Tests the relationship with the users_field_data table.
        */
    -  public function testRelationship() {
    +  public function testRelationship(): void {
         $view = Views::getView('dblog_integration_test');
         $view->setDisplay('page_1');
         // The uid relationship should now join to the {users_field_data} table.
    @@ -105,7 +107,7 @@ public function testRelationship() {
       /**
        * Tests views can be filtered by severity and log type.
        */
    -  public function testFiltering() {
    +  public function testFiltering(): void {
         // Remove the watchdog entries added by the potential batch process.
         $this->container->get('database')->truncate('watchdog')->execute();
         $this->createLogEntries();
    
  • 🇺🇸United States kkaya

    Thank you very much @cilefen! Taking steps to reproduce, it looks like a conflict with the monolog module, so can close this ticket. Appreciate your help.

Production build 0.71.5 2024