View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.log4j;
    19
    20  import org.apache.log4j.Layout;
    21  import org.apache.log4j.spi.Filter;
    22  import org.apache.log4j.spi.ErrorHandler;
    23  import org.apache.log4j.spi.OptionHandler;
    24  import org.apache.log4j.spi.LoggingEvent;
    25  import org.apache.log4j.helpers.OnlyOnceErrorHandler;
    26  import org.apache.log4j.helpers.LogLog;
    27
    28
    29  /***
    30   * Abstract superclass of the other appenders in the package.
    31   *
    32   *  This class provides the code for common functionality, such as
    33   *  support for threshold filtering and support for general filters.
    34   *
    35   * @since 0.8.1
    36   * @author Ceki G&uuml;lc&uuml;
    37   * */
    38  public abstract class AppenderSkeleton implements Appender, OptionHandler {
    39
    40    /*** The layout variable does not need to be set if the appender
    41        implementation has its own layout. */
    42    protected Layout layout;
    43
    44    /*** Appenders are named. */
    45    protected String name;
    46
    47    /***
    48       There is no level threshold filtering by default.  */
    49    protected Priority threshold;
    50
    51    /***
    52        It is assumed and enforced that errorHandler is never null.
    53    */
    54    protected ErrorHandler errorHandler = new OnlyOnceErrorHandler();
    55
    56    /*** The first filter in the filter chain. Set to <code>null</code>
    57        initially. */
    58    protected Filter headFilter;
    59    /*** The last filter in the filter chain. */
    60    protected Filter tailFilter;
    61
    62    /***
    63       Is this appender closed?
    64     */
    65    protected boolean closed = false;
    66
    67      /***
    68       * Create new instance.
    69       */
    70      public AppenderSkeleton() {
    71          super();
    72      }
    73
    74      /***
    75       * Create new instance.
    76       * Provided for compatibility with log4j 1.3.
    77       *
    78       * @param isActive true if appender is ready for use upon construction.
    79       *                 Not used in log4j 1.2.x.
    80       * @since 1.2.15
    81       */
    82      protected AppenderSkeleton(final boolean isActive) {
    83          super();
    84      }
    85
    86
    87
    88    /***
    89       Derived appenders should override this method if option structure
    90       requires it.  */
    91    public
    92    void activateOptions() {
    93    }
    94
    95
    96    /***
    97       Add a filter to end of the filter list.
    98
    99       @since 0.9.0
    100    */
    101   public
    102   void addFilter(Filter newFilter) {
    103     if(headFilter == null) {
    104       headFilter = tailFilter = newFilter;
    105     } else {
    106       tailFilter.setNext(newFilter);
    107       tailFilter = newFilter;
    108     }
    109   }
    110
    111   /***
    112      Subclasses of <code>AppenderSkeleton</code> should implement this
    113      method to perform actual logging. See also {@link #doAppend
    114      AppenderSkeleton.doAppend} method.
    115
    116      @since 0.9.0
    117   */
    118   abstract
    119   protected
    120   void append(LoggingEvent event);
    121
    122
    123   /***
    124      Clear the filters chain.
    125
    126      @since 0.9.0 */
    127   public
    128   void clearFilters() {
    129     headFilter = tailFilter = null;
    130   }
    131
    132   /***
    133      Finalize this appender by calling the derived class'
    134      <code>close</code> method.
    135
    136      @since 0.8.4 */
    137   public
    138   void finalize() {
    139     // An appender might be closed then garbage collected. There is no
    140     // point in closing twice.
    141     if(this.closed)
    142       return;
    143
    144     LogLog.debug("Finalizing appender named ["+name+"].");
    145     close();
    146   }
    147
    148
    149   /***
    150       Return the currently set {@link ErrorHandler} for this
    151       Appender.
    152
    153       @since 0.9.0 */
    154   public
    155   ErrorHandler getErrorHandler() {
    156     return this.errorHandler;
    157   }
    158
    159
    160   /***
    161      Returns the head Filter.
    162
    163      @since 1.1
    164   */
    165   public
    166   Filter getFilter() {
    167     return headFilter;
    168   }
    169
    170   /***
    171       Return the first filter in the filter chain for this
    172       Appender. The return value may be <code>null</code> if no is
    173       filter is set.
    174
    175   */
    176   public
    177   final
    178   Filter getFirstFilter() {
    179     return headFilter;
    180   }
    181
    182   /***
    183      Returns the layout of this appender. The value may be null.
    184   */
    185   public
    186   Layout getLayout() {
    187     return layout;
    188   }
    189
    190
    191   /***
    192      Returns the name of this FileAppender.
    193    */
    194   public
    195   final
    196   String getName() {
    197     return this.name;
    198   }
    199
    200   /***
    201      Returns this appenders threshold level. See the {@link
    202      #setThreshold} method for the meaning of this option.
    203
    204      @since 1.1 */
    205   public
    206   Priority getThreshold() {
    207     return threshold;
    208   }
    209
    210
    211   /***
    212      Check whether the message level is below the appender's
    213      threshold. If there is no threshold set, then the return value is
    214      always <code>true</code>.
    215
    216   */
    217   public
    218   boolean isAsSevereAsThreshold(Priority priority) {
    219     return ((threshold == null) || priority.isGreaterOrEqual(threshold));
    220   }
    221
    222
    223   /***
    224     * This method performs threshold checks and invokes filters before
    225     * delegating actual logging to the subclasses specific {@link
    226     * AppenderSkeleton#append} method.
    227     * */
    228   public
    229   synchronized
    230   void doAppend(LoggingEvent event) {
    231     if(closed) {
    232       LogLog.error("Attempted to append to closed appender named ["+name+"].");
    233       return;
    234     }
    235
    236     if(!isAsSevereAsThreshold(event.getLevel())) {
    237       return;
    238     }
    239
    240     Filter f = this.headFilter;
    241
    242     FILTER_LOOP:
    243     while(f != null) {
    244       switch(f.decide(event)) {
    245       case Filter.DENY: return;
    246       case Filter.ACCEPT: break FILTER_LOOP;
    247       case Filter.NEUTRAL: f = f.getNext();
    248       }
    249     }
    250
    251     this.append(event);
    252   }
    253
    254   /***
    255       Set the {@link ErrorHandler} for this Appender.
    256       @since 0.9.0
    257   */
    258   public
    259   synchronized
    260   void setErrorHandler(ErrorHandler eh) {
    261     if(eh == null) {
    262       // We do not throw exception here since the cause is probably a
    263       // bad config file.
    264       LogLog.warn("You have tried to set a null error-handler.");
    265     } else {
    266       this.errorHandler = eh;
    267     }
    268   }
    269
    270   /***
    271      Set the layout for this appender. Note that some appenders have
    272      their own (fixed) layouts or do not use one. For example, the
    273      {@link org.apache.log4j.net.SocketAppender} ignores the layout set
    274      here.
    275   */
    276   public
    277   void setLayout(Layout layout) {
    278     this.layout = layout;
    279   }
    280
    281
    282   /***
    283      Set the name of this Appender.
    284    */
    285   public
    286   void setName(String name) {
    287     this.name = name;
    288   }
    289
    290
    291   /***
    292      Set the threshold level. All log events with lower level
    293      than the threshold level are ignored by the appender.
    294
    295      <p>In configuration files this option is specified by setting the
    296      value of the <b>Threshold</b> option to a level
    297      string, such as "DEBUG", "INFO" and so on.
    298
    299      @since 0.8.3 */
    300   public
    301   void setThreshold(Priority threshold) {
    302     this.threshold = threshold;
    303   }
    304 }