Overview

Packages

  • log4php
    • appenders
    • configurators
    • filters
    • helpers
    • layouts
    • pattern
    • renderers

Classes

  • Logger
  • LoggerAppender
  • LoggerAppenderPool
  • LoggerAutoloader
  • LoggerConfigurable
  • LoggerConfiguratorDefault
  • LoggerFilter
  • LoggerHierarchy
  • LoggerLayout
  • LoggerLevel
  • LoggerLocationInfo
  • LoggerLoggingEvent
  • LoggerMDC
  • LoggerNDC
  • LoggerReflectionUtils
  • LoggerRoot
  • LoggerThrowableInformation

Interfaces

  • LoggerConfigurator

Exceptions

  • LoggerException
  • Overview
  • Package
  • Class
  • Tree
  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:  * Default implementation of the logger configurator.
 23:  * 
 24:  * Configures log4php based on a provided configuration file or array.
 25:  * 
 26:  * @package log4php
 27:  * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
 28:  * @version $Revision: 1394956 $
 29:  * @since 2.2
 30:  */
 31: class LoggerConfiguratorDefault implements LoggerConfigurator
 32: {
 33:     /** XML configuration file format. */
 34:     const FORMAT_XML = 'xml';
 35:     
 36:     /** PHP configuration file format. */
 37:     const FORMAT_PHP = 'php';
 38:     
 39:     /** INI (properties) configuration file format. */
 40:     const FORMAT_INI = 'ini';
 41: 
 42:     /** Defines which adapter should be used for parsing which format. */
 43:     private $adapters = array(
 44:         self::FORMAT_XML => 'LoggerConfigurationAdapterXML',
 45:         self::FORMAT_INI => 'LoggerConfigurationAdapterINI',
 46:         self::FORMAT_PHP => 'LoggerConfigurationAdapterPHP',
 47:     );
 48:     
 49:     /** Default configuration; used if no configuration file is provided. */
 50:     private static $defaultConfiguration = array(
 51:         'threshold' => 'ALL',
 52:         'rootLogger' => array(
 53:             'level' => 'DEBUG',
 54:             'appenders' => array('default'),
 55:         ),
 56:         'appenders' => array(
 57:             'default' => array(
 58:                 'class' => 'LoggerAppenderEcho'
 59:             ),
 60:         ),
 61:     );
 62:     
 63:     /** Holds the appenders before they are linked to loggers. */
 64:     private $appenders = array();
 65:     
 66:     /**
 67:      * Configures log4php based on the given configuration. The input can 
 68:      * either be a path to the config file, or a PHP array holding the 
 69:      * configuration. 
 70:      * 
 71:      * If no configuration is given, or if the given configuration cannot be
 72:      * parsed for whatever reason, a warning will be issued, and log4php
 73:      * will use the default configuration contained in 
 74:      * {@link $defaultConfiguration}.
 75:      * 
 76:      * @param LoggerHierarchy $hierarchy The hierarchy on which to perform 
 77:      *      the configuration. 
 78:      * @param string|array $input Either path to the config file or the 
 79:      *      configuration as an array. If not set, default configuration 
 80:      *      will be used.
 81:      */
 82:     public function configure(LoggerHierarchy $hierarchy, $input = null) {
 83:         $config = $this->parse($input);
 84:         $this->doConfigure($hierarchy, $config);
 85:     }
 86:     
 87:     /**
 88:      * Parses the given configuration and returns the parsed configuration
 89:      * as a PHP array. Does not perform any configuration. 
 90:      * 
 91:      * If no configuration is given, or if the given configuration cannot be
 92:      * parsed for whatever reason, a warning will be issued, and the default 
 93:      * configuration will be returned ({@link $defaultConfiguration}).
 94:      * 
 95:      * @param string|array $input Either path to the config file or the 
 96:      *      configuration as an array. If not set, default configuration 
 97:      *      will be used.
 98:      * @return array The parsed configuration.
 99:      */
100:     public function parse($input) {
101:         // No input - use default configuration
102:         if (!isset($input)) {
103:             $config = self::$defaultConfiguration;
104:         }
105:         
106:         // Array input - contains configuration within the array
107:         else if (is_array($input)) {
108:             $config = $input;
109:         }
110:         
111:         // String input - contains path to configuration file
112:         else if (is_string($input)) {
113:             try {
114:                 $config = $this->parseFile($input);
115:             } catch (LoggerException $e) {
116:                 $this->warn("Configuration failed. " . $e->getMessage() . " Using default configuration.");
117:                 $config = self::$defaultConfiguration;
118:             }
119:         }
120:         
121:         // Anything else is an error
122:         else {
123:             $this->warn("Invalid configuration param given. Reverting to default configuration.");
124:             $config = self::$defaultConfiguration;
125:         }
126:         
127:         return $config;
128:     }
129: 
130:     /** 
131:      * Returns the default log4php configuration.
132:      * @return array
133:      */
134:     public static function getDefaultConfiguration() {
135:         return self::$defaultConfiguration;
136:     } 
137:     
138:     /**
139:      * Loads the configuration file from the given URL, determines which
140:      * adapter to use, converts the configuration to a PHP array and
141:      * returns it.
142:      *
143:      * @param string $url Path to the config file.
144:      * @return The configuration from the config file, as a PHP array.
145:      * @throws LoggerException If the configuration file cannot be loaded, or
146:      *      if the parsing fails.
147:      */
148:     private function parseFile($url) {
149:         
150:         if (!file_exists($url)) {
151:             throw new LoggerException("File not found at [$url].");
152:         }
153:         
154:         $type = $this->getConfigType($url);
155:         $adapterClass = $this->adapters[$type];
156: 
157:         $adapter = new $adapterClass();
158:         return $adapter->convert($url);
159:     }
160:     
161:     /** Determines configuration file type based on the file extension. */
162:     private function getConfigType($url) {
163:         $info = pathinfo($url);
164:         $ext = strtolower($info['extension']);
165:         
166:         switch($ext) {
167:             case 'xml':
168:                 return self::FORMAT_XML;
169:             
170:             case 'ini':
171:             case 'properties':
172:                 return self::FORMAT_INI;
173:             
174:             case 'php':
175:                 return self::FORMAT_PHP;
176:                 
177:             default:
178:                 throw new LoggerException("Unsupported configuration file extension: $ext");
179:         }
180:     }
181:     
182:     /**
183:      * Constructs the logger hierarchy based on configuration.
184:      * 
185:      * @param LoggerHierarchy $hierarchy
186:      * @param array $config
187:      */
188:     private function doConfigure(LoggerHierarchy $hierarchy, $config) {
189:         if (isset($config['threshold'])) {
190:             $threshold = LoggerLevel::toLevel($config['threshold']);
191:             if (isset($threshold)) {
192:                 $hierarchy->setThreshold($threshold);
193:             } else {
194:                 $this->warn("Invalid threshold value [{$config['threshold']}] specified. Ignoring threshold definition.");
195:             }
196:         }
197:         
198:         // Configure appenders and add them to the appender pool
199:         if (isset($config['appenders']) && is_array($config['appenders'])) {
200:             foreach($config['appenders'] as $name => $appenderConfig) {
201:                 $this->configureAppender($name, $appenderConfig);
202:             }
203:         }
204:         
205:         // Configure root logger 
206:         if (isset($config['rootLogger'])) {
207:             $this->configureRootLogger($hierarchy, $config['rootLogger']);
208:         }
209:         
210:         // Configure loggers
211:         if (isset($config['loggers']) && is_array($config['loggers'])) {
212:             foreach($config['loggers'] as $loggerName => $loggerConfig) {
213:                 $this->configureOtherLogger($hierarchy, $loggerName, $loggerConfig);
214:             }
215:         }
216: 
217:         // Configure renderers
218:         if (isset($config['renderers']) && is_array($config['renderers'])) {
219:             foreach($config['renderers'] as $rendererConfig) {
220:                 $this->configureRenderer($hierarchy, $rendererConfig);
221:             }
222:         }
223:         
224:         if (isset($config['defaultRenderer'])) {
225:             $this->configureDefaultRenderer($hierarchy, $config['defaultRenderer']);
226:         }
227:     }
228:     
229:     private function configureRenderer(LoggerHierarchy $hierarchy, $config) {
230:         if (empty($config['renderingClass'])) {
231:             $this->warn("Rendering class not specified. Skipping renderer definition.");
232:             return;
233:         }
234:         
235:         if (empty($config['renderedClass'])) {
236:             $this->warn("Rendered class not specified. Skipping renderer definition.");
237:             return;
238:         }
239:         
240:         // Error handling performed by RendererMap
241:         $hierarchy->getRendererMap()->addRenderer($config['renderedClass'], $config['renderingClass']);
242:     }
243:     
244:     private function configureDefaultRenderer(LoggerHierarchy $hierarchy, $class) {
245:         if (empty($class)) {
246:             $this->warn("Rendering class not specified. Skipping default renderer definition.");
247:             return;
248:         }
249:         
250:         // Error handling performed by RendererMap
251:         $hierarchy->getRendererMap()->setDefaultRenderer($class);
252:     }
253:     
254:     /** 
255:      * Configures an appender based on given config and saves it to 
256:      * {@link $appenders} array so it can be later linked to loggers. 
257:      * @param string $name Appender name. 
258:      * @param array $config Appender configuration options.
259:      */
260:     private function configureAppender($name, $config) {
261: 
262:         // TODO: add this check to other places where it might be useful
263:         if (!is_array($config)) {
264:             $type = gettype($config);
265:             $this->warn("Invalid configuration provided for appender [$name]. Expected an array, found <$type>. Skipping appender definition.");
266:             return;
267:         }
268:         
269:         // Parse appender class
270:         $class = $config['class'];
271:         if (empty($class)) {
272:             $this->warn("No class given for appender [$name]. Skipping appender definition.");
273:             return;
274:         }
275:         if (!class_exists($class)) {
276:             $this->warn("Invalid class [$class] given for appender [$name]. Class does not exist. Skipping appender definition.");
277:             return;
278:         }
279:         
280:         // Instantiate the appender
281:         $appender = new $class($name);
282:         if (!($appender instanceof LoggerAppender)) {
283:             $this->warn("Invalid class [$class] given for appender [$name]. Not a valid LoggerAppender class. Skipping appender definition.");
284:             return;
285:         }
286:         
287:         // Parse the appender threshold
288:         if (isset($config['threshold'])) {
289:             $threshold = LoggerLevel::toLevel($config['threshold']);
290:             if ($threshold instanceof LoggerLevel) {
291:                 $appender->setThreshold($threshold);
292:             } else {
293:                 $this->warn("Invalid threshold value [{$config['threshold']}] specified for appender [$name]. Ignoring threshold definition.");
294:             }
295:         }
296:         
297:         // Parse the appender layout
298:         if ($appender->requiresLayout() && isset($config['layout'])) {
299:             $this->createAppenderLayout($appender, $config['layout']);
300:         }
301:         
302:         // Parse filters
303:         if (isset($config['filters']) && is_array($config['filters'])) {
304:             foreach($config['filters'] as $filterConfig) {
305:                 $this->createAppenderFilter($appender, $filterConfig);
306:             }
307:         }
308:         
309:         // Set options if any
310:         if (isset($config['params'])) {
311:             $this->setOptions($appender, $config['params']);
312:         }
313: 
314:         // Activate and save for later linking to loggers
315:         $appender->activateOptions();
316:         $this->appenders[$name] = $appender;
317:     }
318:     
319:     /**
320:      * Parses layout config, creates the layout and links it to the appender.
321:      * @param LoggerAppender $appender
322:      * @param array $config Layout configuration.
323:      */
324:     private function createAppenderLayout(LoggerAppender $appender, $config) {
325:         $name = $appender->getName();
326:         $class = $config['class'];
327:         if (empty($class)) {
328:             $this->warn("Layout class not specified for appender [$name]. Reverting to default layout.");
329:             return;
330:         }
331:         if (!class_exists($class)) {
332:             $this->warn("Nonexistant layout class [$class] specified for appender [$name]. Reverting to default layout.");
333:             return;
334:         }
335:         
336:         $layout = new $class();
337:         if (!($layout instanceof LoggerLayout)) {
338:             $this->warn("Invalid layout class [$class] sepcified for appender [$name]. Reverting to default layout.");
339:             return;
340:         }
341:         
342:         if (isset($config['params'])) {
343:             $this->setOptions($layout, $config['params']);
344:         }
345:         
346:         $layout->activateOptions();
347:         $appender->setLayout($layout);
348:     }
349:     
350:     /**
351:      * Parses filter config, creates the filter and adds it to the appender's 
352:      * filter chain.
353:      * @param LoggerAppender $appender
354:      * @param array $config Filter configuration.
355:      */
356:     private function createAppenderFilter(LoggerAppender $appender, $config) {
357:         $name = $appender->getName();
358:         $class = $config['class'];
359:         if (!class_exists($class)) {
360:             $this->warn("Nonexistant filter class [$class] specified on appender [$name]. Skipping filter definition.");
361:             return;
362:         }
363:     
364:         $filter = new $class();
365:         if (!($filter instanceof LoggerFilter)) {
366:             $this->warn("Invalid filter class [$class] sepcified on appender [$name]. Skipping filter definition.");
367:             return;
368:         }
369:     
370:         if (isset($config['params'])) {
371:             $this->setOptions($filter, $config['params']);
372:         }
373:     
374:         $filter->activateOptions();
375:         $appender->addFilter($filter);
376:     }
377:     
378:     /** 
379:      * Configures the root logger
380:      * @see configureLogger() 
381:      */
382:     private function configureRootLogger(LoggerHierarchy $hierarchy, $config) {
383:         $logger = $hierarchy->getRootLogger();
384:         $this->configureLogger($logger, $config);
385:     }
386: 
387:     /**
388:      * Configures a logger which is not root.
389:      * @see configureLogger()
390:      */
391:     private function configureOtherLogger(LoggerHierarchy $hierarchy, $name, $config) {
392:         // Get logger from hierarchy (this creates it if it doesn't already exist)
393:         $logger = $hierarchy->getLogger($name);
394:         $this->configureLogger($logger, $config);
395:     }
396:     
397:     /**
398:      * Configures a logger. 
399:      * 
400:      * @param Logger $logger The logger to configure
401:      * @param array $config Logger configuration options.
402:      */
403:     private function configureLogger(Logger $logger, $config) {
404:         $loggerName = $logger->getName();
405:         
406:         // Set logger level
407:         if (isset($config['level'])) {
408:             $level = LoggerLevel::toLevel($config['level']);
409:             if (isset($level)) {
410:                 $logger->setLevel($level);
411:             } else {
412:                 $this->warn("Invalid level value [{$config['level']}] specified for logger [$loggerName]. Ignoring level definition.");
413:             }
414:         }
415:         
416:         // Link appenders to logger
417:         if (isset($config['appenders'])) {
418:             foreach($config['appenders'] as $appenderName) {
419:                 if (isset($this->appenders[$appenderName])) {
420:                     $logger->addAppender($this->appenders[$appenderName]);
421:                 } else {
422:                     $this->warn("Nonexistnant appender [$appenderName] linked to logger [$loggerName].");
423:                 }
424:             }
425:         }
426:         
427:         // Set logger additivity
428:         if (isset($config['additivity'])) {
429:             try {
430:                 $additivity = LoggerOptionConverter::toBooleanEx($config['additivity'], null);
431:                 $logger->setAdditivity($additivity);
432:             } catch (Exception $ex) {
433:                 $this->warn("Invalid additivity value [{$config['additivity']}] specified for logger [$loggerName]. Ignoring additivity setting.");
434:             }
435:         }
436:     }
437: 
438:     /**
439:      * Helper method which applies given options to an object which has setters
440:      * for these options (such as appenders, layouts, etc.).
441:      * 
442:      * For example, if options are:
443:      * <code>
444:      * array(
445:      *  'file' => '/tmp/myfile.log',
446:      *  'append' => true
447:      * )
448:      * </code>
449:      * 
450:      * This method will call:
451:      * <code>
452:      * $object->setFile('/tmp/myfile.log')
453:      * $object->setAppend(true)
454:      * </code>
455:      * 
456:      * If required setters do not exist, it will produce a warning. 
457:      * 
458:      * @param mixed $object The object to configure.
459:      * @param unknown_type $options
460:      */
461:     private function setOptions($object, $options) {
462:         foreach($options as $name => $value) {
463:             $setter = "set$name";
464:             if (method_exists($object, $setter)) {
465:                 $object->$setter($value);
466:             } else {
467:                 $class = get_class($object);
468:                 $this->warn("Nonexistant option [$name] specified on [$class]. Skipping.");
469:             }
470:         }
471:     }
472:     
473:     /** Helper method to simplify error reporting. */
474:     private function warn($message) {
475:         trigger_error("log4php: $message", E_USER_WARNING);
476:     }
477: }
478: 
Apache log4php API documentation generated by ApiGen 2.8.0