      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: require dirname(__FILE__) . '/LoggerAutoloader.php';
     22:
     23: /**
     24:  * This is the central class in the log4php package. All logging operations
     25:  * are done through this class.
     26:  *
     27:  * The main logging methods are:
     28:  *  <ul>
     29:  *      <li>{@link trace()}</li>
     30:  *      <li>{@link debug()}</li>
     31:  *      <li>{@link info()}</li>
     32:  *      <li>{@link warn()}</li>
     33:  *      <li>{@link error()}</li>
     34:  *      <li>{@link fatal()}</li>
     35:  *  </ul>
     36:  *
     37:  * @package    log4php
     38:  * @license    http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
     39:  * @version    SVN: $Id: Logger.php 1395241 2012-10-07 08:28:53Z ihabunek $
     40:  * @link       http://logging.apache.org/log4php
     41:  */
     42: class Logger {
     43:
     44:     /**
     45:      * Logger additivity. If set to true then child loggers will inherit
     46:      * the appenders of their ancestors by default.
     47:      * @var boolean
     48:      */
     49:     private $additive = true;
     50:
     51:     /**
     52:      * The Logger's fully qualified class name.
     53:      * TODO: Determine if this is useful.
     54:      */
     55:     private $fqcn = 'Logger';
     56:
     57:     /** The assigned Logger level. */
     58:     private $level;
     59:
     60:     /** The name of this Logger instance. */
     61:     private $name;
     62:
     63:     /** The parent logger. Set to null if this is the root logger. */
     64:     private $parent;
     65:
     66:     /** A collection of appenders linked to this logger. */
     67:     private $appenders = array();
     68:
     69:     /**
     70:      * Constructor.
     71:      * @param string $name Name of the logger.
     72:      */
     73:     public function __construct($name) {
     74:         $this->name = $name;
     75:     }
     76:
     77:     /**
     78:      * Returns the logger name.
     79:      * @return string
     80:      */
     81:     public function getName() {
     82:         return $this->name;
     83:     }
     84:
     85:     /**
     86:      * Returns the parent Logger. Can be null if this is the root logger.
     87:      * @return Logger
     88:      */
     89:     public function getParent() {
     90:         return $this->parent;
     91:     }
     92:
     93:     // ******************************************
     94:     // *** Logging methods                    ***
     95:     // ******************************************
     96:
     97:     /**
     98:      * Log a message object with the TRACE level.
     99:      *
    100:      * @param mixed $message message
    101:      * @param Exception $throwable Optional throwable information to include
    102:      *   in the logging event.
    103:      */
    104:     public function trace($message, $throwable = null) {
    105:         $this->log(LoggerLevel::getLevelTrace(), $message, $throwable);
    106:     }
    107:
    108:     /**
    109:      * Log a message object with the DEBUG level.
    110:      *
    111:      * @param mixed $message message
    112:      * @param Exception $throwable Optional throwable information to include
    113:      *   in the logging event.
    114:      */
    115:     public function debug($message, $throwable = null) {
    116:         $this->log(LoggerLevel::getLevelDebug(), $message, $throwable);
    117:     }
    118:
    119:     /**
    120:      * Log a message object with the INFO Level.
    121:      *
    122:      * @param mixed $message message
    123:      * @param Exception $throwable Optional throwable information to include
    124:      *   in the logging event.
    125:      */
    126:     public function info($message, $throwable = null) {
    127:         $this->log(LoggerLevel::getLevelInfo(), $message, $throwable);
    128:     }
    129:
    130:     /**
    131:      * Log a message with the WARN level.
    132:      *
    133:      * @param mixed $message message
    134:      * @param Exception $throwable Optional throwable information to include
    135:      *   in the logging event.
    136:      */
    137:     public function warn($message, $throwable = null) {
    138:         $this->log(LoggerLevel::getLevelWarn(), $message, $throwable);
    139:     }
    140:
    141:     /**
    142:      * Log a message object with the ERROR level.
    143:      *
    144:      * @param mixed $message message
    145:      * @param Exception $throwable Optional throwable information to include
    146:      *   in the logging event.
    147:      */
    148:     public function error($message, $throwable = null) {
    149:         $this->log(LoggerLevel::getLevelError(), $message, $throwable);
    150:     }
    151:
    152:     /**
    153:      * Log a message object with the FATAL level.
    154:      *
    155:      * @param mixed $message message
    156:      * @param Exception $throwable Optional throwable information to include
    157:      *   in the logging event.
    158:      */
    159:     public function fatal($message, $throwable = null) {
    160:         $this->log(LoggerLevel::getLevelFatal(), $message, $throwable);
    161:     }
    162:
    163:     /**
    164:      * Log a message using the provided logging level.
    165:      *
    166:      * @param LoggerLevel $level The logging level.
    167:      * @param mixed $message Message to log.
    168:      * @param Exception $throwable Optional throwable information to include
    169:      *   in the logging event.
    170:      */
    171:     public function log(LoggerLevel $level, $message, $throwable = null) {
    172:         if($this->isEnabledFor($level)) {
    173:             $event = new LoggerLoggingEvent($this->fqcn, $this, $level, $message, null, $throwable);
    174:             $this->callAppenders($event);
    175:         }
    176:
    177:         // Forward the event upstream if additivity is turned on
    178:         if(isset($this->parent) && $this->getAdditivity()) {
    179:
    180:             // Use the event if already created
    181:             if (isset($event)) {
    182:                 $this->parent->logEvent($event);
    183:             } else {
    184:                 $this->parent->log($level, $message, $throwable);
    185:             }
    186:         }
    187:     }
    188:
    189:     /**
    190:      * Logs an already prepared logging event object.
    191:      * @param LoggerLoggingEvent $event
    192:      */
    193:     public function logEvent(LoggerLoggingEvent $event) {
    194:         if($this->isEnabledFor($event->getLevel())) {
    195:             $this->callAppenders($event);
    196:         }
    197:
    198:         // Forward the event upstream if additivity is turned on
    199:         if(isset($this->parent) && $this->getAdditivity()) {
    200:             $this->parent->logEvent($event);
    201:         }
    202:     }
    203:
    204:     /**
    205:      * If assertion parameter evaluates as false, then logs the message
    206:      * using the ERROR level.
    207:      *
    208:      * @param bool $assertion
    209:      * @param string $msg message to log
    210:      */
    211:     public function assertLog($assertion = true, $msg = '') {
    212:         if($assertion == false) {
    213:             $this->error($msg);
    214:         }
    215:     }
    216:
    217:     /**
    218:      * This method creates a new logging event and logs the event without
    219:      * further checks.
    220:      *
    221:      * It should not be called directly. Use {@link trace()}, {@link debug()},
    222:      * {@link info()}, {@link warn()}, {@link error()} and {@link fatal()}
    223:      * wrappers.
    224:      *
    225:      * @param string $fqcn Fully qualified class name of the Logger
    226:      * @param Exception $throwable Optional throwable information to include
    227:      *   in the logging event.
    228:      * @param LoggerLevel $level log level
    229:      * @param mixed $message message to log
    230:      */
    231:     public function forcedLog($fqcn, $throwable, LoggerLevel $level, $message) {
    232:         $event = new LoggerLoggingEvent($fqcn, $this, $level, $message, null, $throwable);
    233:         $this->callAppenders($event);
    234:
    235:         // Forward the event upstream if additivity is turned on
    236:         if(isset($this->parent) && $this->getAdditivity()) {
    237:             $this->parent->logEvent($event);
    238:         }
    239:     }
    240:
    241:     /**
    242:      * Forwards the given logging event to all linked appenders.
    243:      * @param LoggerLoggingEvent $event
    244:      */
    245:     public function callAppenders($event) {
    246:         foreach($this->appenders as $appender) {
    247:             $appender->doAppend($event);
    248:         }
    249:     }
    250:
    251:     // ******************************************
    252:     // *** Checker methods                    ***
    253:     // ******************************************
    254:
    255:     /**
    256:      * Check whether this Logger is enabled for a given Level passed as parameter.
    257:      *
    258:      * @param LoggerLevel level
    259:      * @return boolean
    260:      */
    261:     public function isEnabledFor(LoggerLevel $level) {
    262:         return $level->isGreaterOrEqual($this->getEffectiveLevel());
    263:     }
    264:
    265:     /**
    266:      * Check whether this Logger is enabled for the TRACE Level.
    267:      * @return boolean
    268:      */
    269:     public function isTraceEnabled() {
    270:         return $this->isEnabledFor(LoggerLevel::getLevelTrace());
    271:     }
    272:
    273:     /**
    274:      * Check whether this Logger is enabled for the DEBUG Level.
    275:      * @return boolean
    276:      */
    277:     public function isDebugEnabled() {
    278:         return $this->isEnabledFor(LoggerLevel::getLevelDebug());
    279:     }
    280:
    281:     /**
    282:      * Check whether this Logger is enabled for the INFO Level.
    283:      * @return boolean
    284:      */
    285:     public function isInfoEnabled() {
    286:         return $this->isEnabledFor(LoggerLevel::getLevelInfo());
    287:     }
    288:
    289:     /**
    290:      * Check whether this Logger is enabled for the WARN Level.
    291:      * @return boolean
    292:      */
    293:     public function isWarnEnabled() {
    294:         return $this->isEnabledFor(LoggerLevel::getLevelWarn());
    295:     }
    296:
    297:     /**
    298:      * Check whether this Logger is enabled for the ERROR Level.
    299:      * @return boolean
    300:      */
    301:     public function isErrorEnabled() {
    302:         return $this->isEnabledFor(LoggerLevel::getLevelError());
    303:     }
    304:
    305:     /**
    306:      * Check whether this Logger is enabled for the FATAL Level.
    307:      * @return boolean
    308:      */
    309:     public function isFatalEnabled() {
    310:         return $this->isEnabledFor(LoggerLevel::getLevelFatal());
    311:     }
    312:
    313:     // ******************************************
    314:     // *** Configuration methods              ***
    315:     // ******************************************
    316:
    317:     /**
    318:      * Adds a new appender to the Logger.
    319:      * @param LoggerAppender $appender The appender to add.
    320:      */
    321:     public function addAppender($appender) {
    322:         $appenderName = $appender->getName();
    323:         $this->appenders[$appenderName] = $appender;
    324:     }
    325:
    326:     /** Removes all appenders from the Logger. */
    327:     public function removeAllAppenders() {
    328:         foreach($this->appenders as $name => $appender) {
    329:             $this->removeAppender($name);
    330:         }
    331:     }
    332:
    333:     /**
    334:      * Remove the appender passed as parameter form the Logger.
    335:      * @param mixed $appender an appender name or a {@link LoggerAppender} instance.
    336:      */
    337:     public function removeAppender($appender) {
    338:         if($appender instanceof LoggerAppender) {
    339:             $appender->close();
    340:             unset($this->appenders[$appender->getName()]);
    341:         } else if (is_string($appender) and isset($this->appenders[$appender])) {
    342:             $this->appenders[$appender]->close();
    343:             unset($this->appenders[$appender]);
    344:         }
    345:     }
    346:
    347:     /**
    348:      * Returns the appenders linked to this logger as an array.
    349:      * @return array collection of appender names
    350:      */
    351:     public function getAllAppenders() {
    352:         return $this->appenders;
    353:     }
    354:
    355:     /**
    356:      * Returns a linked appender by name.
    357:      * @return LoggerAppender
    358:      */
    359:     public function getAppender($name) {
    360:         return $this->appenders[$name];
    361:     }
    362:
    363:     /**
    364:      * Sets the additivity flag.
    365:      * @param boolean $additive
    366:      */
    367:     public function setAdditivity($additive) {
    368:         $this->additive = (bool)$additive;
    369:     }
    370:
    371:     /**
    372:      * Returns the additivity flag.
    373:      * @return boolean
    374:      */
    375:     public function getAdditivity() {
    376:         return $this->additive;
    377:     }
    378:
    379:     /**
    380:      * Starting from this Logger, search the Logger hierarchy for a non-null level and return it.
    381:      * @see LoggerLevel
    382:      * @return LoggerLevel or null
    383:      */
    384:     public function getEffectiveLevel() {
    385:         for($logger = $this; $logger !== null; $logger = $logger->getParent()) {
    386:             if($logger->getLevel() !== null) {
    387:                 return $logger->getLevel();
    388:             }
    389:         }
    390:     }
    391:
    392:     /**
    393:      * Get the assigned Logger level.
    394:      * @return LoggerLevel The assigned level or null if none is assigned.
    395:      */
    396:     public function getLevel() {
    397:         return $this->level;
    398:     }
    399:
    400:     /**
    401:      * Set the Logger level.
    402:      *
    403:      * Use LoggerLevel::getLevelXXX() methods to get a LoggerLevel object, e.g.
    404:      * <code>$logger->setLevel(LoggerLevel::getLevelInfo());</code>
    405:      *
    406:      * @param LoggerLevel $level The level to set, or NULL to clear the logger level.
    407:      */
    408:     public function setLevel(LoggerLevel $level = null) {
    409:         $this->level = $level;
    410:     }
    411:
    412:     /**
    413:      * Checks whether an appender is attached to this logger instance.
    414:      *
    415:      * @param LoggerAppender $appender
    416:      * @return boolean
    417:      */
    418:     public function isAttached(LoggerAppender $appender) {
    419:         return isset($this->appenders[$appender->getName()]);
    420:     }
    421:
    422:     /**
    423:      * Sets the parent logger.
    424:      * @param Logger $logger
    425:      */
    426:     public function setParent(Logger $logger) {
    427:         $this->parent = $logger;
    428:     }
    429:
    430:     // ******************************************
    431:     // *** Static methods and properties      ***
    432:     // ******************************************
    433:
    434:     /** The logger hierarchy used by log4php. */
    435:     private static $hierarchy;
    436:
    437:     /** Inidicates if log4php has been initialized */
    438:     private static $initialized = false;
    439:
    440:     /**
    441:      * Returns the hierarchy used by this Logger.
    442:      *
    443:      * Caution: do not use this hierarchy unless you have called initialize().
    444:      * To get Loggers, use the Logger::getLogger and Logger::getRootLogger
    445:      * methods instead of operating on on the hierarchy directly.
    446:      *
    447:      * @return LoggerHierarchy
    448:      */
    449:     public static function getHierarchy() {
    450:         if(!isset(self::$hierarchy)) {
    451:             self::$hierarchy = new LoggerHierarchy(new LoggerRoot());
    452:         }
    453:         return self::$hierarchy;
    454:     }
    455:
    456:     /**
    457:      * Returns a Logger by name. If it does not exist, it will be created.
    458:      *
    459:      * @param string $name The logger name
    460:      * @return Logger
    461:      */
    462:     public static function getLogger($name) {
    463:         if(!self::isInitialized()) {
    464:             self::configure();
    465:         }
    466:         return self::getHierarchy()->getLogger($name);
    467:     }
    468:
    469:     /**
    470:      * Returns the Root Logger.
    471:      * @return LoggerRoot
    472:      */
    473:     public static function getRootLogger() {
    474:         if(!self::isInitialized()) {
    475:             self::configure();
    476:         }
    477:         return self::getHierarchy()->getRootLogger();
    478:     }
    479:
    480:     /**
    481:      * Clears all Logger definitions from the logger hierarchy.
    482:      * @return boolean
    483:      */
    484:     public static function clear() {
    485:         return self::getHierarchy()->clear();
    486:     }
    487:
    488:     /**
    489:      * Destroy configurations for logger definitions
    490:      */
    491:     public static function resetConfiguration() {
    492:         self::getHierarchy()->resetConfiguration();
    493:         self::getHierarchy()->clear(); // TODO: clear or not?
    494:         self::$initialized = false;
    495:     }
    496:
    497:     /**
    498:      * Safely close all appenders.
    499:      * @deprecated This is no longer necessary due the appenders shutdown via
    500:      * destructors.
    501:      */
    502:     public static function shutdown() {
    503:         return self::getHierarchy()->shutdown();
    504:     }
    505:
    506:     /**
    507:      * check if a given logger exists.
    508:      *
    509:      * @param string $name logger name
    510:      * @return boolean
    511:      */
    512:     public static function exists($name) {
    513:         return self::getHierarchy()->exists($name);
    514:     }
    515:
    516:     /**
    517:      * Returns an array this whole Logger instances.
    518:      * @see Logger
    519:      * @return array
    520:      */
    521:     public static function getCurrentLoggers() {
    522:         return self::getHierarchy()->getCurrentLoggers();
    523:     }
    524:
    525:     /**
    526:      * Configures log4php.
    527:      *
    528:      * This method needs to be called before the first logging event has
    529:      * occured. If this method is not called before then the default
    530:      * configuration will be used.
    531:      *
    532:      * @param string|array $configuration Either a path to the configuration
    533:      *   file, or a configuration array.
    534:      *
    535:      * @param string|LoggerConfigurator $configurator A custom
    536:      * configurator class: either a class name (string), or an object which
    537:      * implements the LoggerConfigurator interface. If left empty, the default
    538:      * configurator implementation will be used.
    539:      */
    540:     public static function configure($configuration = null, $configurator = null) {
    541:         self::resetConfiguration();
    542:         $configurator = self::getConfigurator($configurator);
    543:         $configurator->configure(self::getHierarchy(), $configuration);
    544:         self::$initialized = true;
    545:     }
    546:
    547:     /**
    548:      * Creates a logger configurator instance based on the provided
    549:      * configurator class. If no class is given, returns an instance of
    550:      * the default configurator.
    551:      *
    552:      * @param string|LoggerConfigurator $configurator The configurator class
    553:      * or LoggerConfigurator instance.
    554:      */
    555:     private static function getConfigurator($configurator = null) {
    556:         if ($configurator === null) {
    557:             return new LoggerConfiguratorDefault();
    558:         }
    559:
    560:         if (is_object($configurator)) {
    561:             if ($configurator instanceof LoggerConfigurator) {
    562:                 return $configurator;
    563:             } else {
    564:                 trigger_error("log4php: Given configurator object [$configurator] does not implement the LoggerConfigurator interface. Reverting to default configurator.", E_USER_WARNING);
    565:                 return new LoggerConfiguratorDefault();
    566:             }
    567:         }
    568:
    569:         if (is_string($configurator)) {
    570:             if (!class_exists($configurator)) {
    571:                 trigger_error("log4php: Specified configurator class [$configurator] does not exist. Reverting to default configurator.", E_USER_WARNING);
    572:                 return new LoggerConfiguratorDefault();
    573:             }
    574:
    575:             $instance = new $configurator();
    576:
    577:             if (!($instance instanceof LoggerConfigurator)) {
    578:                 trigger_error("log4php: Specified configurator class [$configurator] does not implement the LoggerConfigurator interface. Reverting to default configurator.", E_USER_WARNING);
    579:                 return new LoggerConfiguratorDefault();
    580:             }
    581:
    582:             return $instance;
    583:         }
    584:
    585:         trigger_error("log4php: Invalid configurator specified. Expected either a string or a LoggerConfigurator instance. Reverting to default configurator.", E_USER_WARNING);
    586:         return new LoggerConfiguratorDefault();
    587:     }
    588:
    589:     /**
    590:      * Returns true if the log4php framework has been initialized.
    591:      * @return boolean
    592:      */
    593:     private static function isInitialized() {
    594:         return self::$initialized;
    595:     }
    596: }
    597: