3 * log4php is a PHP port of the log4j java logging package.
5 * <p>This framework is based on log4j (see {@link http://jakarta.apache.org/log4j log4j} for details).</p>
6 * <p>Design, strategies and part of the methods documentation are developed by log4j team
7 * (Ceki Gülcü as log4j project founder and
8 * {@link http://jakarta.apache.org/log4j/docs/contributors.html contributors}).</p>
10 * <p>PHP port, extensions and modifications by VxR. All rights reserved.<br>
11 * For more information, please see {@link http://www.vxr.it/log4php/}.</p>
13 * <p>This software is published under the terms of the LGPL License
14 * a copy of which has been included with this distribution in the LICENSE file.</p>
23 if (!defined('LOG4PHP_DIR')) define('LOG4PHP_DIR', dirname(__FILE__) . '/..');
25 require_once(LOG4PHP_DIR . '/helpers/LoggerOptionConverter.php');
26 require_once(LOG4PHP_DIR . '/or/LoggerObjectRenderer.php');
27 require_once(LOG4PHP_DIR . '/spi/LoggerConfigurator.php');
28 require_once(LOG4PHP_DIR . '/LoggerAppender.php');
29 require_once(LOG4PHP_DIR . '/LoggerLayout.php');
30 require_once(LOG4PHP_DIR . '/LoggerLog.php');
31 require_once(LOG4PHP_DIR . '/LoggerManager.php');
33 define('LOG4PHP_LOGGER_DOM_CONFIGURATOR_APPENDER_STATE', 1000);
34 define('LOG4PHP_LOGGER_DOM_CONFIGURATOR_LAYOUT_STATE', 1010);
35 define('LOG4PHP_LOGGER_DOM_CONFIGURATOR_ROOT_STATE', 1020);
36 define('LOG4PHP_LOGGER_DOM_CONFIGURATOR_LOGGER_STATE', 1030);
37 define('LOG4PHP_LOGGER_DOM_CONFIGURATOR_FILTER_STATE', 1040);
39 define('LOG4PHP_LOGGER_DOM_CONFIGURATOR_DEFAULT_FILENAME', './log4php.xml');
42 * @var string the default configuration document
44 define('LOG4PHP_LOGGER_DOM_CONFIGURATOR_DEFAULT_CONFIGURATION',
45 '<?xml version="1.0" ?>
46 <log4php:configuration threshold="all">
47 <appender name="A1" class="LoggerAppenderEcho">
48 <layout class="LoggerLayoutSimple" />
51 <level value="debug" />
52 <appender_ref ref="A1" />
54 </log4php:configuration>');
57 * @var string the elements namespace
59 define('LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS', 'HTTP://WWW.VXR.IT/LOG4PHP/');
62 * Use this class to initialize the log4php environment using expat parser.
64 * <p>Read the log4php.dtd included in the documentation directory. Note that
65 * php parser does not validate the document.</p>
67 * <p>Sometimes it is useful to see how log4php is reading configuration
68 * files. You can enable log4php internal logging by setting the <var>debug</var>
69 * attribute in the <var>log4php:configuration</var> element. As in
71 * <log4php:configuration <b>debug="true"</b> xmlns:log4php="http://www.vxr.it/log4php/">
73 * </log4php:configuration>
76 * <p>There are sample XML files included in the package under <b>tests/</b>
79 * @author VxR <vxr@vxr.it>
80 * @version $Revision: 2 $
85 class LoggerDOMConfigurator extends LoggerConfigurator {
88 * @var LoggerHierarchy
93 * @var array state stack
98 * @var Logger parsed Logger
103 * @var LoggerAppender parsed LoggerAppender
108 * @var LoggerFilter parsed LoggerFilter
113 * @var LoggerLayout parsed LoggerLayout
120 function LoggerDOMConfigurator()
122 $this->state = array();
123 $this->logger = null;
124 $this->appender = null;
125 $this->filter = null;
126 $this->layout = null;
130 * Configure the default repository using the resource pointed by <b>url</b>.
131 * <b>Url</b> is any valid resurce as defined in {@link PHP_MANUAL#file} function.
132 * Note that the resource will be search with <i>use_include_path</i> parameter
138 function configure($url = '')
140 $configurator = new LoggerDOMConfigurator();
141 $repository =& LoggerManager::getLoggerRepository();
142 return $configurator->doConfigure($url, $repository);
146 * Configure the given <b>repository</b> using the resource pointed by <b>url</b>.
147 * <b>Url</b> is any valid resurce as defined in {@link PHP_MANUAL#file} function.
148 * Note that the resource will be search with <i>use_include_path</i> parameter
152 * @param LoggerHierarchy &$repository
154 function doConfigure($url = '', &$repository)
158 $xmlData = implode('', file($url, 1));
159 return $this->doConfigureByString($xmlData, $repository);
163 * Configure the given <b>repository</b> using the configuration written in <b>xmlData</b>.
164 * Do not call this method directly. Use {@link doConfigure()} instead.
165 * @param string $xmlData
166 * @param LoggerHierarchy &$repository
168 function doConfigureByString($xmlData, &$repository)
170 return $this->parse($xmlData, $repository);
174 * @param LoggerHierarchy &$repository
176 function doConfigureDefault(&$repository)
178 return $this->doConfigureByString(LOG4PHP_LOGGER_DOM_CONFIGURATOR_DEFAULT_CONFIGURATION, $repository);
182 * @param string $xmlData
184 function parse($xmlData, &$repository)
186 // LoggerManager::resetConfiguration();
187 $this->repository =& $repository;
189 $parser = xml_parser_create_ns();
191 xml_set_object($parser, &$this);
192 xml_set_element_handler($parser, "tagOpen", "tagClose");
194 $result = xml_parse($parser, $xmlData, true);
196 $errorCode = xml_get_error_code($parser);
197 $errorStr = xml_error_string($errorCode);
198 $errorLine = xml_get_current_line_number($parser);
200 "LoggerDOMConfigurator::parse() ".
201 "Parsing error [{$errorCode}] {$errorStr}, line {$errorLine}"
203 $this->repository->resetConfiguration();
205 xml_parser_free($parser);
211 * @param mixed $parser
213 * @param array $attribs
215 * @todo In 'LOGGER' case find a better way to detect 'getLogger()' method
217 function tagOpen($parser, $tag, $attribs)
221 case 'CONFIGURATION' :
222 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':CONFIGURATION':
224 LoggerLog::debug("LoggerDOMConfigurator::tagOpen() CONFIGURATION");
226 if (isset($attribs['THRESHOLD'])) {
228 $this->repository->setThreshold(
229 LoggerOptionConverter::toLevel(
230 $this->subst($attribs['THRESHOLD']),
231 $this->repository->getThreshold()
235 if (isset($attribs['DEBUG'])) {
236 $debug = LoggerOptionConverter::toBoolean($this->subst($attribs['DEBUG']), LoggerLog::internalDebugging());
237 $this->repository->debug = $debug;
238 LoggerLog::internalDebugging($debug);
239 LoggerLog::debug("LoggerDOMConfigurator::tagOpen() LOG4PHP:CONFIGURATION. Internal Debug turned ".($debug ? 'on':'off'));
245 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':APPENDER':
247 unset($this->appender);
248 $this->appender = null;
250 $name = $this->subst(@$attribs['NAME']);
251 $class = $this->subst(@$attribs['CLASS']);
253 LoggerLog::debug("LoggerDOMConfigurator::tagOpen():tag=[$tag]:name=[$name]:class=[$class]");
255 $this->appender =& LoggerAppender::singleton($name, $class);
256 if ($this->appender === null) {
257 LoggerLog::warn("LoggerDOMConfigurator::tagOpen() APPENDER cannot instantiate appender '$name'");
259 $this->state[] = LOG4PHP_LOGGER_DOM_CONFIGURATOR_APPENDER_STATE;
262 case 'APPENDER_REF' :
263 case 'APPENDER-REF' :
264 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':APPENDER_REF':
265 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':APPENDER-REF':
268 if (isset($attribs['REF']) and !empty($attribs['REF'])) {
269 $appenderName = $this->subst($attribs['REF']);
271 LoggerLog::debug("LoggerDOMConfigurator::tagOpen() APPENDER-REF ref='$appenderName'");
273 $appender =& LoggerAppender::singleton($appenderName);
274 if ($appender !== null) {
275 switch (end($this->state)) {
276 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_LOGGER_STATE:
277 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_ROOT_STATE:
278 $this->logger->addAppender($appender);
282 LoggerLog::warn("LoggerDOMConfigurator::tagOpen() APPENDER-REF ref '$appenderName' points to a null appender");
285 LoggerLog::warn("LoggerDOMConfigurator::tagOpen() APPENDER-REF ref not set or empty");
290 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':FILTER':
292 LoggerLog::debug("LoggerDOMConfigurator::tagOpen() FILTER");
294 unset($this->filter);
295 $this->filter = null;
297 $filterName = basename($this->subst(@$attribs['CLASS']));
298 if (!empty($filterName)) {
299 if (!class_exists($filterName)) {
300 @include_once(LOG4PHP_DIR . "/varia/{$filterName}.php");
302 if (class_exists($filterName)) {
303 $this->filter = new $filterName();
305 LoggerLog::warn("LoggerDOMConfigurator::tagOpen() FILTER. class '$filterName' doesnt exist");
307 $this->state[] = LOG4PHP_LOGGER_DOM_CONFIGURATOR_FILTER_STATE;
309 LoggerLog::warn("LoggerDOMConfigurator::tagOpen() FILTER filter name cannot be empty");
314 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':LAYOUT':
316 $class = @$attribs['CLASS'];
318 LoggerLog::debug("LoggerDOMConfigurator::tagOpen() LAYOUT class='{$class}'");
320 $this->layout = LoggerLayout::factory($this->subst($class));
321 if ($this->layout === null)
322 LoggerLog::warn("LoggerDOMConfigurator::tagOpen() LAYOUT unable to instanciate class='{$class}'");
324 $this->state[] = LOG4PHP_LOGGER_DOM_CONFIGURATOR_LAYOUT_STATE;
328 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':LOGGER':
330 // $this->logger is assigned by reference.
331 // Only '$this->logger=null;' destroys referenced object
332 unset($this->logger);
333 $this->logger = null;
335 $loggerName = $this->subst(@$attribs['NAME']);
336 if (!empty($loggerName)) {
337 LoggerLog::debug("LoggerDOMConfigurator::tagOpen() LOGGER. name='$loggerName'");
339 $class = $this->subst(@$attribs['CLASS']);
341 $this->logger =& $this->repository->getLogger($loggerName);
343 $className = basename($class);
344 if (!class_exists($className))
345 @include_once("{$class}.php");
346 if (!class_exists($className)) {
348 "LoggerDOMConfigurator::tagOpen() LOGGER. ".
349 "cannot find '$className'."
353 if (in_array('getlogger', get_class_methods($className))) {
354 $this->logger =& call_user_func(array($className, 'getlogger'), $loggerName);
357 "LoggerDOMConfigurator::tagOpen() LOGGER. ".
358 "class '$className' doesnt implement 'getLogger()' method."
363 if ($this->logger !== null and isset($attribs['ADDITIVITY'])) {
364 $additivity = LoggerOptionConverter::toBoolean($this->subst($attribs['ADDITIVITY']), true);
365 $this->logger->setAdditivity($additivity);
368 LoggerLog::warn("LoggerDOMConfigurator::tagOpen() LOGGER. Attribute 'name' is not set or is empty.");
370 $this->state[] = LOG4PHP_LOGGER_DOM_CONFIGURATOR_LOGGER_STATE;;
374 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':LEVEL':
376 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':PRIORITY':
378 if (!isset($attribs['VALUE'])) {
379 LoggerLog::debug("LoggerDOMConfigurator::tagOpen() LEVEL value not set");
383 LoggerLog::debug("LoggerDOMConfigurator::tagOpen() LEVEL value={$attribs['VALUE']}");
385 if ($this->logger === null) {
386 LoggerLog::warn("LoggerDOMConfigurator::tagOpen() LEVEL. parent logger is null");
390 switch (end($this->state)) {
391 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_ROOT_STATE:
392 $this->logger->setLevel(
393 LoggerOptionConverter::toLevel(
394 $this->subst($attribs['VALUE']),
395 $this->logger->getLevel()
398 LoggerLog::debug("LoggerDOMConfigurator::tagOpen() LEVEL root level is now '{$attribs['VALUE']}' ");
400 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_LOGGER_STATE:
401 $this->logger->setLevel(
402 LoggerOptionConverter::toLevel(
403 $this->subst($attribs['VALUE']),
404 $this->logger->getLevel()
409 LoggerLog::warn("LoggerDOMConfigurator::tagOpen() LEVEL state '{$this->state}' not allowed here");
414 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':PARAM':
416 LoggerLog::debug("LoggerDOMConfigurator::tagOpen() PARAM");
418 if (!isset($attribs['NAME'])) {
420 "LoggerDOMConfigurator::tagOpen() PARAM. ".
421 "attribute 'name' not defined."
425 if (!isset($attribs['VALUE'])) {
427 "LoggerDOMConfigurator::tagOpen() PARAM. ".
428 "attribute 'value' not defined."
433 switch (end($this->state)) {
434 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_APPENDER_STATE:
435 if ($this->appender !== null) {
436 $this->setter($this->appender, $this->subst($attribs['NAME']), $this->subst($attribs['VALUE']));
439 "LoggerDOMConfigurator::tagOpen() PARAM. ".
440 " trying to set property to a null appender."
444 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_LAYOUT_STATE:
445 if ($this->layout !== null) {
446 $this->setter($this->layout, $this->subst($attribs['NAME']), $this->subst($attribs['VALUE']));
449 "LoggerDOMConfigurator::tagOpen() PARAM. ".
450 " trying to set property to a null layout."
454 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_FILTER_STATE:
455 if ($this->filter !== null) {
456 $this->setter($this->filter, $this->subst($attribs['NAME']), $this->subst($attribs['VALUE']));
459 "LoggerDOMConfigurator::tagOpen() PARAM. ".
460 " trying to set property to a null filter."
465 LoggerLog::warn("LoggerDOMConfigurator::tagOpen() PARAM state '{$this->state}' not allowed here");
470 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':RENDERER':
472 $renderedClass = $this->subst(@$attribs['RENDEREDCLASS']);
473 $renderingClass = $this->subst(@$attribs['RENDERINGCLASS']);
475 LoggerLog::debug("LoggerDOMConfigurator::tagOpen() RENDERER renderedClass='$renderedClass' renderingClass='$renderingClass'");
477 if (!empty($renderedClass) and !empty($renderingClass)) {
478 $renderer = LoggerObjectRenderer::factory($renderingClass);
479 if ($renderer === null) {
480 LoggerLog::warn("LoggerDOMConfigurator::tagOpen() RENDERER cannot instantiate '$renderingClass'");
482 $this->repository->setRenderer($renderedClass, $renderer);
485 LoggerLog::warn("LoggerDOMConfigurator::tagOpen() RENDERER renderedClass or renderingClass is empty");
490 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':ROOT':
492 LoggerLog::debug("LoggerDOMConfigurator::tagOpen() ROOT");
494 $this->logger =& LoggerManager::getRootLogger();
496 $this->state[] = LOG4PHP_LOGGER_DOM_CONFIGURATOR_ROOT_STATE;
505 * @param mixed $parser
508 function tagClose($parser, $tag)
512 case 'CONFIGURATION' :
513 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':CONFIGURATION':
515 LoggerLog::debug("LoggerDOMConfigurator::tagClose() CONFIGURATION");
519 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':APPENDER':
521 LoggerLog::debug("LoggerDOMConfigurator::tagClose() APPENDER");
523 if ($this->appender !== null) {
524 if ($this->appender->requiresLayout() and $this->appender->layout === null) {
525 $appenderName = $this->appender->getName();
527 "LoggerDOMConfigurator::tagClose() APPENDER. ".
528 "'$appenderName' requires a layout that is not defined. ".
529 "Using a simple layout"
531 $this->appender->setLayout(LoggerLayout::factory('LoggerLayoutSimple'));
533 $this->appender->activateOptions();
535 array_pop($this->state);
539 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':FILTER':
541 LoggerLog::debug("LoggerDOMConfigurator::tagClose() FILTER");
543 if ($this->filter !== null) {
544 $this->filter->activateOptions();
545 $this->appender->addFilter($this->filter);
546 $this->filter = null;
548 array_pop($this->state);
552 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':LAYOUT':
554 LoggerLog::debug("LoggerDOMConfigurator::tagClose() LAYOUT");
556 if ($this->appender !== null and $this->layout !== null and $this->appender->requiresLayout()) {
557 $this->layout->activateOptions();
558 $this->appender->setLayout($this->layout);
559 $this->layout = null;
561 array_pop($this->state);
565 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':LOGGER':
567 LoggerLog::debug("LoggerDOMConfigurator::tagClose() LOGGER");
569 array_pop($this->state);
573 case LOG4PHP_LOGGER_DOM_CONFIGURATOR_XMLNS.':ROOT':
575 LoggerLog::debug("LoggerDOMConfigurator::tagClose() ROOT");
577 array_pop($this->state);
583 * @param object $object
584 * @param string $name
585 * @param mixed $value
587 function setter(&$object, $name, $value)
590 LoggerLog::debug("LoggerDOMConfigurator::setter() 'name' param cannot be empty");
593 $methodName = 'set'.ucfirst($name);
594 if (method_exists($object, $methodName)) {
595 LoggerLog::debug("LoggerDOMConfigurator::setter() Calling ".get_class($object)."::{$methodName}({$value})");
596 return call_user_func(array(&$object, $methodName), $value);
598 LoggerLog::warn("LoggerDOMConfigurator::setter() ".get_class($object)."::{$methodName}() does not exists");
603 function subst($value)
605 return LoggerOptionConverter::substVars($value);