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: