first commit

This commit is contained in:
salam committed 2026-10-19 08:18:39 +02:00
commit 1218dd1517
12716 files changed
+989233

No files matched your search

@@ -0,0 +1,208 @@
<?php
declare(strict_types = 1);
namespace TYPO3\CMS\Adminpanel\Modules\Debug;
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Adminpanel\Log\InMemoryLogWriter;
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractSubModule;
use TYPO3\CMS\Adminpanel\ModuleApi\DataProviderInterface;
use TYPO3\CMS\Adminpanel\ModuleApi\InitializableInterface;
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleData;
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleSettingsProviderInterface;
use TYPO3\CMS\Adminpanel\Service\ConfigurationService;
use TYPO3\CMS\Core\Log\LogLevel;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
/**
* Log Sub Module of the AdminPanel
*
* @internal
*/
class Log extends AbstractSubModule implements DataProviderInterface, ModuleSettingsProviderInterface, InitializableInterface
{
protected $logLevel = LogLevel::INFO;
/**
* @var ConfigurationService
*/
protected $configurationService;
public function __construct()
{
$this->configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
}
/**
* @return string
*/
public function getIdentifier(): string
{
return 'debug_log';
}
/**
* Sub-Module label
*
* @return string
*/
public function getLabel(): string
{
return $this->getLanguageService()->sL(
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_debug.xlf:submodule.log.label'
);
}
/**
* @inheritdoc
*/
public function getDataToStore(ServerRequestInterface $request): ModuleData
{
$levels = [];
for ($i = 1; $i <= LogLevel::DEBUG; $i++) {
$levels[] = [
'level' => $i,
'levelName' => LogLevel::getName($i),
];
}
$log = InMemoryLogWriter::$log;
$logArray = [];
/** @var \TYPO3\CMS\Core\Log\LogRecord $logRecord */
foreach ($log as $logRecord) {
$entry = $logRecord->toArray();
// store only necessary info
unset($entry['data']);
$logArray[] = $entry;
}
return new ModuleData(
[
'levels' => $levels,
'startLevel' => (int)$this->getConfigOption('startLevel'),
'log' => $logArray,
]
);
}
/**
* @inheritdoc
*/
public function getSettings(): string
{
$view = GeneralUtility::makeInstance(StandaloneView::class);
$templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/Debug/LogSettings.html';
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
$view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
$levels = [];
for ($i = 1; $i <= LogLevel::DEBUG; $i++) {
$levels[] = [
'level' => $i,
'levelName' => LogLevel::getName($i),
];
}
$view->assignMultiple(
[
'levels' => $levels,
'startLevel' => (int)$this->getConfigOption('startLevel'),
'groupByComponent' => $this->getConfigOption('groupByComponent'),
'groupByLevel' => $this->getConfigOption('groupByLevel'),
]
);
return $view->render();
}
/**
* Sub-Module content as rendered HTML
*
* @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleData $data
* @return string
*/
public function getContent(ModuleData $data): string
{
$this->logLevel = $this->getConfigOption('startLevel');
$view = GeneralUtility::makeInstance(StandaloneView::class);
$templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/Debug/Log.html';
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
$view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
$sortedLog = [];
// settings for this module
$groupByComponent = $this->getConfigOption('groupByComponent');
$groupByLevel = $this->getConfigOption('groupByLevel');
foreach ($data['log'] as $logRecord) {
if ($logRecord['level'] > $this->logLevel) {
continue;
}
if ($groupByComponent && $groupByLevel) {
$sortedLog[$logRecord['component']][LogLevel::getName($logRecord['level'])][] = $logRecord;
} elseif ($groupByComponent) {
$sortedLog[$logRecord['component']][] = $logRecord;
} elseif ($groupByLevel) {
$sortedLog[$logRecord['level']][] = $logRecord;
} else {
$sortedLog[] = $logRecord;
}
}
$data['log'] = $sortedLog;
$data['groupByComponent'] = $groupByComponent;
$data['groupByLevel'] = $groupByLevel;
$view->assignMultiple($data->getArrayCopy());
return $view->render();
}
/**
* @inheritdoc
*/
public function initializeModule(ServerRequestInterface $request): void
{
$this->logLevel = $this->getConfigOption('startLevel');
// set inMemoryLogWriter recursively for all configured namespaces/areas so we don't lose log entries
$configWithInMemoryWriter = $this->setLoggingConfigRecursive($GLOBALS['TYPO3_CONF_VARS']['LOG'] ?? []);
// in case there are empty array parts, remove them
$GLOBALS['TYPO3_CONF_VARS']['LOG'] = array_filter(
$configWithInMemoryWriter
);
}
protected function setLoggingConfigRecursive(array $logConfig): array
{
foreach ($logConfig as $key => $value) {
if ($key === 'writerConfiguration') {
$logConfig[$key] = $value;
$logConfig[$key][LogLevel::DEBUG][InMemoryLogWriter::class] = [];
} elseif (is_array($value)) {
$logConfig[$key] = $this->setLoggingConfigRecursive($value);
}
}
return $logConfig;
}
/**
* @param string $option
* @return string
*/
protected function getConfigOption(string $option): string
{
return $this->configurationService->getConfigurationOption('debug_log', $option);
}
}
@@ -0,0 +1,131 @@
<?php
declare(strict_types = 1);
namespace TYPO3\CMS\Adminpanel\Modules\Debug;
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Adminpanel\Log\DoctrineSqlLogger;
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractSubModule;
use TYPO3\CMS\Adminpanel\ModuleApi\DataProviderInterface;
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleData;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
/**
* Admin Panel Query Information module for showing SQL Queries
*
* @internal
*/
class QueryInformation extends AbstractSubModule implements DataProviderInterface
{
/**
* Identifier for this Sub-module,
* for example "preview" or "cache"
*
* @return string
*/
public function getIdentifier(): string
{
return 'debug_queryinformation';
}
/**
* Sub-Module label
*
* @return string
*/
public function getLabel(): string
{
return $this->getLanguageService()->sL(
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_debug.xlf:submodule.queryInformation.label'
);
}
/**
* @param ServerRequestInterface $request
* @return \TYPO3\CMS\Adminpanel\ModuleApi\ModuleData
* @throws \Doctrine\DBAL\DBALException
*/
public function getDataToStore(ServerRequestInterface $request): ModuleData
{
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
$connection = $connectionPool->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
$logger = $connection->getConfiguration()->getSQLLogger();
$data = [];
if ($logger instanceof DoctrineSqlLogger) {
$queries = $logger->getQueries();
$data['queries'] = $this->groupQueries($queries) ?? [];
$data['totalTime'] = array_sum(array_column($queries, 'executionMS')) * 1000;
}
return new ModuleData($data);
}
/**
* @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleData $data
* @return string Returns content of admin panel
*/
public function getContent(ModuleData $data): string
{
$view = new StandaloneView();
$view->setTemplatePathAndFilename(
'EXT:adminpanel/Resources/Private/Templates/Modules/Debug/QueryInformation.html'
);
$this->getLanguageService()->includeLLFile('EXT:adminpanel/Resources/Private/Language/locallang_debug.xlf');
$view->assignMultiple($data->getArrayCopy());
return $view->render();
}
/**
* @param array $queries
* @return array
*/
protected function groupQueries(array $queries): array
{
$groupedQueries = [];
foreach ($queries as $query) {
$identifier = sha1($query['sql']) . sha1(json_encode($query['backtrace']));
if (is_array($query['params'])) {
foreach ($query['params'] as $k => $param) {
if (is_array($param)) {
$query['params'][$k] = implode(',', $param);
}
}
}
if (isset($groupedQueries[$identifier])) {
$groupedQueries[$identifier]['count']++;
$groupedQueries[$identifier]['time'] += ($query['executionMS'] * 1000);
$groupedQueries[$identifier]['queries'][] = $query;
} else {
$groupedQueries[$identifier] = [
'sql' => $query['sql'],
'time' => $query['executionMS'] * 1000,
'count' => 1,
'queries' => [
$query,
],
];
}
}
uasort(
$groupedQueries,
function ($a, $b) {
return $b['time'] <=> $a['time'];
}
);
return $groupedQueries;
}
}