|
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 * Converts ini configuration files to a PHP array. |
|
23 * |
|
24 * These used to be called "properties" files (inherited from log4j), and that |
|
25 * file extension is still supported. |
|
26 * |
|
27 * @package log4php |
|
28 * @subpackage configurators |
|
29 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 |
|
30 * @version $Revision: 1343601 $ |
|
31 * @since 2.2 |
|
32 */ |
|
33 class LoggerConfigurationAdapterINI implements LoggerConfigurationAdapter { |
|
34 |
|
35 /** Name to assign to the root logger. */ |
|
36 const ROOT_LOGGER_NAME = "root"; |
|
37 |
|
38 /** Prefix used for defining logger additivity. */ |
|
39 const ADDITIVITY_PREFIX = "log4php.additivity."; |
|
40 |
|
41 /** Prefix used for defining logger threshold. */ |
|
42 const THRESHOLD_PREFIX = "log4php.threshold"; |
|
43 |
|
44 /** Prefix used for defining the root logger. */ |
|
45 const ROOT_LOGGER_PREFIX = "log4php.rootLogger"; |
|
46 |
|
47 /** Prefix used for defining a logger. */ |
|
48 const LOGGER_PREFIX = "log4php.logger."; |
|
49 |
|
50 /** Prefix used for defining an appender. */ |
|
51 const APPENDER_PREFIX = "log4php.appender."; |
|
52 |
|
53 /** Prefix used for defining a renderer. */ |
|
54 const RENDERER_PREFIX = "log4php.renderer."; |
|
55 |
|
56 /** Holds the configuration. */ |
|
57 private $config = array(); |
|
58 |
|
59 /** |
|
60 * Loads and parses the INI configuration file. |
|
61 * |
|
62 * @param string $url Path to the config file. |
|
63 * @throws LoggerException |
|
64 */ |
|
65 private function load($url) { |
|
66 if (!file_exists($url)) { |
|
67 throw new LoggerException("File [$url] does not exist."); |
|
68 } |
|
69 |
|
70 $properties = @parse_ini_file($url, true); |
|
71 if ($properties === false) { |
|
72 $error = error_get_last(); |
|
73 throw new LoggerException("Error parsing configuration file: {$error['message']}"); |
|
74 } |
|
75 |
|
76 return $properties; |
|
77 } |
|
78 |
|
79 /** |
|
80 * Converts the provided INI configuration file to a PHP array config. |
|
81 * |
|
82 * @param string $path Path to the config file. |
|
83 * @throws LoggerException If the file cannot be loaded or parsed. |
|
84 */ |
|
85 public function convert($path) { |
|
86 // Load the configuration |
|
87 $properties = $this->load($path); |
|
88 |
|
89 // Parse threshold |
|
90 if (isset($properties[self::THRESHOLD_PREFIX])) { |
|
91 $this->config['threshold'] = $properties[self::THRESHOLD_PREFIX]; |
|
92 } |
|
93 |
|
94 // Parse root logger |
|
95 if (isset($properties[self::ROOT_LOGGER_PREFIX])) { |
|
96 $this->parseLogger($properties[self::ROOT_LOGGER_PREFIX], self::ROOT_LOGGER_NAME); |
|
97 } |
|
98 |
|
99 $appenders = array(); |
|
100 |
|
101 foreach ($properties as $key => $value) { |
|
102 // Parse loggers |
|
103 if ($this->beginsWith($key, self::LOGGER_PREFIX)) { |
|
104 $name = substr($key, strlen(self::LOGGER_PREFIX)); |
|
105 $this->parseLogger($value, $name); |
|
106 } |
|
107 |
|
108 // Parse additivity |
|
109 if ($this->beginsWith($key, self::ADDITIVITY_PREFIX)) { |
|
110 $name = substr($key, strlen(self::ADDITIVITY_PREFIX)); |
|
111 $this->config['loggers'][$name]['additivity'] = $value; |
|
112 } // Parse appenders |
|
113 else if ($this->beginsWith($key, self::APPENDER_PREFIX)) { |
|
114 $this->parseAppender($key, $value); |
|
115 } // Parse renderers |
|
116 else if ($this->beginsWith($key, self::RENDERER_PREFIX)) { |
|
117 $this->parseRenderer($key, $value); |
|
118 } |
|
119 } |
|
120 |
|
121 return $this->config; |
|
122 } |
|
123 |
|
124 |
|
125 /** |
|
126 * Parses a logger definition. |
|
127 * |
|
128 * Loggers are defined in the following manner: |
|
129 * <pre> |
|
130 * log4php.logger.<name> = [<level>], [<appender-ref>, <appender-ref>, ...] |
|
131 * </pre> |
|
132 * |
|
133 * @param string $value The configuration value (level and appender-refs). |
|
134 * @param string $name Logger name. |
|
135 */ |
|
136 private function parseLogger($value, $name) { |
|
137 // Value is divided by commas |
|
138 $parts = explode(',', $value); |
|
139 if (empty($value) || empty($parts)) { |
|
140 return; |
|
141 } |
|
142 |
|
143 // The first value is the logger level |
|
144 $level = array_shift($parts); |
|
145 |
|
146 // The remaining values are appender references |
|
147 $appenders = array(); |
|
148 while ($appender = array_shift($parts)) { |
|
149 $appender = trim($appender); |
|
150 if (!empty($appender)) { |
|
151 $appenders[] = trim($appender); |
|
152 } |
|
153 } |
|
154 |
|
155 // Find the target configuration |
|
156 if ($name == self::ROOT_LOGGER_NAME) { |
|
157 $this->config['rootLogger']['level'] = trim($level); |
|
158 $this->config['rootLogger']['appenders'] = $appenders; |
|
159 } else { |
|
160 $this->config['loggers'][$name]['level'] = trim($level); |
|
161 $this->config['loggers'][$name]['appenders'] = $appenders; |
|
162 } |
|
163 } |
|
164 |
|
165 /** |
|
166 * Parses an configuration line pertaining to an appender. |
|
167 * |
|
168 * Parses the following patterns: |
|
169 * |
|
170 * Appender class: |
|
171 * <pre> |
|
172 * log4php.appender.<name> = <class> |
|
173 * </pre> |
|
174 * |
|
175 * Appender parameter: |
|
176 * <pre> |
|
177 * log4php.appender.<name>.<param> = <value> |
|
178 * </pre> |
|
179 * |
|
180 * Appender threshold: |
|
181 * <pre> |
|
182 * log4php.appender.<name>.threshold = <level> |
|
183 * </pre> |
|
184 * |
|
185 * Appender layout: |
|
186 * <pre> |
|
187 * log4php.appender.<name>.layout = <layoutClass> |
|
188 * </pre> |
|
189 * |
|
190 * Layout parameter: |
|
191 * <pre> |
|
192 * log4php.appender.<name>.layout.<param> = <value> |
|
193 * </pre> |
|
194 * |
|
195 * For example, a full appender config might look like: |
|
196 * <pre> |
|
197 * log4php.appender.myAppender = LoggerAppenderConsole |
|
198 * log4php.appender.myAppender.threshold = info |
|
199 * log4php.appender.myAppender.target = stdout |
|
200 * log4php.appender.myAppender.layout = LoggerLayoutPattern |
|
201 * log4php.appender.myAppender.layout.conversionPattern = "%d %c: %m%n" |
|
202 * </pre> |
|
203 * |
|
204 * After parsing all these options, the following configuration can be |
|
205 * found under $this->config['appenders']['myAppender']: |
|
206 * <pre> |
|
207 * array( |
|
208 * 'class' => LoggerAppenderConsole, |
|
209 * 'threshold' => info, |
|
210 * 'params' => array( |
|
211 * 'target' => 'stdout' |
|
212 * ), |
|
213 * 'layout' => array( |
|
214 * 'class' => 'LoggerAppenderConsole', |
|
215 * 'params' => array( |
|
216 * 'conversionPattern' => '%d %c: %m%n' |
|
217 * ) |
|
218 * ) |
|
219 * ) |
|
220 * </pre> |
|
221 * |
|
222 * @param string $key |
|
223 * @param string $value |
|
224 */ |
|
225 private function parseAppender($key, $value) { |
|
226 |
|
227 // Remove the appender prefix from key |
|
228 $subKey = substr($key, strlen(self::APPENDER_PREFIX)); |
|
229 |
|
230 // Divide the string by dots |
|
231 $parts = explode('.', $subKey); |
|
232 $count = count($parts); |
|
233 |
|
234 // The first part is always the appender name |
|
235 $name = trim($parts[0]); |
|
236 |
|
237 // Only one part - this line defines the appender class |
|
238 if ($count == 1) { |
|
239 $this->config['appenders'][$name]['class'] = $value; |
|
240 return; |
|
241 } // Two parts - either a parameter, a threshold or layout class |
|
242 else if ($count == 2) { |
|
243 |
|
244 if ($parts[1] == 'layout') { |
|
245 $this->config['appenders'][$name]['layout']['class'] = $value; |
|
246 return; |
|
247 } else if ($parts[1] == 'threshold') { |
|
248 $this->config['appenders'][$name]['threshold'] = $value; |
|
249 return; |
|
250 } else { |
|
251 $this->config['appenders'][$name]['params'][$parts[1]] = $value; |
|
252 return; |
|
253 } |
|
254 } // Three parts - this can only be a layout parameter |
|
255 else if ($count == 3) { |
|
256 if ($parts[1] == 'layout') { |
|
257 $this->config['appenders'][$name]['layout']['params'][$parts[2]] = $value; |
|
258 return; |
|
259 } |
|
260 } |
|
261 |
|
262 trigger_error("log4php: Don't know how to parse the following line: \"$key = $value\". Skipping."); |
|
263 } |
|
264 |
|
265 /** |
|
266 * Parses a renderer definition. |
|
267 * |
|
268 * Renderers are defined as: |
|
269 * <pre> |
|
270 * log4php.renderer.<renderedClass> = <renderingClass> |
|
271 * </pre> |
|
272 * |
|
273 * @param string $key log4php.renderer.<renderedClass> |
|
274 * @param string $value <renderingClass> |
|
275 */ |
|
276 private function parseRenderer($key, $value) { |
|
277 // Remove the appender prefix from key |
|
278 $renderedClass = substr($key, strlen(self::APPENDER_PREFIX)); |
|
279 $renderingClass = $value; |
|
280 |
|
281 $this->config['renderers'][] = compact('renderedClass', 'renderingClass'); |
|
282 } |
|
283 |
|
284 /** Helper method. Returns true if $str begins with $sub. */ |
|
285 private function beginsWith($str, $sub) { |
|
286 return (strncmp($str, $sub, strlen($sub)) == 0); |
|
287 } |
|
288 |
|
289 |
|
290 } |
|
291 |