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: