Issue #2381797 by Tom Verhaeghe, slashrsm, johnwebdev, chr.fritsch, ankithashetty, Krzysztof Domański, nevergone, tobiasb, yogeshmpawar, anmolgoyal74, dhirendra.mishra, Wim Leers, longwave, Fabianx, andypost, joachim, alexpott: Add render_cache debug output
parent
9ff2c846dc
commit
cc44e691f9
|
@ -132,6 +132,14 @@ parameters:
|
|||
#
|
||||
# @default []
|
||||
tags: []
|
||||
# Renderer cache debug:
|
||||
#
|
||||
# Allows cache debugging output for each rendered element.
|
||||
#
|
||||
# Enabling render cache debugging is not recommended in production
|
||||
# environments.
|
||||
# @default false
|
||||
debug: false
|
||||
# Cacheability debugging:
|
||||
#
|
||||
# Responses with cacheability metadata (CacheableResponseInterface instances)
|
||||
|
|
|
@ -21,6 +21,7 @@ parameters:
|
|||
max-age: 0
|
||||
contexts: ['session', 'user']
|
||||
tags: []
|
||||
debug: false
|
||||
factory.keyvalue:
|
||||
default: keyvalue.database
|
||||
http.response.debug_cacheability_headers: false
|
||||
|
|
|
@ -120,6 +120,9 @@ class Renderer implements RendererInterface {
|
|||
$this->elementInfo = $element_info;
|
||||
$this->placeholderGenerator = $placeholder_generator;
|
||||
$this->renderCache = $render_cache;
|
||||
if (!isset($renderer_config['debug'])) {
|
||||
$renderer_config['debug'] = FALSE;
|
||||
}
|
||||
$this->rendererConfig = $renderer_config;
|
||||
$this->requestStack = $request_stack;
|
||||
|
||||
|
@ -215,6 +218,10 @@ class Renderer implements RendererInterface {
|
|||
return '';
|
||||
}
|
||||
|
||||
if ($this->rendererConfig['debug'] === TRUE) {
|
||||
$render_start = microtime(TRUE);
|
||||
}
|
||||
|
||||
if (!isset($elements['#access']) && isset($elements['#access_callback'])) {
|
||||
$elements['#access'] = $this->doCallback('#access_callback', $elements['#access_callback'], [$elements]);
|
||||
}
|
||||
|
@ -276,6 +283,10 @@ class Renderer implements RendererInterface {
|
|||
if (is_string($elements['#markup'])) {
|
||||
$elements['#markup'] = Markup::create($elements['#markup']);
|
||||
}
|
||||
// Add debug output to the renderable array on cache hit.
|
||||
if ($this->rendererConfig['debug'] === TRUE) {
|
||||
$elements = $this->addDebugOutput($elements, TRUE);
|
||||
}
|
||||
// The render cache item contains all the bubbleable rendering metadata
|
||||
// for the subtree.
|
||||
$context->update($elements);
|
||||
|
@ -513,6 +524,11 @@ class Renderer implements RendererInterface {
|
|||
throw new \LogicException('Cache keys may not be changed after initial setup. Use the contexts property instead to bubble additional metadata.');
|
||||
}
|
||||
$this->renderCache->set($elements, $pre_bubbling_elements);
|
||||
// Add debug output to the renderable array on cache miss.
|
||||
if ($this->rendererConfig['debug'] === TRUE) {
|
||||
$render_stop = microtime(TRUE);
|
||||
$elements = $this->addDebugOutput($elements, FALSE, $pre_bubbling_elements, $render_stop - $render_start);
|
||||
}
|
||||
// Update the render context; the render cache implementation may update
|
||||
// the element, and it may have different bubbleable metadata now.
|
||||
// @see \Drupal\Core\Render\PlaceholderingRenderCache::set()
|
||||
|
@ -772,4 +788,67 @@ class Renderer implements RendererInterface {
|
|||
return $this->doTrustedCallback($callback, $args, $message, TrustedCallbackInterface::THROW_EXCEPTION, RenderCallbackInterface::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add cache debug information to the render array.
|
||||
*
|
||||
* @param array $elements
|
||||
* The renderable array that must be wrapped with the cache debug output.
|
||||
* @param bool $is_cache_hit
|
||||
* A flag indicating that the cache is hit or miss.
|
||||
* @param array $pre_bubbling_elements
|
||||
* The renderable array for pre-bubbling elements.
|
||||
* @param float $render_time
|
||||
* The rendering time.
|
||||
*
|
||||
* @return array
|
||||
* The renderable array.
|
||||
*/
|
||||
protected function addDebugOutput(array $elements, bool $is_cache_hit, array $pre_bubbling_elements = [], float $render_time = 0) {
|
||||
if (empty($elements['#markup'])) {
|
||||
return $elements;
|
||||
}
|
||||
|
||||
$debug_items = [
|
||||
'CACHE' => &$elements,
|
||||
'PRE-BUBBLING CACHE' => &$pre_bubbling_elements,
|
||||
];
|
||||
$prefix = "<!-- START RENDERER -->";
|
||||
$prefix .= "\n<!-- CACHE-HIT: " . ($is_cache_hit ? 'Yes' : 'No') . " -->";
|
||||
foreach ($debug_items as $name_prefix => $debug_item) {
|
||||
if (!empty($debug_item['#cache']['tags'])) {
|
||||
$prefix .= "\n<!-- " . $name_prefix . " TAGS:";
|
||||
foreach ($debug_item['#cache']['tags'] as $tag) {
|
||||
$prefix .= "\n * " . $tag;
|
||||
}
|
||||
$prefix .= "\n-->";
|
||||
}
|
||||
if (!empty($debug_item['#cache']['contexts'])) {
|
||||
$prefix .= "\n<!-- " . $name_prefix . " CONTEXTS:";
|
||||
foreach ($debug_item['#cache']['contexts'] as $context) {
|
||||
$prefix .= "\n * " . $context;
|
||||
}
|
||||
$prefix .= "\n-->";
|
||||
}
|
||||
if (!empty($debug_item['#cache']['keys'])) {
|
||||
$prefix .= "\n<!-- " . $name_prefix . " KEYS:";
|
||||
foreach ($debug_item['#cache']['keys'] as $key) {
|
||||
$prefix .= "\n * " . $key;
|
||||
}
|
||||
$prefix .= "\n-->";
|
||||
}
|
||||
if (!empty($debug_item['#cache']['max-age'])) {
|
||||
$prefix .= "\n<!-- " . $name_prefix . " MAX-AGE: " . $debug_item['#cache']['max-age'] . " -->";
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($render_time)) {
|
||||
$prefix .= "\n<!-- RENDERING TIME: " . number_format($render_time, 9) . " -->";
|
||||
}
|
||||
$suffix = "<!-- END RENDERER -->";
|
||||
|
||||
$elements['#markup'] = Markup::create("$prefix\n" . $elements['#markup'] . "\n$suffix");
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Core\Render;
|
||||
|
||||
use function preg_replace;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\Render\Renderer
|
||||
* @group Render
|
||||
*/
|
||||
class RendererDebugTest extends RendererTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
$this->rendererConfig['debug'] = TRUE;
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test render debug output.
|
||||
*/
|
||||
public function testDebugOutput() {
|
||||
$this->setUpRequest();
|
||||
$this->setupMemoryCache();
|
||||
|
||||
$element = [
|
||||
'#cache' => [
|
||||
'keys' => ['render_cache_test_key'],
|
||||
'tags' => ['render_cache_test_tag', 'render_cache_test_tag1'],
|
||||
'max-age' => 10,
|
||||
],
|
||||
'#markup' => 'Test 1',
|
||||
];
|
||||
$markup = $this->renderer->renderRoot($element);
|
||||
|
||||
$expected = <<<EOF
|
||||
<!-- START RENDERER -->
|
||||
<!-- CACHE-HIT: No -->
|
||||
<!-- CACHE TAGS:
|
||||
* render_cache_test_tag
|
||||
* render_cache_test_tag1
|
||||
-->
|
||||
<!-- CACHE CONTEXTS:
|
||||
* languages:language_interface
|
||||
* theme
|
||||
-->
|
||||
<!-- CACHE KEYS:
|
||||
* render_cache_test_key
|
||||
-->
|
||||
<!-- CACHE MAX-AGE: 10 -->
|
||||
<!-- PRE-BUBBLING CACHE TAGS:
|
||||
* render_cache_test_tag
|
||||
* render_cache_test_tag1
|
||||
-->
|
||||
<!-- PRE-BUBBLING CACHE CONTEXTS:
|
||||
* languages:language_interface
|
||||
* theme
|
||||
-->
|
||||
<!-- PRE-BUBBLING CACHE KEYS:
|
||||
* render_cache_test_key
|
||||
-->
|
||||
<!-- PRE-BUBBLING CACHE MAX-AGE: 10 -->
|
||||
<!-- RENDERING TIME: 0.123456789 -->
|
||||
Test 1
|
||||
<!-- END RENDERER -->
|
||||
EOF;
|
||||
$this->assertSame($expected, preg_replace('/RENDERING TIME: \d{1}.\d{9}/', 'RENDERING TIME: 0.123456789', $markup->__toString()));
|
||||
|
||||
$element = [
|
||||
'#cache' => [
|
||||
'keys' => ['render_cache_test_key'],
|
||||
'tags' => ['render_cache_test_tag', 'render_cache_test_tag1'],
|
||||
'max-age' => 10,
|
||||
],
|
||||
'#markup' => 'Test 1',
|
||||
];
|
||||
$markup = $this->renderer->renderRoot($element);
|
||||
|
||||
$this->assertStringContainsString('CACHE-HIT: Yes', $markup->__toString());
|
||||
}
|
||||
|
||||
}
|
|
@ -109,6 +109,7 @@ abstract class RendererTestBase extends UnitTestCase {
|
|||
'contexts' => ['session', 'user'],
|
||||
'tags' => ['current-temperature'],
|
||||
],
|
||||
'debug' => FALSE,
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
@ -132,6 +132,14 @@ parameters:
|
|||
#
|
||||
# @default []
|
||||
tags: []
|
||||
# Renderer cache debug:
|
||||
#
|
||||
# Allows cache debugging output for each rendered element.
|
||||
#
|
||||
# Enabling render cache debugging is not recommended in production
|
||||
# environments.
|
||||
# @default false
|
||||
debug: false
|
||||
# Cacheability debugging:
|
||||
#
|
||||
# Responses with cacheability metadata (CacheableResponseInterface instances)
|
||||
|
|
Loading…
Reference in New Issue