1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
140
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
263
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 }