diff --git a/Classes/Aspect/CollectDebugInformationAspect.php b/Classes/Aspect/CollectDebugInformationAspect.php index 022f009..793a2d1 100644 --- a/Classes/Aspect/CollectDebugInformationAspect.php +++ b/Classes/Aspect/CollectDebugInformationAspect.php @@ -27,7 +27,7 @@ use Neos\Flow\Aop\JoinPointInterface; use Neos\Flow\ResourceManagement\PersistentResource; use Neos\Media\Domain\Model\AssetInterface; -use Neos\Utility\ObjectAccess; +use Psr\Http\Message\StreamInterface; #[Flow\Scope('singleton')] #[Flow\Aspect] @@ -73,18 +73,18 @@ public function debuggingActive(): void } #[Flow\Around("method(Neos\Neos\View\FusionView->render()) && Flowpack\Neos\Debug\Aspect\CollectDebugInformationAspect->debuggingActive")] - public function addDebugValuesToNeosFusionView(JoinPointInterface $joinPoint): string|Response + public function addDebugValuesToNeosFusionView(JoinPointInterface $joinPoint): string|Response|StreamInterface { return $this->addDebugValues($joinPoint); } #[Flow\Around("method(Neos\Fusion\View\FusionView->render()) && Flowpack\Neos\Debug\Aspect\CollectDebugInformationAspect->debuggingActive")] - public function addDebugValuesToDefaultFusionView(JoinPointInterface $joinPoint): string|Response + public function addDebugValuesToDefaultFusionView(JoinPointInterface $joinPoint): string|Response|StreamInterface { return $this->addDebugValues($joinPoint); } - protected function addDebugValues(JoinPointInterface $joinPoint): string|Response + protected function addDebugValues(JoinPointInterface $joinPoint): string|Response|StreamInterface { $startRenderAt = microtime(true) * 1000; $response = $joinPoint->getAdviceChain()->proceed($joinPoint); @@ -114,7 +114,10 @@ protected function addDebugValues(JoinPointInterface $joinPoint): string|Respons if ($response->getHeader('Content-Type') !== 'text/html' && !str_contains($output, '')) { return $response; } + } elseif ($response instanceof StreamInterface) { + $output = $response->getContents(); } else { + // legacy 8.3 $output = $response; } @@ -157,8 +160,12 @@ protected function addDebugValues(JoinPointInterface $joinPoint): string|Respons if ($response instanceof Response) { return $response->withBody(Utils::streamFor($output)); + } elseif ($response instanceof StreamInterface) { + return Utils::streamFor($output); + } else { + // legacy 8.3 + return $output; } - return $output; } #[Flow\Before("method(Neos\Flow\Mvc\Routing\Router->route()) && Flowpack\Neos\Debug\Aspect\CollectDebugInformationAspect->debuggingActive")] diff --git a/Classes/Aspect/ContentCacheSegmentAspect.php b/Classes/Aspect/ContentCacheSegmentAspect.php index 4d46557..167188f 100644 --- a/Classes/Aspect/ContentCacheSegmentAspect.php +++ b/Classes/Aspect/ContentCacheSegmentAspect.php @@ -96,7 +96,11 @@ public function wrapUncachedSegment(JoinPointInterface $joinPoint): string return $this->renderCacheInfoIntoSegment($segment, [ 'mode' => static::MODE_UNCACHED, 'fusionPath' => $joinPoint->getMethodArgument('fusionPath'), - 'contextVariables' => array_keys($joinPoint->getMethodArgument('contextVariables')), + 'contextVariables' => array_keys($joinPoint->isMethodArgument('serializedContext') + ? $joinPoint->getMethodArgument('serializedContext') + // legacy 8.3 + : $joinPoint->getMethodArgument('contextVariables') + ), ]); } @@ -111,7 +115,11 @@ public function wrapDynamicSegment(JoinPointInterface $joinPoint): string 'entryIdentifier' => $this->interceptedCacheEntryValues, 'entryTags' => $joinPoint->getMethodArgument('tags'), 'lifetime' => $joinPoint->getMethodArgument('lifetime'), - 'contextVariables' => array_keys($joinPoint->getMethodArgument('contextVariables')), + 'contextVariables' => array_keys($joinPoint->isMethodArgument('serializedContext') + ? $joinPoint->getMethodArgument('serializedContext') + // legacy 8.3 + : $joinPoint->getMethodArgument('contextVariables') + ), 'entryDiscriminator' => $joinPoint->getMethodArgument('cacheDiscriminator'), ]); } diff --git a/Classes/DataCollector/ContentContextMetricsCollectorFactory.php b/Classes/DataCollector/ContentContextMetricsCollectorFactory.php index c3fc046..50c7f23 100644 --- a/Classes/DataCollector/ContentContextMetricsCollectorFactory.php +++ b/Classes/DataCollector/ContentContextMetricsCollectorFactory.php @@ -27,7 +27,8 @@ public function build(): ?ContentContextMetricsCollectorInterface ); } else { return new ContentContextMetricsCollectorNeos9( - $this->dataFormatter + $this->dataFormatter, + $this->objectManager->get(\Neos\ContentRepositoryRegistry\SubgraphCachingInMemory\SubgraphCachePool::class) ); } } diff --git a/Classes/DataCollector/ContentContextMetricsCollectorNeos9.php b/Classes/DataCollector/ContentContextMetricsCollectorNeos9.php index d78fdc4..6dcbbd0 100644 --- a/Classes/DataCollector/ContentContextMetricsCollectorNeos9.php +++ b/Classes/DataCollector/ContentContextMetricsCollectorNeos9.php @@ -4,13 +4,29 @@ namespace Flowpack\Neos\Debug\DataCollector; -use Flowpack\Neos\Debug\Domain\Model\Dto\CacheMonitorMetrics; -use Neos\Flow\Annotations as Flow; +use Flowpack\Neos\Debug\DataFormatter\DataFormatterInterface; +use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface; +use Neos\ContentRepositoryRegistry\SubgraphCachingInMemory\InMemoryCache\AllChildNodesByNodeIdCache; +use Neos\ContentRepositoryRegistry\SubgraphCachingInMemory\InMemoryCache\NamedChildNodeByNodeIdCache; +use Neos\ContentRepositoryRegistry\SubgraphCachingInMemory\InMemoryCache\NodeByNodeAggregateIdCache; +use Neos\ContentRepositoryRegistry\SubgraphCachingInMemory\InMemoryCache\NodePathCache; +use Neos\ContentRepositoryRegistry\SubgraphCachingInMemory\InMemoryCache\ParentNodeIdByChildNodeIdCache; +use Neos\ContentRepositoryRegistry\SubgraphCachingInMemory\SubgraphCachePool; +use Neos\Utility\ObjectAccess; class ContentContextMetricsCollectorNeos9 extends AbstractDataCollector implements ContentContextMetricsCollectorInterface { + public function __construct( + ?DataFormatterInterface $dataFormatter, + protected SubgraphCachePool $subgraphCachePool, + ) + { + parent::__construct($dataFormatter); + } + public function getName(): string { + // todo rename to subgraph metrics, but make js work with that return 'contentContextMetrics'; } @@ -19,6 +35,46 @@ public function getName(): string */ public function collect(): array { - return []; + /** @var array $subgraphsById */ + $subgraphsById = ObjectAccess::getProperty($this->subgraphCachePool, 'subgraphInstancesCache', true); + + /** @var array $nodePathCaches */ + $nodePathCaches = ObjectAccess::getProperty($this->subgraphCachePool, 'nodePathCaches', true); + /** @var array $nodeByNodeAggregateIdCaches */ + $nodeByNodeAggregateIdCaches = ObjectAccess::getProperty($this->subgraphCachePool, 'nodeByNodeAggregateIdCaches', true); + /** @var array $nodeByNodeAggregateIdCaches */ + $allChildNodesByNodeIdCaches = ObjectAccess::getProperty($this->subgraphCachePool, 'allChildNodesByNodeIdCaches', true); + /** @var array $nodeByNodeAggregateIdCaches */ + $namedChildNodeByNodeIdCaches = ObjectAccess::getProperty($this->subgraphCachePool, 'namedChildNodeByNodeIdCaches', true); + /** @var array $nodeByNodeAggregateIdCaches */ + $parentNodeIdByChildNodeIdCaches = ObjectAccess::getProperty($this->subgraphCachePool, 'parentNodeIdByChildNodeIdCaches', true); + + $subgraphMetrics = []; + foreach ($subgraphsById as $subgraphId => $subgraph) { + /** @var NodePathCache|null $nodePathCache */ + $nodePathCache = $nodePathCaches[$subgraphId] ?? null; + /** @var NodeByNodeAggregateIdCache|null $nodeByNodeAggregateIdCache */ + $nodeByNodeAggregateIdCache = $nodeByNodeAggregateIdCaches[$subgraphId] ?? null; + /** @var AllChildNodesByNodeIdCache|null $nodeByNodeAggregateIdCache */ + $allChildNodesByNodeIdCache = $allChildNodesByNodeIdCaches[$subgraphId] ?? null; + /** @var NamedChildNodeByNodeIdCache|null $nodeByNodeAggregateIdCache */ + $namedChildNodeByNodeIdCache = $namedChildNodeByNodeIdCaches[$subgraphId] ?? null; + /** @var ParentNodeIdByChildNodeIdCache|null $nodeByNodeAggregateIdCache */ + $parentNodeIdByChildNodeIdCache = $parentNodeIdByChildNodeIdCaches[$subgraphId] ?? null; + + $subgraphMetrics[$subgraphId] = [ + 'workspace' => $subgraph->getWorkspaceName(), + 'dimensionSpacePoint' => $subgraph->getDimensionSpacePoint(), + 'visibilityConstraints' => $subgraph->getVisibilityConstraints(), + 'nodeCaches' => [ + ...($nodePathCache ? ['nodePath' => count(ObjectAccess::getProperty($nodePathCache, 'nodePaths', true))] : []), + ...($nodeByNodeAggregateIdCache ? ['nodeByNodeAggregateId' => count(ObjectAccess::getProperty($nodeByNodeAggregateIdCache, 'nodes', true)) + count(ObjectAccess::getProperty($nodeByNodeAggregateIdCache, 'nonExistingNodeAggregateIds', true))] : []), + ...($allChildNodesByNodeIdCache ? ['allChildNodesByNodeId' => count(ObjectAccess::getProperty($allChildNodesByNodeIdCache, 'childNodes', true))] : []), + ...($namedChildNodeByNodeIdCache ? ['namedChildNodeByNodeId' => count(ObjectAccess::getProperty($namedChildNodeByNodeIdCache, 'nodes', true))] : []), + ...($parentNodeIdByChildNodeIdCache ? ['parentNodeIdByChildNodeId' => count(ObjectAccess::getProperty($parentNodeIdByChildNodeIdCache, 'parentNodeAggregateIds', true)) + count(ObjectAccess::getProperty($parentNodeIdByChildNodeIdCache, 'nodesWithoutParentNode', true))] : []), + ], + ]; + } + return $subgraphMetrics; } }