Problem/Motivation

We're seeing the following error:

#0 [internal function]: field_tokens()
#1 /web/core/lib/Drupal/Core/Extension/ModuleHandler.php(403): call_user_func_array()
#2 /web/core/lib/Drupal/Core/Utility/Token.php(304): Drupal\Core\Extension\ModuleHandler->invokeAll()
#3 /web/modules/contrib/token/token.tokens.inc(937): Drupal\Core\Utility\Token->generate()
#4 [internal function]: token_tokens()
#5 /web/core/lib/Drupal/Core/Extension/ModuleHandler.php(403): call_user_func_array()
#6 /web/core/lib/Drupal/Core/Utility/Token.php(304): Drupal\Core\Extension\ModuleHandler->invokeAll()
#7 /web/modules/contrib/filelog/filelog.tokens.inc(135): Drupal\Core\Utility\Token->generate()
#8 [internal function]: filelog_tokens()
#9 /web/core/lib/Drupal/Core/Extension/ModuleHandler.php(403): call_user_func_array()
#10 /web/core/lib/Drupal/Core/Utility/Token.php(304): Drupal\Core\Extension\ModuleHandler->invokeAll()
#11 /web/core/lib/Drupal/Core/Utility/Token.php(196): Drupal\Core\Utility\Token->generate()
#12 /web/modules/contrib/filelog/src/Logger/FileLog.php(223): Drupal\Core\Utility\Token->replace()
#13 /web/modules/contrib/filelog/src/Logger/FileLog.php(157): Drupal\filelog\Logger\FileLog->render()
#14 /web/core/lib/Drupal/Core/Logger/LoggerChannel.php(127): Drupal\filelog\Logger\FileLog->log()
#15 /web/core/includes/errors.inc(175): Drupal\Core\Logger\LoggerChannel->log()
#16 /web/core/includes/errors.inc(83): _drupal_log_error()
#17 /web/core/includes/bootstrap.inc(346): _drupal_error_handler_real()
#18 /web/core/lib/Drupal/Core/Cache/DatabaseBackend.php(121): _drupal_error_handler()
#19 /web/core/lib/Drupal/Core/Cache/DatabaseBackend.php(92): Drupal\Core\Cache\DatabaseBackend->getMultiple()
#20 /web/core/modules/page_cache/src/StackMiddleware/PageCache.php(306): Drupal\Core\Cache\DatabaseBackend->get()
#21 /web/core/modules/page_cache/src/StackMiddleware/PageCache.php(124): Drupal\page_cache\StackMiddleware\PageCache->get()
#22 /web/core/modules/page_cache/src/StackMiddleware/PageCache.php(82): Drupal\page_cache\StackMiddleware\PageCache->lookup()
#23 /web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Drupal\page_cache\StackMiddleware\PageCache->handle()
#24 /web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle()
#25 /vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle()
#26 /web/core/lib/Drupal/Core/DrupalKernel.php(708): Stack\StackedHttpKernel->handle()
#27 /web/index.php(19): Drupal\Core\DrupalKernel->handle()
#28 {main}

Steps to reproduce

When filelog module and page_cache is enabled and DatabaseBackend->getMultiple() throw's a fatal error.

Proposed resolution

This is the most similar error I've seen. It looks like when page_cache throws a fatal error (i.e. before a full bootstrap is done), file logging module calls token replace, which doesn't exist yet.

Maybe filelog should skip token hooks when logging page_cache errors?

Issue fork filelog-3270867

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

firewaller created an issue. See original summary.

firewaller’s picture

cburschka’s picture

This looks tough. There's nothing immediately going wrong when calling the token service; the failure is buried far down in the call-stack where it reaches the token contrib module. I'm not sure if this means the token service is generally unsafe to call in early bootstrap (which would mean we must check the bootstrap level before calling it), or only if specific contributed modules are installed.

As far as I'm aware though, undefined function errors *can* be caught by try-catch though, so this may be fixed by coding a bit more defensively: Wrapping the render() in a try-catch and falling back to skipping the log message entirely. (Rendering without tokens isn't useful; the output would simply be a copy of the template string. I suppose we could "defer" logging by storing the message in a state variable for later, but that'd be a substantial new feature for a later version.)

firewaller’s picture

So something like this short-term and then adding a "defer" feature separately?

churel made their first commit to this issue’s fork.

churel’s picture

Hello,

Php 7 is able to catch errors but only if we catch them Error or Throwable. Added the render function in the try, and adding a catch for Throwable works for me

cburschka’s picture

Status: Active » Needs work

Indeed; the undefined function error is not caught with \Exception.

Also note that the catch block should probably exit the function, as without rendering the log message cannot be logged.

Edit: I didn't see the merge request now has both the rendering and the file-writing in the try block, which fixes the above.

cburschka’s picture

Status: Needs work » Needs review

@churel, were you able to confirm that this fixes the problem when logging before the full bootstrap? I don't have a setup for reproducing this problem myself so I can't really test it.

churel’s picture

@cburschka Yes, the fatal error got caught and the page displays correctly now for me.

mr_fenix’s picture

Status: Needs review » Needs work

Hello,

I have tested this with Drupal 9.3 (with a standard profile), PHP 7.4, and filelog 2.0.x-dev(Currently it also is applicable to other versions)

I was not able to reproduce the exactly same error inside the method cache Drupal\Core\Cache\DatabaseBackend->getMultiple() following the information given here, also it seems complex tokens of the type [log:user:url] were used. However,i am sure the idea is the filelog does not report errors from the PageCache MiddleWare service. Indeed this is the case - I've tested it.

When the Drupal\page_cache\StackMiddleware\PageCache->handle service is invoked, all services are initialized at this stage, but the files of type tokens.module (*.module) are not loaded yet (hook_tokens won't work in these files - core tokens functionality purely support early calls too), so this error is a result of the token module not supporting calls at early stages (as it uses functions from the token.module file), and you could test this simply by uninstalling the token module for example.

Also, there is another problem. When an error is logged from the PageCache MiddleWare service at this stage, the "public" Stream Wrapper is not initialized yet, and as a result, if the root directory is writable, a folder named logs will be created in the web root directory and all next errors in this request will be logged in logs/drupal.log in the web directory. Maybe a check needs to be done for the existence of the "public" Stream Wrapper before opening the file for writing.

Summarizing:
1. Early calls support seems to need to be fixed in the ,token module.
2. This patch is a partial solution, the error in the log file is still not logged when it appears at the early stages of PageCache MiddleWare Service.
3. When the public Stream Wrapper is not defined, errors are logged in a different place - web/logs/drupal.log

So, the patch #5 needs to be updated according to point (3) at least. Ideally, there should be a functionality to log to the drupal.log file (2), or get it ignored if the token module gets fixed and starts supporting calls from MiddleWare services (for those running before Drupal\Core\DrupalKernel MW) (1).

Also, I will add that after this patch implementation if an error occurs during token processing, that error will be logged only in the PHP error log instead of the drupal.log file, which also seems to need to be fixed. For this, the module's functionality might need to be changed to create its own token processing system, to be only partially dependent on the token functionality, and when there is an error in token parsing, to have the ability to log this also to the drupal.log file, using an alternative (implementable without the token module functionality) error message formatting.

Thanks

AstonVictor changed the visibility of the branch 3270867-call-to-undefined to hidden.

astonvictor’s picture

Version: 2.0.x-dev » 2.1.x-dev

astonvictor’s picture

Status: Needs work » Fixed

was not able to reproduce it with drupal 10.2. anyway added a try catch in case.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.