99acb239e2002b3a134ab1676e4849c2041bf3a7
[Packages/TYPO3.CMS.git] / typo3 / sysext / adminpanel / Classes / Modules / Debug / Log.php
1 <?php
2 declare(strict_types = 1);
3
4 namespace TYPO3\CMS\Adminpanel\Modules\Debug;
5
6 /*
7 * This file is part of the TYPO3 CMS project.
8 *
9 * It is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License, either version 2
11 * of the License, or any later version.
12 *
13 * For the full copyright and license information, please read the
14 * LICENSE.txt file that was distributed with this source code.
15 *
16 * The TYPO3 project - inspiring people to share!
17 */
18
19 use Psr\Http\Message\ServerRequestInterface;
20 use TYPO3\CMS\Adminpanel\Log\InMemoryLogWriter;
21 use TYPO3\CMS\Adminpanel\ModuleApi\AbstractSubModule;
22 use TYPO3\CMS\Adminpanel\ModuleApi\ContentProviderInterface;
23 use TYPO3\CMS\Adminpanel\ModuleApi\DataProviderInterface;
24 use TYPO3\CMS\Adminpanel\ModuleApi\InitializableInterface;
25 use TYPO3\CMS\Adminpanel\ModuleApi\ModuleData;
26 use TYPO3\CMS\Adminpanel\ModuleApi\ModuleSettingsProviderInterface;
27 use TYPO3\CMS\Adminpanel\Service\ConfigurationService;
28 use TYPO3\CMS\Core\Log\LogLevel;
29 use TYPO3\CMS\Core\Utility\GeneralUtility;
30 use TYPO3\CMS\Fluid\View\StandaloneView;
31
32 /**
33 * Log Sub Module of the AdminPanel
34 *
35 * @internal
36 */
37 class Log extends AbstractSubModule implements DataProviderInterface, ContentProviderInterface, ModuleSettingsProviderInterface, InitializableInterface
38 {
39 protected $logLevel = LogLevel::INFO;
40
41 /**
42 * @var ConfigurationService
43 */
44 protected $configurationService;
45
46 public function __construct()
47 {
48 $this->configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
49 }
50
51 /**
52 * @return string
53 */
54 public function getIdentifier(): string
55 {
56 return 'debug_log';
57 }
58
59 /**
60 * Sub-Module label
61 *
62 * @return string
63 */
64 public function getLabel(): string
65 {
66 return $this->getLanguageService()->sL(
67 'LLL:EXT:adminpanel/Resources/Private/Language/locallang_debug.xlf:submodule.log.label'
68 );
69 }
70
71 /**
72 * @inheritdoc
73 */
74 public function getDataToStore(ServerRequestInterface $request): ModuleData
75 {
76 $levels = [];
77 for ($i = 1; $i <= LogLevel::DEBUG; $i++) {
78 $levels[] = [
79 'level' => $i,
80 'levelName' => LogLevel::getName($i),
81 ];
82 }
83
84 $log = InMemoryLogWriter::$log;
85
86 $logArray = [];
87 /** @var \TYPO3\CMS\Core\Log\LogRecord $logRecord */
88 foreach ($log as $logRecord) {
89 $entry = $logRecord->toArray();
90 // store only necessary info
91 unset($entry['data']);
92 $logArray[] = $entry;
93 }
94 return new ModuleData(
95 [
96 'levels' => $levels,
97 'startLevel' => (int)$this->getConfigOption('startLevel'),
98 'log' => $logArray,
99 ]
100 );
101 }
102
103 /**
104 * @inheritdoc
105 */
106 public function getSettings(): string
107 {
108 $view = GeneralUtility::makeInstance(StandaloneView::class);
109 $templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/Debug/LogSettings.html';
110 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
111 $view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
112
113 $levels = [];
114 for ($i = 1; $i <= LogLevel::DEBUG; $i++) {
115 $levels[] = [
116 'level' => $i,
117 'levelName' => LogLevel::getName($i),
118 ];
119 }
120 $view->assignMultiple(
121 [
122 'levels' => $levels,
123 'startLevel' => (int)$this->getConfigOption('startLevel'),
124 'groupByComponent' => $this->getConfigOption('groupByComponent'),
125 'groupByLevel' => $this->getConfigOption('groupByLevel'),
126 ]
127 );
128
129 return $view->render();
130 }
131
132 /**
133 * Sub-Module content as rendered HTML
134 *
135 * @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleData $data
136 * @return string
137 */
138 public function getContent(ModuleData $data): string
139 {
140 $this->logLevel = $this->getConfigOption('startLevel');
141 $view = GeneralUtility::makeInstance(StandaloneView::class);
142 $templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/Debug/Log.html';
143 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
144 $view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
145 $sortedLog = [];
146 // settings for this module
147 $groupByComponent = $this->getConfigOption('groupByComponent');
148 $groupByLevel = $this->getConfigOption('groupByLevel');
149
150 foreach ($data['log'] as $logRecord) {
151 if ($logRecord['level'] > $this->logLevel) {
152 continue;
153 }
154 if ($groupByComponent && $groupByLevel) {
155 $sortedLog[$logRecord['component']][LogLevel::getName($logRecord['level'])][] = $logRecord;
156 } elseif ($groupByComponent) {
157 $sortedLog[$logRecord['component']][] = $logRecord;
158 } elseif ($groupByLevel) {
159 $sortedLog[$logRecord['level']][] = $logRecord;
160 } else {
161 $sortedLog[] = $logRecord;
162 }
163 }
164 $data['log'] = $sortedLog;
165 $data['groupByComponent'] = $groupByComponent;
166 $data['groupByLevel'] = $groupByLevel;
167 $view->assignMultiple($data->getArrayCopy());
168
169 return $view->render();
170 }
171
172 /**
173 * @inheritdoc
174 */
175 public function initializeModule(ServerRequestInterface $request): void
176 {
177 $this->logLevel = $this->getConfigOption('startLevel');
178
179 // set inMemoryLogWriter recursively for all configured namespaces/areas so we don't lose log entries
180 $configWithInMemoryWriter = $this->setLoggingConfigRecursive($GLOBALS['TYPO3_CONF_VARS']['LOG'] ?? []);
181
182 // in case there are empty array parts, remove them
183 $GLOBALS['TYPO3_CONF_VARS']['LOG'] = array_filter(
184 $configWithInMemoryWriter
185 );
186 }
187
188 protected function setLoggingConfigRecursive(array $logConfig): array
189 {
190 foreach ($logConfig as $key => $value) {
191 if ($key === 'writerConfiguration') {
192 $logConfig[$key] = $value;
193 $logConfig[$key][LogLevel::DEBUG][InMemoryLogWriter::class] = [];
194 } elseif (is_array($value)) {
195 $logConfig[$key] = $this->setLoggingConfigRecursive($value);
196 }
197 }
198 return $logConfig;
199 }
200
201 /**
202 * @param string $option
203 * @return string
204 */
205 protected function getConfigOption(string $option): string
206 {
207 return $this->configurationService->getConfigurationOption('debug_log', $option);
208 }
209 }