764d15a4587dd63292aba4ac1559529ce6006621
[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 * @author Ingo Renner <ingo@typo3.org>
23 * @author Steffen Müller <typo3@t3node.com>
24 * @author Steffen Gebert <steffen.gebert@typo3.org>
25 */
26 class LogManager implements \TYPO3\CMS\Core\SingletonInterface, LogManagerInterface {
27
28 /**
29 * @var string
30 */
31 const CONFIGURATION_TYPE_WRITER = 'writer';
32
33 /**
34 * @var string
35 */
36 const CONFIGURATION_TYPE_PROCESSOR = 'processor';
37
38 /**
39 * Loggers to retrieve them for repeated use.
40 *
41 * @var array
42 */
43 protected $loggers = array();
44
45 /**
46 * Default / global / root logger.
47 *
48 * @var \TYPO3\CMS\Core\Log\Logger
49 */
50 protected $rootLogger = NULL;
51
52 /**
53 * Constructor
54 */
55 public function __construct() {
56 $this->rootLogger = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Log\Logger::class, '');
57 $this->loggers[''] = $this->rootLogger;
58 }
59
60 /**
61 * For use in unit test context only. Resets the internal logger registry.
62 *
63 * @return void
64 */
65 public function reset() {
66 $this->loggers = array();
67 }
68
69 /**
70 * Gets a logger instance for the given name.
71 *
72 * \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Log\LogManager::class)->getLogger('main.sub.subsub');
73 *
74 * $name can also be submitted as a underscore-separated string, which will
75 * be converted to dots. This is useful to call this method with __CLASS__
76 * as parameter.
77 *
78 * @param string $name Logger name, empty to get the global "root" logger.
79 * @return \TYPO3\CMS\Core\Log\Logger Logger with name $name
80 */
81 public function getLogger($name = '') {
82 /** @var $logger \TYPO3\CMS\Core\Log\Logger */
83 $logger = NULL;
84 // Transform namespaces and underscore class names to the dot-name style
85 $separators = array('_', '\\');
86 $name = str_replace($separators, '.', $name);
87 if (isset($this->loggers[$name])) {
88 $logger = $this->loggers[$name];
89 } else {
90 // Lazy instantiation
91 /** @var $logger \TYPO3\CMS\Core\Log\Logger */
92 $logger = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Log\Logger::class, $name);
93 $this->loggers[$name] = $logger;
94 $this->setWritersForLogger($logger);
95 $this->setProcessorsForLogger($logger);
96 }
97 return $logger;
98 }
99
100 /**
101 * For use in unit test context only.
102 *
103 * @param string $name
104 * @return void
105 */
106 public function registerLogger($name) {
107 $this->loggers[$name] = NULL;
108 }
109
110 /**
111 * For use in unit test context only.
112 *
113 * @return array
114 */
115 public function getLoggerNames() {
116 return array_keys($this->loggers);
117 }
118
119 /**
120 * Appends the writers to the given logger as configured.
121 *
122 * @param \TYPO3\CMS\Core\Log\Logger $logger Logger to configure
123 * @return void
124 * @throws \RangeException
125 */
126 protected function setWritersForLogger(Logger $logger) {
127 $configuration = $this->getConfigurationForLogger(self::CONFIGURATION_TYPE_WRITER, $logger->getName());
128 foreach ($configuration as $severityLevel => $writer) {
129 foreach ($writer as $logWriterClassName => $logWriterOptions) {
130 /** @var $logWriter \TYPO3\CMS\Core\Log\Writer\WriterInterface */
131 $logWriter = NULL;
132 try {
133 $logWriter = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($logWriterClassName, $logWriterOptions);
134 $logger->addWriter($severityLevel, $logWriter);
135 } catch (\RangeException $e) {
136 $logger->warning('Instantiation of LogWriter "' . $logWriterClassName . '" failed for logger ' . $logger->getName() . ' (' . $e->getMessage() . ')');
137 }
138 }
139 }
140 }
141
142 /**
143 * Appends the processors to the given logger as configured.
144 *
145 * @param \TYPO3\CMS\Core\Log\Logger $logger Logger to configure
146 * @return void
147 * @throws \RangeException
148 */
149 protected function setProcessorsForLogger(Logger $logger) {
150 $configuration = $this->getConfigurationForLogger(self::CONFIGURATION_TYPE_PROCESSOR, $logger->getName());
151 foreach ($configuration as $severityLevel => $processor) {
152 foreach ($processor as $logProcessorClassName => $logProcessorOptions) {
153 /** @var $logProcessor \TYPO3\CMS\Core\Log\Processor\ProcessorInterface */
154 $logProcessor = NULL;
155 try {
156 $logProcessor = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($logProcessorClassName, $logProcessorOptions);
157 $logger->addProcessor($severityLevel, $logProcessor);
158 } catch (\RangeException $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 \RangeException
172 * @return array
173 */
174 protected function getConfigurationForLogger($configurationType, $loggerName) {
175 // Split up the logger name (dot-separated) into its parts
176 $explodedName = explode('.', $loggerName);
177 // Search in the $TYPO3_CONF_VARS['LOG'] array
178 // for these keys, for example "writerConfiguration"
179 $configurationKey = $configurationType . 'Configuration';
180 $configuration = $GLOBALS['TYPO3_CONF_VARS']['LOG'];
181 $result = $configuration[$configurationKey] ?: array();
182 // Walk from general to special (t3lib, t3lib.db, t3lib.db.foo)
183 // and search for the most specific configuration
184 foreach ($explodedName as $partOfClassName) {
185 if (!empty($configuration[$partOfClassName][$configurationKey])) {
186 $result = $configuration[$partOfClassName][$configurationKey];
187 }
188 $configuration = $configuration[$partOfClassName];
189 }
190 // Validate the config
191 foreach ($result as $level => $unused) {
192 try {
193 LogLevel::validateLevel($level);
194 } catch (\RangeException $e) {
195 throw new \RangeException('The given severity level "' . htmlspecialchars($level) . '" for ' . $configurationKey . ' of logger "' . $loggerName . '" is not valid.', 1326406447);
196 }
197 }
198 return $result;
199 }
200
201 }