Display backtrace for logged throwables on log message details page

Created on 7 October 2020, over 3 years ago
Updated 27 November 2023, 7 months ago

Problem/Motivation

When an exception is logged to the dblog by \Drupal\Core\EventSubscriber\ExceptionLoggingSubscriber::onError() or \Drupal\Core\Utility\Error::logException(), there is no backtrace on the log event details page and it is very difficult to find the problem in code.

Steps to reproduce

Throw an exception from a controller and look at the message logged by dblog module.

Proposed resolution

Option B) [Chosen resolution] Do not add @backtrace_string to log messages; instead, because @backtrace_string is already part of the context array passed to loggers, dblog module can display the backtrace as a separate row at the bottom of the log details page. See #28

Remaining tasks

User interface changes

dblog module: PHP errors and some throwables already contained a backtrace in the log message - this is now expanded to an additional large set of throwables.

API changes

none

Data model changes

none

Release notes snippet

Feature request
Status

Fixed

Version

10.2

Component
Database Logging 

Last updated about 1 month ago

Created by

🇺🇦Ukraine super_romeo Kiev

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

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇬🇧United Kingdom alexpott 🇪🇺🌍

    The question in #24 is a good one.

    +++ b/core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php
    @@ -67,7 +67,7 @@ public function on404(ExceptionEvent $event) {
    -    $this->logger->get('php')->log($error['severity_level'], Error::DEFAULT_ERROR_MESSAGE, $error);
    +    $this->logger->get('php')->log($error['severity_level'], Error::DEFAULT_ERROR_MESSAGE . ' @backtrace_string', $error);
     
         $is_critical = !$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500;
    

    I think we should only be adding the backtrace for critical errors. Like I don't think we should be adding backtraces for \Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException for example.

    And we should have concerns about swamping logs.

    So yeah I think we should have the ability to display the backtrace in dblog if we have the backtrace_string in the context variables - even if it is not in the message. Great idea @mfb

  • 🇬🇧United Kingdom alexpott 🇪🇺🌍

    And then we won't need to make the change to ExceptionLoggingSubscriber

  • Status changed to Needs review over 1 year ago
  • 🇺🇸United States mfb San Francisco

    Here's the alternate approach to not add @backtrace_string to the log message, and instead display it as a new row at the bottom of the dblog event details page.

  • 🇬🇧United Kingdom alexpott 🇪🇺🌍

    @mfb #28 looks nice!

    I think we should only do this if the string does not have the @backtrace_string in it - otherwise the page is going to have a lot of duplicate content.

  • 🇺🇸United States mfb San Francisco

    Resolves #29

  • 🇮🇳India Nitin shrivastava

    Fix command failures #30

  • Status changed to Needs work over 1 year ago
  • 🇬🇧United Kingdom alexpott 🇪🇺🌍
    +++ b/core/modules/dblog/tests/src/Functional/DbLogTest.php
    @@ -143,6 +143,30 @@ public function testLogEventPage() {
    diff --git a/core/themes/gin b/core/themes/gin
    
    diff --git a/core/themes/gin b/core/themes/gin
    new file mode 160000
    
    new file mode 160000
    index 0000000000..0a89ac8733
    
    index 0000000000..0a89ac8733
    --- /dev/null
    
    --- /dev/null
    +++ b/core/themes/gin
    
    +++ b/core/themes/gin
    +++ b/core/themes/gin
    @@ -0,0 +1 @@
    
    @@ -0,0 +1 @@
    +Subproject commit 0a89ac873395ae9ecff7474a4685a305463c9ac6
    

    This should not be here.

  • First commit to issue fork.
  • Status changed to Needs review over 1 year ago
  • 🇺🇸United States mfb San Francisco

    Resolved #32

  • Status changed to RTBC over 1 year ago
  • 🇺🇸United States smustgrave

    This issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.

    #33 appears (from what I can tell) to be a rebase.

    Since there were a number of changes since I added a test case in #19 think I'm good to review.

    So reviewing #34

    Tested this using the error_test module and visiting /error-test/trigger-exception
    Checking the logs and I see

    Exception: Drupal & awesome in Drupal\error_test\Controller\ErrorTestController->triggerException() (line 74 of /var/www/html/web/core/modules/system/tests/modules/error_test/src/Controller/ErrorTestController.php).
    

    with no backtrace

    Applying fix
    I see the same issue with the backtrace.

    Looks good!

  • 🇺🇸United States mfb San Francisco

    Created a draft change record @ https://www.drupal.org/node/3340781

  • Status changed to Needs work over 1 year ago
  • 🇬🇧United Kingdom alexpott 🇪🇺🌍
    +++ b/core/includes/errors.inc
    @@ -172,7 +172,7 @@ function _drupal_log_error($error, $fatal = FALSE) {
    -      \Drupal::logger('php')->log($severity, '%type: @message in %function (line %line of %file) @backtrace_string.', $error + ['backtrace' => $backtrace, 'exception' => $exception, 'severity_level' => $severity]);
    +      \Drupal::logger('php')->log($severity, Error::DEFAULT_ERROR_MESSAGE, $error + ['backtrace' => $backtrace, 'exception' => $exception, 'severity_level' => $severity]);
    
    +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityUpdater.php
    @@ -154,7 +154,7 @@ public function update(array &$sandbox, $entity_type_id, callable $callback = NU
    -        \Drupal::logger('update')->error('Unable to update %entity_type %view due to error @message %function (line %line of %file). <pre>@backtrace_string</pre>', $context);
    +        \Drupal::logger('update')->error('Unable to update %entity_type %view due to error @message %function (line %line of %file).', $context);
    

    I don't think we should be making these changes here. This will alter the syslog output.

  • 🇺🇸United States mfb San Francisco

    Well, I'm unclear on the logic of sending @backtrace_string to syslog here, but not for most throwables which are logged by the ExceptionLoggingSubscriber. Note that previously PHP triggered lots of old-fashioned PHP errors/warnings/etc. but now throwing an Error is more common, and they go to ExceptionLoggingSubscriber most of the time. And throwables are the main thing that you would expect to have a backtrace for.

    My understanding is anything thrown during normal request handling is logged by ExceptionLoggingSubscriber; and outside of that _drupal_log_error() is used (e.g. running a script via drush with drupal bootstrapped).

    We could have syslog start logging @backtrace_string? Or have a new syslog config toggle to add @backtrace_string to the syslog message? That way it could finally be logged for most throwabes.

    Note that when you send @backtrace_string to syslog you actually get multiple syslog messages, one for each line :/ So I'm not sure everyone appreciates it, but if syslog is your only logging then I guess that's where you want to find backtraces..

  • 🇬🇧United Kingdom alexpott 🇪🇺🌍

    @mfb let’s open a follow-up to discuss that. I don’t think that working that out needs to impact us making this improvement in dblog.

  • Status changed to Needs review over 1 year ago
  • 🇺🇸United States mfb San Francisco

    Ok removed those changes, and updated the change record to match.

  • 🇺🇸United States mfb San Francisco

    Filed a followup @ 📌 Sort out @backtrace_string logging by Syslog module Active

    I don't use syslog module so I don't have strong feelings how it should work, but I do maintain two contrib logger modules, so more sanity around this is helpful :)

  • Status changed to RTBC over 1 year ago
  • 🇺🇸United States smustgrave

    Moving back to RTBC but could some strike out in the issue summary which option wasn't chosen?

  • 🇺🇸United States mfb San Francisco
  • 🇺🇸United States mfb San Francisco

    Unrelated failure

  • 🇦🇺Australia VladimirAus Brisbane, Australia

    +1. Moving patch to MR.

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    30,128 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    29,204 pass
  • 🇳🇿New Zealand quietone New Zealand

    There are reasons to convert a patch to an MR but this was already RTBC and doing so it was not needed. There are no comments why the MR was done. This MR is against 9.4.x, where this patch is not eligible. It also generated two unnecessary test runs. To be sure there were no changes I downloaded both the MR and patch. They are the same. Therefor, credit has been removed per How is credit granted for Drupal core issues .

    Also, the latest patch is no longer being tested every two day. Since I have already downloaded the patch, I will upload again to be sure that the automatic testing restarts.

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    29,285 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    29,302 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    29,304 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    29,306 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    29,361 pass
  • Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    Waiting for branch to pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    30,128 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    30,128 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    30,128 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    30,128 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    30,128 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    29,382 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    29,385 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    29,390 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    29,390 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    29,390 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    29,390 pass
  • Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update about 1 year ago
    Waiting for branch to pass
  • Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened , as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle .

  • last update 12 months ago
    29,813 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 12 months ago
    29,446 pass
  • 🇺🇸United States mfb San Francisco

    That was an unrelated failure, back to RTBC

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 12 months ago
    29,446 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 12 months ago
    29,448 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 12 months ago
    29,448 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 12 months ago
    29,448 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 11 months ago
    29,448 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 11 months ago
    29,452 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 11 months ago
    29,455 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    23:50
    21:51
    Running
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 11 months ago
    29,457 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 11 months ago
    29,458 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 11 months ago
    29,459 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    24:19
    19:44
    Running
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 11 months ago
    29,460 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 11 months ago
    29,461 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 11 months ago
    29,467 pass
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 11 months ago
    29,467 pass
  • Status changed to Needs work 11 months ago
  • 🇳🇿New Zealand quietone New Zealand

    I am doing triage on the core RTBC queue .

    I read the issue summary, comments and the patch. The proposed resolution matches the patch. The remaining tasks is a bit of date but lets see if I find anything still to do.

    I don't know the error handling system so I applied the patch and ran the tests. The output in the logs is just another row for the backtrace and it was formatted correctly. I then copied the trigger_error line from the test to another form and went to that form. The resulting error does not have a backtrace. Why? To answer that I read the CR. I guess the form I was using doesn't use ExceptionLoggingSubscriber?

    Now that I have read the CR I see that the branch/version are out of date. The CR mentions adding '@backtrace_string' in the context array. This should be accompanied by a before and after example. Along with anything else one needs to do to use this functionality.

    Oh, and the title should explain what the change is. Maybe something like 'Backtrace can be logged when using ExceptionLoggingSubscriber or watchdog_exception()"?

    For updating the CR I am adding the tag and setting to NW.

    And from reading the patch there were two small things.

    +++ b/core/modules/dblog/tests/src/Functional/DbLogTest.php
    @@ -143,6 +143,30 @@ public function testLogEventPage() {
    +   * Test that an error logged has a backtrace.
    

    Should be "Tests" not "Test".
    This reads as if any error logged will have a backtrace which isn't true

  • Status changed to Needs review 11 months ago
  • last update 11 months ago
    29,961 pass
  • 🇺🇸United States mfb San Francisco

    @quietone thanks for the review, I tried to clarify the change record. Let me know what you think.

    I also updated the test method description to clarify that this specific test is about the backtrace being displayed when a throwable is logged.

    The idea is that with this change, Database Logging module will display a backtrace in many common cases. When trigger_error() is called, both the log message and context should contain @backtrace_string and therefore the backtrace should be displayed as part of the log message. This was already the case, and is tested by \Drupal\Tests\dblog\Functional\DbLogTest::testBacktrace(). When a throwable is logged, the context should contain @backtrace_string, although the log message will not, and therefore the backtrace should be displayed at the bottom of the details page. This is the new behavior, and is tested by \Drupal\Tests\dblog\Functional\DbLogTest::testOnError().

    @quietone could you clarify the situation where there is no backtrace so we can double check all this?

    (By the way, in followup issue 📌 Sort out @backtrace_string logging by Syslog module Active , we can discuss if it makes sense to remove @backtrace_string from the log message and provide it only in the context, under the reasoning that such a string is too long for a log message, and loggers can retrieve it from the context if/when they want it, as dblog is doing in this case.)

  • 🇺🇸United States mfb San Francisco

    Removed remaining tasks (until next review :)

  • Status changed to Needs work 11 months ago
  • 🇦🇷Argentina dagmar Argentina

    @mfb Any particular reason why

              // Save a reference so the backtrace can be displayed separately.
              if (!str_contains($row->message, '@backtrace_string')) {
                $row->backtrace = $variables['@backtrace_string'];
              }
    

    Can be calculated inside the eventDetails method? The logic here seems a bit odd to follow. Also with change from #52 ::formatMessage would do more than just formatting the message.

  • Status changed to Needs review 11 months ago
  • last update 11 months ago
    29,969 pass
  • 🇺🇸United States mfb San Francisco

    Ok, I added more documentation re: the formatMessage() method not just formatting the message, but also adding a backtrace property to the row if there is a @backtrace_string that is not used in the message.

    In the formatMessage() method, the variables are unserialized and the backtrace markup object is created for use in the message. It would be redundant to repeat these two steps again in the eventDetails() method. If we need to further refactor this code, it would be nice to figure out a way to do that without redundancy.

  • 🇺🇸United States AaronBauman Philadelphia

    latest MR applies cleanly to 10.1 and works great, thanks y'all!
    +1 RTBC from me

    Would love to see this feature in an upcoming D10 release, and not have to maintain this patch for the next couple years... do we need a "needs backport" tag for that?

  • Status changed to Needs work 10 months ago
  • 🇦🇷Argentina dagmar Argentina

    In the formatMessage() method, the variables are unserialized and the backtrace markup object is created for use in the message. It would be redundant to repeat these two steps again in the eventDetails()

    @mfb I see. Thanks!

    Are we re-introducing #2371141: XSS vulnerability when displaying exception backtrace because we are not sanitizing the output? I would love to see a test case for this new addition.

  • last update 10 months ago
    30,062 pass
  • @vladimiraus opened merge request.
  • last update 10 months ago
    30,062 pass
  • last update 10 months ago
    30,050 pass, 2 fail
  • Status changed to Needs review 10 months ago
  • last update 10 months ago
    30,062 pass
  • 🇺🇸United States mfb San Francisco

    Added an assertion that the backtrace is HTML-encoded

  • Status changed to RTBC 10 months ago
  • 🇺🇸United States smustgrave

    Seems #57 has been addressed. Remarking this one.

  • last update 10 months ago
    30,065 pass
  • last update 10 months ago
    30,132 pass
  • last update 10 months ago
    30,137 pass
  • last update 10 months ago
    30,138 pass
  • last update 10 months ago
    30,138 pass
  • last update 10 months ago
    30,148 pass
  • last update 10 months ago
    30,148 pass
  • 54:19
    47:24
    Running
  • last update 10 months ago
    30,156 pass
  • 54:17
    53:07
    Running
  • last update 9 months ago
    30,170 pass
  • last update 9 months ago
    30,170 pass
  • last update 9 months ago
    30,207 pass
  • last update 9 months ago
    30,208 pass
  • last update 9 months ago
    30,362 pass
  • 24:20
    46:31
    Running
  • last update 9 months ago
    30,362 pass
  • last update 9 months ago
    30,373 pass
  • last update 9 months ago
    30,379 pass
  • last update 9 months ago
    30,379 pass
  • last update 9 months ago
    30,386 pass
  • last update 9 months ago
    30,395 pass
  • last update 9 months ago
    30,399 pass
  • last update 9 months ago
    30,399 pass
  • last update 9 months ago
    30,417 pass
  • last update 8 months ago
    30,422 pass
  • last update 8 months ago
    30,428 pass
  • last update 8 months ago
    30,430 pass
  • 🇦🇺Australia silverham

    +1 for interest on getting this one commited.

  • last update 8 months ago
    30,440 pass
  • last update 8 months ago
    30,457 pass, 1 fail
  • 24:19
    20:20
    Running
  • last update 8 months ago
    30,485 pass
  • last update 8 months ago
    30,487 pass
  • last update 8 months ago
    30,488 pass
  • last update 8 months ago
    30,490 pass
  • last update 8 months ago
    30,513 pass
  • 🇺🇸United States xjm

    There are two open merge requests and a patch in the issue summary. There should be only one canonical patch or merge request listed.

    Please close the non-canonical merge request(s) and hide non-canonical patches. If you don't have permission to close merge requests, please hide any non-canonical patches and then document which merge request(s) should be closed in an issue comment and the IS. This will allow a committer to close them for you. Thanks!

  • Status changed to Needs work 8 months ago
  • 🇺🇸United States smustgrave

    #62 also MR is saying unmeragble so will need manual rebase it seems.

  • Status changed to Needs review 8 months ago
  • 🇺🇸United States mfb San Francisco

    My latest work on this is patch #59; please close both MRs thank you!

  • last update 8 months ago
    30,514 pass
  • Status changed to RTBC 8 months ago
  • 🇺🇸United States xjm

    Done, thanks @mfb!

  • Status changed to Needs work 8 months ago
  • 🇺🇸United States xjm
    1. Should there be a new restricted-access permission for viewing backtraces? Or is whatever current permission is required sufficient?

    2. +++ b/core/modules/dblog/src/Controller/DbLogController.php
      @@ -291,6 +291,12 @@ public function eventDetails($event_id) {
      +        ['data' => $this->t('Backtrace'), 'header' => TRUE],
      +        $dblog->backtrace,
      

      I feel like some things already have backtraces in the description... or am I thinking of devel? If I am thinking of devel, it merely needs a CR. If I'm actually remembering other backtraces in the log, then we also need core issue followups for those cases.

    3. +++ b/core/modules/dblog/src/Controller/DbLogController.php
      @@ -348,7 +354,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.
      +   *   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.
      

      I think the added information should be in a separate paragraph in the row description. (I also think the list of properties should be in a list, but that's out of scope here.)

    4. +++ b/core/modules/dblog/tests/src/Functional/DbLogTest.php
      @@ -142,6 +142,31 @@ public function testLogEventPage() {
      +   * Tests that the details page displays the backtrace for a logged throwable.
      

      "Throwable" is a Drupalism used in like five places that we might try to remove from the dictionary. Could we just say "logged exception"?

    5. +++ b/core/modules/dblog/tests/src/Functional/DbLogTest.php
      @@ -142,6 +142,31 @@ public function testLogEventPage() {
      +    // Login the admin user.
      

      Nit: "Login" is a noun. "Log in" is a verb. So:

      Log in as the admin user.

    6. +++ b/core/modules/dblog/tests/src/Functional/DbLogTest.php
      @@ -142,6 +142,31 @@ public function testLogEventPage() {
      +    // Trigger error.
      

      I don't think this comment is helpful as-is. It should either be removed or expanded with more detail.

    7. +++ b/core/modules/dblog/tests/src/Functional/DbLogTest.php
      @@ -142,6 +142,31 @@ public function testLogEventPage() {
      +    $query = Database::getConnection()->select('watchdog')
      +      ->condition('type', 'php');
      +    $query->addExpression('MAX([wid])');
      +    $wid = $query->execute()->fetchField();
      +    $this->drupalGet('admin/reports/dblog/event/' . $wid);
      

      OTOH, this could use an inline comment. explaining what's going on.

    8. +++ b/core/modules/dblog/tests/src/Functional/DbLogTest.php
      @@ -142,6 +142,31 @@ public function testLogEventPage() {
      +    $table = $this->assertSession()->elementExists('xpath', "//table[@class='dblog-event']");
      +    $type = "//tr/th[contains(text(), 'Type')]/../td";
      +    $this->assertSession()->elementsCount('xpath', $type, 1, $table);
      

      As could this.

    9. +++ b/core/modules/dblog/tests/src/Functional/DbLogTest.php
      @@ -142,6 +142,31 @@ public function testLogEventPage() {
      +    $backtrace = "//tr//pre[contains(@class, 'backtrace')]";
      +    $this->assertCount(1, $table->findAll('xpath', $backtrace));
      +    $this->assertSession()->responseContains(htmlspecialchars("<script>alert('xss')</script>"));
      

      As could this. Especially the last line. I had a brief moment of panic with the positive assertion and the JS before I re-read and caught the htmlspecialchars(). 😛

    10. +++ b/core/modules/system/tests/modules/error_test/src/Controller/ErrorTestController.php
      @@ -69,8 +69,11 @@ public function generateFatals() {
      -  public function triggerException() {
      +  public function triggerException($argument = "<script>alert('xss')</script>") {
      

      The new parameter needs a typehint and documentation in the docblock.

    11. +++ b/core/modules/system/tests/modules/error_test/src/Controller/ErrorTestController.php
      @@ -69,8 +69,11 @@ public function generateFatals() {
      +    // Add function calling arguments to the exception backtrace.
      

      I think "function call" would work here (rather than "function calling")?

  • Status changed to Needs review 8 months ago
  • 🇺🇸United States mfb San Francisco

    Removed the "Needs change record" tag because this issue already has a change record. Feel free to criticize and/or re-draft it though :)

    Should there be a new restricted-access permission for viewing backtraces? Or is whatever current permission is required sufficient?

    I don't think a new permission is necessary, because A) some Drupal core logging mechanisms already make backtraces available as part of the log message, so this is not the first time that site admins have access to exception backtraces, it would just be happening more often now; and B) PHP, assuming it is configured correctly (!), keeps backtraces free of sensitive data via two configs: zend.exception_ignore_args (should be enabled on production to leave function arguments out of the backtrace) and zend.exception_string_param_max_len (should be zero on production, such that if arguments are added to the backtrace, strings will be cutoff at zero characters).

    I feel like some things already have backtraces in the description... or am I thinking of devel? If I am thinking of devel, it merely needs a CR. If I'm actually remembering other backtraces in the log, then we also need core issue followups for those cases.

    Yes, some things already have a backtrace in the log message: 1) When a \Throwable is thrown early or late in the request lifecycle, it is caught by Drupal's exception handler; and 2) when a PHP error/warning is triggered (these are triggered not thrown), it is caught by Drupal's error handler; both of these mechanisms add the backtrace to the log message.

    This issue is addressing two other logging mechanisms. There is no backtrace added to the log message 1) when a \Throwable is thrown in the middle of the request (e.g. in a controller) and caught by \Drupal\Core\EventSubscriber\ExceptionLoggingSubscriber::onError(), or 2) when a developer uses \Drupal\Core\Utility\Error::logException() to manually log a \Throwable. The backtrace is however in the log context in both cases, and thus available to loggers such as dblog, which is what we're taking advantage of in this patch.

    This was already explained to some extent in the change record, but we could flesh it out further if need be.

    As far as followups: We could e.g. remove backtrace strings where they do already appear in log messages, and switch to the mechanism used in this patch. I like the idea, but I'm not sure there is consensus; some people might be relying on the currently-existing backtraces in their log messages in Syslog or wherever they are logging. Personally, I prefer to have short log messages in Syslog, and some other system for storing backtraces and other large blobs of data ("crash dumps"). I did previously open this related/followup issue for further discussion re: Syslog module: 📌 Sort out @backtrace_string logging by Syslog module Active . I think anyone who really cares about logging, and wants to customize it, can install a module like Monolog and go to town, so they're not inclined to worry about how core logs out-of-the-box.

    I think the added information should be in a separate paragraph in the row description. (I also think the list of properties should be in a list, but that's out of scope here.)

    Done.

    "Throwable" is a Drupalism used in like five places that we might try to remove from the dictionary. Could we just say "logged exception"?

    Changed to \Throwable (a PHP class, not a Drupalism). "Logged exception" is unclear because we are talking about both \Exception and \Error objects, i.e. \Throwable objects.

    Nit: "Login" is a noun. "Log in" is a verb. So:

    Fixed

    I don't think this comment is helpful as-is. It should either be removed or expanded with more detail.

    Changed to clearly say what scenario we are testing: "Load a page that throws an exception in the controller, and includes its function arguments in the exception backtrace."

    OTOH, this could use an inline comment. explaining what's going on.

    Added "Load details page for the most recent event logged by the "php" logger."

    As could this.

    Added that - I think - this is just checking that there's a vaguely-correct dblog-event table with a "Type" header cell? Idk lol.

    As could this. Especially the last line. I had a brief moment of panic with the positive assertion and the JS before I re-read and caught the htmlspecialchars(). 😛 I would prefer that assertions contain a string literal rather than functions operating on a string.

    Added explanation and changed to string literal.

    The new parameter needs a typehint and documentation in the docblock.

    Added types and docblock documentation.

    I think "function call" would work here (rather than "function calling")?

    I changed "function calling arguments" to "function arguments" to make it less verbose.

  • last update 8 months ago
    30,518 pass
  • 🇺🇸United States mfb San Francisco

    Oops I fixed the wrong case of "Login" to "Log in" :p And a typo

  • last update 8 months ago
    30,518 pass
  • Status changed to RTBC 8 months ago
  • 🇺🇸United States smustgrave

    Believe the feedback has been addressed

  • Status changed to Needs work 8 months ago
  • The Needs Review Queue Bot tested this issue.

    While you are making the above changes, we recommend that you convert this patch to a merge request . Merge requests are preferred over patches. Be sure to hide the old patch files as well. (Converting an issue to a merge request without other contributions to the issue will not receive credit.)

  • last update 8 months ago
    30,530 pass
  • 🇺🇸United States xjm

    Thanks @mfb; the explanation in #69 is helpful.

    Regarding the permissions, I verified that the permission required for dblog pages is access site reports, which is already a restricted access permission, so that's fine.

    That said, I noticed there's outstanding feedback from @alexpott that has not been addressed it. It was recommended to only add backtraces for critical messages to avoid blowing up the logs. I can see the value in wanting to have backtraces for non-critical messages; however, I agree with the log size concern also. Maybe a (non-UI) configuration setting would be helpful here? Tagging for framework manager review once we get a proposed solution.

    Meanwhile, a couple nitpicks escaped the cleanups above:

    1. +++ b/core/modules/dblog/tests/src/Functional/DbLogTest.php
      @@ -142,6 +142,35 @@ public function testLogEventPage() {
      +  public function testOnError() {
      

      This is missing a return typehint.

    2. +++ b/core/modules/dblog/tests/src/Functional/DbLogTest.php
      @@ -142,6 +142,35 @@ public function testLogEventPage() {
      +    // Log in the admin user.
      

      Also still missing the word "as".

    3. +++ b/core/modules/dblog/tests/src/Functional/DbLogTest.php
      @@ -142,6 +142,35 @@ public function testLogEventPage() {
      +    // Load details page for the most recent event logged by the "php" logger.
      

      Still missing the word "the".

  • Status changed to Needs review 8 months ago
  • 🇺🇸United States mfb San Francisco

    @xjm This version of the patch is the response to @alexpott's concern. At this point there should not be cause for concern about log size, as we decided to display the @backtrace_string that dblog has already been storing in the variables database column this whole time (it just was not being displayed in these cases).

    So there is no size increase here. There is an increase of information available in the UI, but it's helpfully in its own table row, down at the bottom of the page.

    Any code doing logging always has the option of removing the @backtrace_string from the context array if it will not be helpful. But I'm not aware of any places where we should do that at this time.

    Fixed up those nitpicks

  • last update 8 months ago
    30,532 pass
  • 🇺🇸United States mfb San Francisco

    @xjm @alexpott Looking at core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php I do see one place where we could consider removing @backtrace_string from the context array: The ExceptionLoggingSubscriber::onClientError() method.

    It's already removed in the ExceptionLoggingSubscriber::on403() method.

    This would clean up the UI by removing the backtrace for miscellaneous 4xx errors (e.g. \Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException) logged by this mechanism, and would reduce storage size of dblog module going forward, for sites that have been getting lots of non-404/403 4xx errors.

    Could also be decided in a followup if we're not sure.

  • 🇺🇸United States mfb San Francisco

    The @backtrace_string was removed for 403 errors in #3167390: ExceptionLoggingSubscriber should not log backtrace string on access denied exceptions . Looks like there was no discussion at that time re: whether or not it'd be a good idea to remove for other 4xx errors.

  • Status changed to RTBC 8 months ago
  • 🇺🇸United States smustgrave

    Think this would be a nice feature to have for 10.2.

    #75 mentions we could do more in a follow up potentially.

  • 🇬🇧United Kingdom alexpott 🇪🇺🌍

    The fix in #74 looks great. It's not adding storing anything new - it's just surfacing information we already have - nice. And the follow-ups to consider removing where it is not helpful are great too.

  • Status changed to Needs work 8 months ago
  • 🇺🇸United States xjm

    Thanks @alexpott.

    Let's add an additional followup for #75 and then I think this is ready to go.

  • Status changed to RTBC 8 months ago
  • 🇺🇸United States smustgrave

    Opened follow up for everyone.

  • 🇺🇸United States smustgrave

    Ah @longwave beat me. I'll close mine out.

  • 🇺🇸United States xjm

    Saving credits.

  • 🇺🇸United States xjm
    +++ b/core/modules/system/tests/modules/error_test/src/Controller/ErrorTestController.php
    @@ -68,9 +68,17 @@ public function generateFatals() {
    +    ini_set('zend.exception_ignore_args', FALSE);
    +    ini_set('zend.exception_string_param_max_len', 1024);
    

    I had a brief moment of concern that this could pollute other tests. What we usually do is save the existing settings and restore them after the test has run.

    However, since this is in the test module rather than the test itself, it's maybe altering the child site PHP settings rather than the parent site settings. Maybe? I do not actually know if the PHP settings are shared between the test runner and test child site or not. We have no other examples of adjusting the ini settings in a tesst module. I'll ask. Leaving RTBC since this might be fine.

  • 🇺🇸United States xjm

    Per @longwave:

    for functional tests it should only be for the duration of the page loaded under test, as they are done through http and ini_set() only lasts for the request

    different story in kernel tests or if it was in the test method for some reason

    So we should be all good here.

    • xjm committed d5e06105 on 11.x
      Issue #3175449 by mfb, super_romeo, smustgrave, _pratik_, Medha Kumari,...
    • xjm committed 72d9d9ba on 10.2.x
      Issue #3175449 by mfb, super_romeo, smustgrave, _pratik_, Medha Kumari,...
  • Status changed to Fixed 8 months ago
  • 🇺🇸United States xjm

    Alright, finally committed to 11.x and 10.2.x as a UI change. Also published the change record. Thanks!

  • 🇬🇧United Kingdom alexpott 🇪🇺🌍
  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.69.0 2024