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.spi.Filter; 21 import org.apache.log4j.spi.ErrorHandler; 22 import org.apache.log4j.spi.OptionHandler; 23 import org.apache.log4j.spi.LoggingEvent; 24 import org.apache.log4j.helpers.OnlyOnceErrorHandler; 25 import org.apache.log4j.helpers.LogLog; 26 27 28 /** 29 * Abstract superclass of the other appenders in the package. 30 * 31 * This class provides the code for common functionality, such as 32 * support for threshold filtering and support for general filters. 33 * 34 * @since 0.8.1 35 * @author Ceki Gülcü 36 * */ 37 public abstract class AppenderSkeleton implements Appender, OptionHandler { 38 39 /** The layout variable does not need to be set if the appender 40 implementation has its own layout. */ 41 protected Layout layout; 42 43 /** Appenders are named. */ 44 protected String name; 45 46 /** 47 There is no level threshold filtering by default. */ 48 protected Priority threshold; 49 50 /** 51 It is assumed and enforced that errorHandler is never null. 52 */ 53 protected ErrorHandler errorHandler = new OnlyOnceErrorHandler(); 54 55 /** The first filter in the filter chain. Set to <code>null</code> 56 initially. */ 57 protected Filter headFilter; 58 /** The last filter in the filter chain. */ 59 protected Filter tailFilter; 60 61 /** 62 Is this appender closed? 63 */ 64 protected boolean closed = false; 65 66 /** 67 * Create new instance. 68 */ 69 public AppenderSkeleton() { 70 super(); 71 } 72 73 /** 74 * Create new instance. 75 * Provided for compatibility with log4j 1.3. 76 * 77 * @param isActive true if appender is ready for use upon construction. 78 * Not used in log4j 1.2.x. 79 * @since 1.2.15 80 */ 81 protected AppenderSkeleton(final boolean isActive) { 82 super(); 83 } 84 85 86 87 /** 88 Derived appenders should override this method if option structure 89 requires it. */ 90 public 91 void activateOptions() { 92 } 93 94 95 /** 96 Add a filter to end of the filter list. 97 98 @since 0.9.0 99 */ 100 public 101 void addFilter(Filter newFilter) { 102 if(headFilter == null) { 103 headFilter = tailFilter = newFilter; 104 } else { 105 tailFilter.setNext(newFilter); 106 tailFilter = newFilter; 107 } 108 } 109 110 /** 111 Subclasses of <code>AppenderSkeleton</code> should implement this 112 method to perform actual logging. See also {@link #doAppend 113 AppenderSkeleton.doAppend} method. 114 115 @since 0.9.0 116 */ 117 abstract 118 protected 119 void append(LoggingEvent event); 120 121 122 /** 123 Clear the filters chain. 124 125 @since 0.9.0 */ 126 public 127 void clearFilters() { 128 headFilter = tailFilter = null; 129 } 130 131 /** 132 Finalize this appender by calling the derived class' 133 <code>close</code> method. 134 135 @since 0.8.4 */ 136 public 137 void finalize() { 138 // An appender might be closed then garbage collected. There is no 139 // point in closing twice. 140 if(this.closed) 141 return; 142 143 LogLog.debug("Finalizing appender named ["+name+"]."); 144 close(); 145 } 146 147 148 /** 149 Return the currently set {@link ErrorHandler} for this 150 Appender. 151 152 @since 0.9.0 */ 153 public 154 ErrorHandler getErrorHandler() { 155 return this.errorHandler; 156 } 157 158 159 /** 160 Returns the head Filter. 161 162 @since 1.1 163 */ 164 public 165 Filter getFilter() { 166 return headFilter; 167 } 168 169 /** 170 Return the first filter in the filter chain for this 171 Appender. The return value may be <code>null</code> if no is 172 filter is set. 173 174 */ 175 public 176 final 177 Filter getFirstFilter() { 178 return headFilter; 179 } 180 181 /** 182 Returns the layout of this appender. The value may be null. 183 */ 184 public 185 Layout getLayout() { 186 return layout; 187 } 188 189 190 /** 191 Returns the name of this appender. 192 @return name, may be null. 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 }