[BUGFIX] Fix some PHP Notices thrown when rendering page module
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Log / LogManager.php
1 <?php
2 namespace TYPO3\CMS\Core\Log;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 /**
18 * Global LogManager that keeps track of global logging information.
19 *
20 * Inspired by java.util.logging
21 */
22 class LogManager implements \TYPO3\CMS\Core\SingletonInterface, LogManagerInterface
23 {
24 /**
25 * @var string
26 */
27 const CONFIGURATION_TYPE_WRITER = 'writer';
28
29 /**
30 * @var string
31 */
32 const CONFIGURATION_TYPE_PROCESSOR = 'processor';
33
34 /**
35 * Loggers to retrieve them for repeated use.
36 *
37 * @var array
38 */
39 protected $loggers = [];
40
41 /**
42 * Default / global / root logger.
43 *
44 * @var \TYPO3\CMS\Core\Log\Logger
45 */
46 protected $rootLogger = null;
47
48 /**
49 * Constructor
50 */
51 public function __construct()
52 {
53 $this->rootLogger = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(Logger::class, '');
54 $this->loggers[''] = $this->rootLogger;
55 }
56
57 /**
58 * For use in unit test context only. Resets the internal logger registry.
59 */
60 public function reset()
61 {
62 $this->loggers = [];
63 }
64
65 /**
66 * Gets a logger instance for the given name.
67 *
68 * \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Log\LogManager::class)->getLogger('main.sub.subsub');
69 *
70 * $name can also be submitted as a underscore-separated string, which will
71 * be converted to dots. This is useful to call this method with __CLASS__
72 * as parameter.
73 *
74 * @param string $name Logger name, empty to get the global "root" logger.
75 * @return \TYPO3\CMS\Core\Log\Logger Logger with name $name
76 */
77 public function getLogger($name = '')
78 {
79 /** @var $logger \TYPO3\CMS\Core\Log\Logger */
80 $logger = null;
81 // Transform namespaces and underscore class names to the dot-name style
82 $separators = ['_', '\\'];
83 $name = str_replace($separators, '.', $name);
84 if (isset($this->loggers[$name])) {
85 $logger = $this->loggers[$name];
86 } else {
87 // Lazy instantiation
88 /** @var $logger \TYPO3\CMS\Core\Log\Logger */
89 $logger = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(Logger::class, $name);
90 $this->loggers[$name] = $logger;
91 $this->setWritersForLogger($logger);
92 $this->setProcessorsForLogger($logger);
93 }
94 return $logger;
95 }
96
97 /**
98 * For use in unit test context only.
99 *
100 * @param string $name
101 */
102 public function registerLogger($name)
103 {
104 $this->loggers[$name] = null;
105 }
106
107 /**
108 * For use in unit test context only.
109 *
110 * @return array
111 */
112 public function getLoggerNames()
113 {
114 return array_keys($this->loggers);
115 }
116
117 /**
118 * Appends the writers to the given logger as configured.
119 *
120 * @param \TYPO3\CMS\Core\Log\Logger $logger Logger to configure
121 */
122 protected function setWritersForLogger(Logger $logger)
123 {
124 $configuration = $this->getConfigurationForLogger(self::CONFIGURATION_TYPE_WRITER, $logger->getName());
125 foreach ($configuration as $severityLevel => $writer) {
126 foreach ($writer as $logWriterClassName => $logWriterOptions) {
127 /** @var $logWriter \TYPO3\CMS\Core\Log\Writer\WriterInterface */
128 $logWriter = null;
129 try {
130 $logWriter = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($logWriterClassName, $logWriterOptions);
131 $logger->addWriter($severityLevel, $logWriter);
132 } catch (\Psr\Log\InvalidArgumentException $e) {
133 $logger->warning('Instantiation of LogWriter "' . $logWriterClassName . '" failed for logger ' . $logger->getName() . ' (' . $e->getMessage() . ')');
134 } catch (\TYPO3\CMS\Core\Log\Exception\InvalidLogWriterConfigurationException $e) {
135 $logger->warning('Instantiation of LogWriter "' . $logWriterClassName . '" failed for logger ' . $logger->getName() . ' (' . $e->getMessage() . ')');
136 }
137 }
138 }
139 }
140
141 /**
142 * Appends the processors to the given logger as configured.
143 *
144 * @param \TYPO3\CMS\Core\Log\Logger $logger Logger to configure
145 */
146 protected function setProcessorsForLogger(Logger $logger)
147 {
148 $configuration = $this->getConfigurationForLogger(self::CONFIGURATION_TYPE_PROCESSOR, $logger->getName());
149 foreach ($configuration as $severityLevel => $processor) {
150 foreach ($processor as $logProcessorClassName => $logProcessorOptions) {
151 /** @var $logProcessor \TYPO3\CMS\Core\Log\Processor\ProcessorInterface */
152 $logProcessor = null;
153 try {
154 $logProcessor = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($logProcessorClassName, $logProcessorOptions);
155 $logger->addProcessor($severityLevel, $logProcessor);
156 } catch (\Psr\Log\InvalidArgumentException $e) {
157 $logger->warning('Instantiation of LogProcessor "' . $logProcessorClassName . '" failed for logger ' . $logger->getName() . ' (' . $e->getMessage() . ')');
158 } catch (\TYPO3\CMS\Core\Log\Exception\InvalidLogProcessorConfigurationException $e) {
159 $logger->warning('Instantiation of LogProcessor "' . $logProcessorClassName . '" failed for logger ' . $logger->getName() . ' (' . $e->getMessage() . ')');
160 }
161 }
162 }
163 }
164
165 /**
166 * Returns the configuration from $TYPO3_CONF_VARS['LOG'] as
167 * hierarchical array for different components of the class hierarchy.
168 *
169 * @param string $configurationType Type of config to return (writer, processor)
170 * @param string $loggerName Logger name
171 * @throws \Psr\Log\InvalidArgumentException
172 * @return array
173 */
174 protected function getConfigurationForLogger($configurationType, $loggerName)
175 {
176 // Split up the logger name (dot-separated) into its parts
177 $explodedName = explode('.', $loggerName);
178 // Search in the $TYPO3_CONF_VARS['LOG'] array
179 // for these keys, for example "writerConfiguration"
180 $configurationKey = $configurationType . 'Configuration';
181 $configuration = $GLOBALS['TYPO3_CONF_VARS']['LOG'];
182 $result = $configuration[$configurationKey] ?? [];
183 // Walk from general to special (t3lib, t3lib.db, t3lib.db.foo)
184 // and search for the most specific configuration
185 foreach ($explodedName as $partOfClassName) {
186 if (!empty($configuration[$partOfClassName][$configurationKey])) {
187 $result = $configuration[$partOfClassName][$configurationKey];
188 }
189 $configuration = $configuration[$partOfClassName];
190 }
191 // Validate the config
192 foreach ($result as $level => $unused) {
193 try {
194 LogLevel::validateLevel($level);
195 } catch (\Psr\Log\InvalidArgumentException $e) {
196 throw new \Psr\Log\InvalidArgumentException('The given severity level "' . htmlspecialchars($level) . '" for ' . $configurationKey . ' of logger "' . $loggerName . '" is not valid.', 1326406447);
197 }
198 }
199 return $result;
200 }
201 }