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ülcü 
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 }