      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:  * The internal representation of logging event.
     23:  *
     24:  * @version $Revision: 1382273 $
     25:  * @package log4php
     26:  */
     27: class LoggerLoggingEvent {
     28:
     29:     private static $startTime;
     30:
     31:     /**
     32:     * @var string Fully Qualified Class Name of the calling category class.
     33:     */
     34:     private $fqcn;
     35:
     36:     /**
     37:     * @var Logger reference
     38:     */
     39:     private $logger;
     40:
     41:     /**
     42:      * The category (logger) name.
     43:      * This field will be marked as private in future
     44:      * releases. Please do not access it directly.
     45:      * Use the {@link getLoggerName()} method instead.
     46:      * @deprecated
     47:      */
     48:     private $categoryName;
     49:
     50:     /**
     51:      * Level of the logging event.
     52:      * @var LoggerLevel
     53:      */
     54:     protected $level;
     55:
     56:     /**
     57:      * The nested diagnostic context (NDC) of logging event.
     58:      * @var string
     59:      */
     60:     private $ndc;
     61:
     62:     /**
     63:      * Have we tried to do an NDC lookup? If we did, there is no need
     64:      * to do it again.  Note that its value is always false when
     65:      * serialized. Thus, a receiving SocketNode will never use it's own
     66:      * (incorrect) NDC. See also writeObject method.
     67:      * @var boolean
     68:      */
     69:     private $ndcLookupRequired = true;
     70:
     71:     /**
     72:      * @var mixed The application supplied message of logging event.
     73:      */
     74:     private $message;
     75:
     76:     /**
     77:      * The application supplied message rendered through the log4php
     78:      * objet rendering mechanism. At present renderedMessage == message.
     79:      * @var string
     80:      */
     81:     private $renderedMessage;
     82:
     83:     /**
     84:      * The name of thread in which this logging event was generated.
     85:      * log4php saves here the process id via {@link PHP_MANUAL#getmypid getmypid()}
     86:      * @var mixed
     87:      */
     88:     private $threadName;
     89:
     90:     /**
     91:     * The number of seconds elapsed from 1/1/1970 until logging event
     92:     * was created plus microseconds if available.
     93:     * @var float
     94:     */
     95:     public $timeStamp;
     96:
     97:     /**
     98:     * @var LoggerLocationInfo Location information for the caller.
     99:     */
    100:     private $locationInfo;
    101:
    102:     /**
    103:      * @var LoggerThrowableInformation log4php internal representation of throwable
    104:      */
    105:     private $throwableInfo;
    106:
    107:     /**
    108:     * Instantiate a LoggingEvent from the supplied parameters.
    109:     *
    110:     * Except {@link $timeStamp} all the other fields of
    111:     * LoggerLoggingEvent are filled when actually needed.
    112:     *
    113:     * @param string $fqcn name of the caller class.
    114:     * @param mixed $logger The {@link Logger} category of this event or the logger name.
    115:     * @param LoggerLevel $level The level of this event.
    116:     * @param mixed $message The message of this event.
    117:     * @param integer $timeStamp the timestamp of this logging event.
    118:     * @param Exception $throwable The throwable associated with logging event
    119:     */
    120:     public function __construct($fqcn, $logger, LoggerLevel $level, $message, $timeStamp = null, $throwable = null) {
    121:         $this->fqcn = $fqcn;
    122:         if($logger instanceof Logger) {
    123:             $this->logger = $logger;
    124:             $this->categoryName = $logger->getName();
    125:         } else {
    126:             $this->categoryName = strval($logger);
    127:         }
    128:         $this->level = $level;
    129:         $this->message = $message;
    130:         if($timeStamp !== null && is_numeric($timeStamp)) {
    131:             $this->timeStamp = $timeStamp;
    132:         } else {
    133:             $this->timeStamp = microtime(true);
    134:         }
    135:
    136:         if ($throwable !== null && $throwable instanceof Exception) {
    137:             $this->throwableInfo = new LoggerThrowableInformation($throwable);
    138:         }
    139:     }
    140:
    141:     /**
    142:      * Returns the full qualified classname.
    143:      * TODO: PHP does contain namespaces in 5.3. Those should be returned too,
    144:      */
    145:      public function getFullQualifiedClassname() {
    146:          return $this->fqcn;
    147:      }
    148:
    149:     /**
    150:      * Set the location information for this logging event. The collected
    151:      * information is cached for future use.
    152:      *
    153:      * <p>This method uses {@link PHP_MANUAL#debug_backtrace debug_backtrace()} function (if exists)
    154:      * to collect informations about caller.</p>
    155:      * <p>It only recognize informations generated by {@link Logger} and its subclasses.</p>
    156:      * @return LoggerLocationInfo
    157:      */
    158:     public function getLocationInformation() {
    159:         if($this->locationInfo === null) {
    160:
    161:             $locationInfo = array();
    162:             $trace = debug_backtrace();
    163:             $prevHop = null;
    164:             // make a downsearch to identify the caller
    165:             $hop = array_pop($trace);
    166:             while($hop !== null) {
    167:                 if(isset($hop['class'])) {
    168:                     // we are sometimes in functions = no class available: avoid php warning here
    169:                     $className = strtolower($hop['class']);
    170:                     if(!empty($className) and ($className == 'logger' or
    171:                         strtolower(get_parent_class($className)) == 'logger')) {
    172:                         $locationInfo['line'] = $hop['line'];
    173:                         $locationInfo['file'] = $hop['file'];
    174:                         break;
    175:                     }
    176:                 }
    177:                 $prevHop = $hop;
    178:                 $hop = array_pop($trace);
    179:             }
    180:             $locationInfo['class'] = isset($prevHop['class']) ? $prevHop['class'] : 'main';
    181:             if(isset($prevHop['function']) and
    182:                 $prevHop['function'] !== 'include' and
    183:                 $prevHop['function'] !== 'include_once' and
    184:                 $prevHop['function'] !== 'require' and
    185:                 $prevHop['function'] !== 'require_once') {
    186:
    187:                 $locationInfo['function'] = $prevHop['function'];
    188:             } else {
    189:                 $locationInfo['function'] = 'main';
    190:             }
    191:
    192:             $this->locationInfo = new LoggerLocationInfo($locationInfo, $this->fqcn);
    193:         }
    194:         return $this->locationInfo;
    195:     }
    196:
    197:     /**
    198:      * Return the level of this event. Use this form instead of directly
    199:      * accessing the {@link $level} field.
    200:      * @return LoggerLevel
    201:      */
    202:     public function getLevel() {
    203:         return $this->level;
    204:     }
    205:
    206:     /**
    207:      * Returns the logger which created the event.
    208:      * @return Logger
    209:      */
    210:     public function getLogger() {
    211:         return $this->logger;
    212:     }
    213:
    214:     /**
    215:      * Return the name of the logger. Use this form instead of directly
    216:      * accessing the {@link $categoryName} field.
    217:      * @return string
    218:      */
    219:     public function getLoggerName() {
    220:         return $this->categoryName;
    221:     }
    222:
    223:     /**
    224:      * Return the message for this logging event.
    225:      * @return mixed
    226:      */
    227:     public function getMessage() {
    228:         return $this->message;
    229:     }
    230:
    231:     /**
    232:      * This method returns the NDC for this event. It will return the
    233:      * correct content even if the event was generated in a different
    234:      * thread or even on a different machine. The {@link LoggerNDC::get()} method
    235:      * should <b>never</b> be called directly.
    236:      * @return string
    237:      */
    238:     public function getNDC() {
    239:         if($this->ndcLookupRequired) {
    240:             $this->ndcLookupRequired = false;
    241:             $this->ndc = LoggerNDC::get();
    242:         }
    243:         return $this->ndc;
    244:     }
    245:
    246:     /**
    247:      * Returns the the context corresponding to the <code>key</code>
    248:      * parameter.
    249:      * @return string
    250:      */
    251:     public function getMDC($key) {
    252:         return LoggerMDC::get($key);
    253:     }
    254:
    255:     /**
    256:      * Returns the entire MDC context.
    257:      * @return array
    258:      */
    259:     public function getMDCMap () {
    260:         return LoggerMDC::getMap();
    261:     }
    262:
    263:     /**
    264:      * Render message.
    265:      * @return string
    266:      */
    267:     public function getRenderedMessage() {
    268:         if($this->renderedMessage === null and $this->message !== null) {
    269:             if(is_string($this->message)) {
    270:                 $this->renderedMessage = $this->message;
    271:             } else {
    272:                 $rendererMap = Logger::getHierarchy()->getRendererMap();
    273:                 $this->renderedMessage= $rendererMap->findAndRender($this->message);
    274:             }
    275:         }
    276:         return $this->renderedMessage;
    277:     }
    278:
    279:     /**
    280:      * Returns the time when the application started, as a UNIX timestamp
    281:      * with microseconds.
    282:      * @return float
    283:      */
    284:     public static function getStartTime() {
    285:         if(!isset(self::$startTime)) {
    286:             self::$startTime = microtime(true);
    287:         }
    288:         return self::$startTime;
    289:     }
    290:
    291:     /**
    292:      * @return float
    293:      */
    294:     public function getTimeStamp() {
    295:         return $this->timeStamp;
    296:     }
    297:
    298:     /**
    299:      * Returns the time in seconds passed from the beginning of execution to
    300:      * the time the event was constructed.
    301:      *
    302:      * @return float Seconds with microseconds in decimals.
    303:      */
    304:     public function getRelativeTime() {
    305:         return $this->timeStamp - self::$startTime;
    306:     }
    307:
    308:     /**
    309:      * Returns the time in milliseconds passed from the beginning of execution
    310:      * to the time the event was constructed.
    311:      *
    312:      * @deprecated This method has been replaced by getRelativeTime which
    313:      *      does not perform unneccesary multiplication and formatting.
    314:      *
    315:      * @return integer
    316:      */
    317:     public function getTime() {
    318:         $eventTime = $this->getTimeStamp();
    319:         $eventStartTime = LoggerLoggingEvent::getStartTime();
    320:         return number_format(($eventTime - $eventStartTime) * 1000, 0, '', '');
    321:     }
    322:
    323:     /**
    324:      * @return mixed
    325:      */
    326:     public function getThreadName() {
    327:         if ($this->threadName === null) {
    328:             $this->threadName = (string)getmypid();
    329:         }
    330:         return $this->threadName;
    331:     }
    332:
    333:     /**
    334:      * @return mixed LoggerThrowableInformation
    335:      */
    336:     public function getThrowableInformation() {
    337:         return $this->throwableInfo;
    338:     }
    339:
    340:     /**
    341:      * Serialize this object
    342:      * @return string
    343:      */
    344:     public function toString() {
    345:         serialize($this);
    346:     }
    347:
    348:     /**
    349:      * Avoid serialization of the {@link $logger} object
    350:      */
    351:     public function __sleep() {
    352:         return array(
    353:             'fqcn',
    354:             'categoryName',
    355:             'level',
    356:             'ndc',
    357:             'ndcLookupRequired',
    358:             'message',
    359:             'renderedMessage',
    360:             'threadName',
    361:             'timeStamp',
    362:             'locationInfo',
    363:         );
    364:     }
    365:
    366: }
    367:
    368: LoggerLoggingEvent::getStartTime();
    369: