|
1 <?php |
|
2 /** |
|
3 * Licensed to the Apache Software Foundation (ASF) under one or more |
|
4 * contributor license agreements. See the NOTICE file distributed with |
|
5 * this work for additional information regarding copyright ownership. |
|
6 * The ASF licenses this file to You under the Apache License, Version 2.0 |
|
7 * (the "License"); you may not use this file except in compliance with |
|
8 * the License. You may obtain a copy of the License at |
|
9 * |
|
10 * http://www.apache.org/licenses/LICENSE-2.0 |
|
11 * |
|
12 * Unless required by applicable law or agreed to in writing, software |
|
13 * distributed under the License is distributed on an "AS IS" BASIS, |
|
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
15 * See the License for the specific language governing permissions and |
|
16 * limitations under the License. |
|
17 * |
|
18 * @package log4php |
|
19 */ |
|
20 |
|
21 /** |
|
22 * This class is specialized in retrieving loggers by name and also maintaining |
|
23 * the logger hierarchy. The logger hierarchy is dealing with the several Log-Levels |
|
24 * Logger can have. From log4j website: |
|
25 * |
|
26 * "A logger is said to be an ancestor of another logger if its name followed |
|
27 * by a dot is a prefix of the descendant logger name. A logger is said to be |
|
28 * a parent of a child logger if there are no ancestors between itself and the |
|
29 * descendant logger." |
|
30 * |
|
31 * Child Loggers do inherit their Log-Levels from their Ancestors. They can |
|
32 * increase their Log-Level compared to their Ancestors, but they cannot decrease it. |
|
33 * |
|
34 * <p>The casual user does not have to deal with this class directly.</p> |
|
35 * |
|
36 * <p>The structure of the logger hierarchy is maintained by the |
|
37 * getLogger method. The hierarchy is such that children link |
|
38 * to their parent but parents do not have any pointers to their |
|
39 * children. Moreover, loggers can be instantiated in any order, in |
|
40 * particular descendant before ancestor.</p> |
|
41 * |
|
42 * <p>In case a descendant is created before a particular ancestor, |
|
43 * then it creates a provision node for the ancestor and adds itself |
|
44 * to the provision node. Other descendants of the same ancestor add |
|
45 * themselves to the previously created provision node.</p> |
|
46 * |
|
47 * @version $Revision: 1394956 $ |
|
48 * @package log4php |
|
49 */ |
|
50 class LoggerHierarchy { |
|
51 |
|
52 /** Array holding all Logger instances. */ |
|
53 protected $loggers = array(); |
|
54 |
|
55 /** |
|
56 * The root logger. |
|
57 * @var RootLogger |
|
58 */ |
|
59 protected $root; |
|
60 |
|
61 /** |
|
62 * The logger renderer map. |
|
63 * @var LoggerRendererMap |
|
64 */ |
|
65 protected $rendererMap; |
|
66 |
|
67 /** |
|
68 * Main level threshold. Events with lower level will not be logged by any |
|
69 * logger, regardless of it's configuration. |
|
70 * @var LoggerLevel |
|
71 */ |
|
72 protected $threshold; |
|
73 |
|
74 /** |
|
75 * Creates a new logger hierarchy. |
|
76 * @param LoggerRoot $root The root logger. |
|
77 */ |
|
78 public function __construct(LoggerRoot $root) { |
|
79 $this->root = $root; |
|
80 $this->setThreshold(LoggerLevel::getLevelAll()); |
|
81 $this->rendererMap = new LoggerRendererMap(); |
|
82 } |
|
83 |
|
84 /** |
|
85 * Clears all loggers. |
|
86 */ |
|
87 public function clear() { |
|
88 $this->loggers = array(); |
|
89 } |
|
90 |
|
91 /** |
|
92 * Check if the named logger exists in the hierarchy. |
|
93 * @param string $name |
|
94 * @return boolean |
|
95 */ |
|
96 public function exists($name) { |
|
97 return isset($this->loggers[$name]); |
|
98 } |
|
99 |
|
100 /** |
|
101 * Returns all the currently defined loggers in this hierarchy as an array. |
|
102 * @return array |
|
103 */ |
|
104 public function getCurrentLoggers() { |
|
105 return array_values($this->loggers); |
|
106 } |
|
107 |
|
108 /** |
|
109 * Returns a named logger instance logger. If it doesn't exist, one is created. |
|
110 * |
|
111 * @param string $name Logger name |
|
112 * @return Logger Logger instance. |
|
113 */ |
|
114 public function getLogger($name) { |
|
115 if (!isset($this->loggers[$name])) { |
|
116 $logger = new Logger($name); |
|
117 |
|
118 $nodes = explode('.', $name); |
|
119 $firstNode = array_shift($nodes); |
|
120 |
|
121 // if name is not a first node but another first node is their |
|
122 if ($firstNode != $name and isset($this->loggers[$firstNode])) { |
|
123 $logger->setParent($this->loggers[$firstNode]); |
|
124 } else { |
|
125 // if there is no father, set root logger as father |
|
126 $logger->setParent($this->root); |
|
127 } |
|
128 |
|
129 // if there are more nodes than one |
|
130 if (count($nodes) > 0) { |
|
131 // find parent node |
|
132 foreach ($nodes as $node) { |
|
133 $parentNode = "$firstNode.$node"; |
|
134 if (isset($this->loggers[$parentNode]) and $parentNode != $name) { |
|
135 $logger->setParent($this->loggers[$parentNode]); |
|
136 } |
|
137 $firstNode .= ".$node"; |
|
138 } |
|
139 } |
|
140 |
|
141 $this->loggers[$name] = $logger; |
|
142 } |
|
143 |
|
144 return $this->loggers[$name]; |
|
145 } |
|
146 |
|
147 /** |
|
148 * Returns the logger renderer map. |
|
149 * @return LoggerRendererMap |
|
150 */ |
|
151 public function getRendererMap() { |
|
152 return $this->rendererMap; |
|
153 } |
|
154 |
|
155 /** |
|
156 * Returns the root logger. |
|
157 * @return LoggerRoot |
|
158 */ |
|
159 public function getRootLogger() { |
|
160 return $this->root; |
|
161 } |
|
162 |
|
163 /** |
|
164 * Returns the main threshold level. |
|
165 * @return LoggerLevel |
|
166 */ |
|
167 public function getThreshold() { |
|
168 return $this->threshold; |
|
169 } |
|
170 |
|
171 /** |
|
172 * Returns true if the hierarchy is disabled for given log level and false |
|
173 * otherwise. |
|
174 * @return boolean |
|
175 */ |
|
176 public function isDisabled(LoggerLevel $level) { |
|
177 return ($this->threshold->toInt() > $level->toInt()); |
|
178 } |
|
179 |
|
180 /** |
|
181 * Reset all values contained in this hierarchy instance to their |
|
182 * default. |
|
183 * |
|
184 * This removes all appenders from all loggers, sets |
|
185 * the level of all non-root loggers to <i>null</i>, |
|
186 * sets their additivity flag to <i>true</i> and sets the level |
|
187 * of the root logger to {@link LOGGER_LEVEL_DEBUG}. |
|
188 * |
|
189 * <p>Existing loggers are not removed. They are just reset. |
|
190 * |
|
191 * <p>This method should be used sparingly and with care as it will |
|
192 * block all logging until it is completed.</p> |
|
193 */ |
|
194 public function resetConfiguration() { |
|
195 $root = $this->getRootLogger(); |
|
196 |
|
197 $root->setLevel(LoggerLevel::getLevelDebug()); |
|
198 $this->setThreshold(LoggerLevel::getLevelAll()); |
|
199 $this->shutDown(); |
|
200 |
|
201 foreach ($this->loggers as $logger) { |
|
202 $logger->setLevel(null); |
|
203 $logger->setAdditivity(true); |
|
204 $logger->removeAllAppenders(); |
|
205 } |
|
206 |
|
207 $this->rendererMap->reset(); |
|
208 LoggerAppenderPool::clear(); |
|
209 } |
|
210 |
|
211 /** |
|
212 * Sets the main threshold level. |
|
213 * @param LoggerLevel $l |
|
214 */ |
|
215 public function setThreshold(LoggerLevel $threshold) { |
|
216 $this->threshold = $threshold; |
|
217 } |
|
218 |
|
219 /** |
|
220 * Shutting down a hierarchy will <i>safely</i> close and remove |
|
221 * all appenders in all loggers including the root logger. |
|
222 * |
|
223 * The shutdown method is careful to close nested |
|
224 * appenders before closing regular appenders. This is allows |
|
225 * configurations where a regular appender is attached to a logger |
|
226 * and again to a nested appender. |
|
227 * |
|
228 * @todo Check if the last paragraph is correct. |
|
229 */ |
|
230 public function shutdown() { |
|
231 $this->root->removeAllAppenders(); |
|
232 |
|
233 foreach ($this->loggers as $logger) { |
|
234 $logger->removeAllAppenders(); |
|
235 } |
|
236 } |
|
237 |
|
238 /** |
|
239 * Prints the current Logger hierarchy tree. Useful for debugging. |
|
240 */ |
|
241 public function printHierarchy() { |
|
242 $this->printHierarchyInner($this->getRootLogger(), 0); |
|
243 } |
|
244 |
|
245 private function printHierarchyInner(Logger $current, $level) { |
|
246 for ($i = 0; $i < $level; $i++) { |
|
247 echo ($i == $level - 1) ? "|--" : "| "; |
|
248 } |
|
249 echo $current->getName() . "\n"; |
|
250 |
|
251 foreach ($this->loggers as $logger) { |
|
252 if ($logger->getParent() == $current) { |
|
253 $this->printHierarchyInner($logger, $level + 1); |
|
254 } |
|
255 } |
|
256 } |
|
257 } |