      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:  * Abstract class that defines output logs strategies.
     23:  *
     24:  * @version $Revision: 1374777 $
     25:  * @package log4php
     26:  */
     27: abstract class LoggerAppender extends LoggerConfigurable {
     28:
     29:     /**
     30:      * Set to true when the appender is closed. A closed appender will not
     31:      * accept any logging requests.
     32:      * @var boolean
     33:      */
     34:     protected $closed = false;
     35:
     36:     /**
     37:      * The first filter in the filter chain.
     38:      * @var LoggerFilter
     39:      */
     40:     protected $filter;
     41:
     42:     /**
     43:      * The appender's layout. Can be null if the appender does not use
     44:      * a layout.
     45:      * @var LoggerLayout
     46:      */
     47:     protected $layout;
     48:
     49:     /**
     50:      * Appender name. Used by other components to identify this appender.
     51:      * @var string
     52:      */
     53:     protected $name;
     54:
     55:     /**
     56:      * Appender threshold level. Events whose level is below the threshold
     57:      * will not be logged.
     58:      * @var LoggerLevel
     59:      */
     60:     protected $threshold;
     61:
     62:     /**
     63:      * Set to true if the appender requires a layout.
     64:      *
     65:      * True by default, appenders which do not use a layout should override
     66:      * this property to false.
     67:      *
     68:      * @var boolean
     69:      */
     70:     protected $requiresLayout = true;
     71:
     72:     /**
     73:      * Default constructor.
     74:      * @param string $name Appender name
     75:      */
     76:     public function __construct($name = '') {
     77:         $this->name = $name;
     78:
     79:         if ($this->requiresLayout) {
     80:             $this->layout = $this->getDefaultLayout();
     81:         }
     82:     }
     83:
     84:     public function __destruct() {
     85:         $this->close();
     86:     }
     87:
     88:     /**
     89:      * Returns the default layout for this appender. Can be overriden by
     90:      * derived appenders.
     91:      *
     92:      * @return LoggerLayout
     93:      */
     94:     public function getDefaultLayout() {
     95:         return new LoggerLayoutSimple();
     96:     }
     97:
     98:     /**
     99:      * Adds a filter to the end of the filter chain.
    100:      * @param LoggerFilter $filter add a new LoggerFilter
    101:      */
    102:     public function addFilter($filter) {
    103:         if($this->filter === null) {
    104:             $this->filter = $filter;
    105:         } else {
    106:             $this->filter->addNext($filter);
    107:         }
    108:     }
    109:
    110:     /**
    111:      * Clears the filter chain by removing all the filters in it.
    112:      */
    113:     public function clearFilters() {
    114:         $this->filter = null;
    115:     }
    116:
    117:     /**
    118:      * Returns the first filter in the filter chain.
    119:      * The return value may be <i>null</i> if no is filter is set.
    120:      * @return LoggerFilter
    121:      */
    122:     public function getFilter() {
    123:         return $this->filter;
    124:     }
    125:
    126:     /**
    127:      * Returns the first filter in the filter chain.
    128:      * The return value may be <i>null</i> if no is filter is set.
    129:      * @return LoggerFilter
    130:      */
    131:     public function getFirstFilter() {
    132:         return $this->filter;
    133:     }
    134:
    135:     /**
    136:      * Performs threshold checks and invokes filters before delegating logging
    137:      * to the subclass' specific <i>append()</i> method.
    138:      * @see LoggerAppender::append()
    139:      * @param LoggerLoggingEvent $event
    140:      */
    141:     public function doAppend(LoggerLoggingEvent $event) {
    142:         if($this->closed) {
    143:             return;
    144:         }
    145:
    146:         if(!$this->isAsSevereAsThreshold($event->getLevel())) {
    147:             return;
    148:         }
    149:
    150:         $filter = $this->getFirstFilter();
    151:         while($filter !== null) {
    152:             switch ($filter->decide($event)) {
    153:                 case LoggerFilter::DENY: return;
    154:                 case LoggerFilter::ACCEPT: return $this->append($event);
    155:                 case LoggerFilter::NEUTRAL: $filter = $filter->getNext();
    156:             }
    157:         }
    158:         $this->append($event);
    159:     }
    160:
    161:     /**
    162:      * Sets the appender layout.
    163:      * @param LoggerLayout $layout
    164:      */
    165:     public function setLayout($layout) {
    166:         if($this->requiresLayout()) {
    167:             $this->layout = $layout;
    168:         }
    169:     }
    170:
    171:     /**
    172:      * Returns the appender layout.
    173:      * @return LoggerLayout
    174:      */
    175:     public function getLayout() {
    176:         return $this->layout;
    177:     }
    178:
    179:     /**
    180:      * Configurators call this method to determine if the appender
    181:      * requires a layout.
    182:      *
    183:      * <p>If this method returns <i>true</i>, meaning that layout is required,
    184:      * then the configurator will configure a layout using the configuration
    185:      * information at its disposal.  If this method returns <i>false</i>,
    186:      * meaning that a layout is not required, then layout configuration will be
    187:      * skipped even if there is available layout configuration
    188:      * information at the disposal of the configurator.</p>
    189:      *
    190:      * <p>In the rather exceptional case, where the appender
    191:      * implementation admits a layout but can also work without it, then
    192:      * the appender should return <i>true</i>.</p>
    193:      *
    194:      * @return boolean
    195:      */
    196:     public function requiresLayout() {
    197:         return $this->requiresLayout;
    198:     }
    199:
    200:     /**
    201:      * Retruns the appender name.
    202:      * @return string
    203:      */
    204:     public function getName() {
    205:         return $this->name;
    206:     }
    207:
    208:     /**
    209:      * Sets the appender name.
    210:      * @param string $name
    211:      */
    212:     public function setName($name) {
    213:         $this->name = $name;
    214:     }
    215:
    216:     /**
    217:      * Returns the appender's threshold level.
    218:      * @return LoggerLevel
    219:      */
    220:     public function getThreshold() {
    221:         return $this->threshold;
    222:     }
    223:
    224:     /**
    225:      * Sets the appender threshold.
    226:      *
    227:      * @param LoggerLevel|string $threshold Either a {@link LoggerLevel}
    228:      *   object or a string equivalent.
    229:      * @see LoggerOptionConverter::toLevel()
    230:      */
    231:     public function setThreshold($threshold) {
    232:         $this->setLevel('threshold', $threshold);
    233:     }
    234:
    235:     /**
    236:      * Checks whether the message level is below the appender's threshold.
    237:      *
    238:      * If there is no threshold set, then the return value is always <i>true</i>.
    239:      *
    240:      * @param LoggerLevel $level
    241:      * @return boolean Returns true if level is greater or equal than
    242:      *   threshold, or if the threshold is not set. Otherwise returns false.
    243:      */
    244:     public function isAsSevereAsThreshold($level) {
    245:         if($this->threshold === null) {
    246:             return true;
    247:         }
    248:         return $level->isGreaterOrEqual($this->getThreshold());
    249:     }
    250:
    251:     /**
    252:      * Prepares the appender for logging.
    253:      *
    254:      * Derived appenders should override this method if option structure
    255:      * requires it.
    256:      */
    257:     public function activateOptions() {
    258:         $this->closed = false;
    259:     }
    260:
    261:     /**
    262:      * Forwards the logging event to the destination.
    263:      *
    264:      * Derived appenders should implement this method to perform actual logging.
    265:      *
    266:      * @param LoggerLoggingEvent $event
    267:      */
    268:     abstract protected function append(LoggerLoggingEvent $event);
    269:
    270:     /**
    271:      * Releases any resources allocated by the appender.
    272:      *
    273:      * Derived appenders should override this method to perform proper closing
    274:      * procedures.
    275:      */
    276:     public function close() {
    277:         $this->closed = true;
    278:     }
    279:
    280:     /** Triggers a warning for this logger with the given message. */
    281:     protected function warn($message) {
    282:         $id = get_class($this) . (empty($this->name) ? '' : ":{$this->name}");
    283:         trigger_error("log4php: [$id]: $message", E_USER_WARNING);
    284:     }
    285:
    286: }
    287: