| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.log4j; |
| |
| import org.apache.log4j.Layout; |
| import org.apache.log4j.spi.Filter; |
| import org.apache.log4j.spi.ErrorHandler; |
| import org.apache.log4j.spi.OptionHandler; |
| import org.apache.log4j.spi.LoggingEvent; |
| import org.apache.log4j.helpers.OnlyOnceErrorHandler; |
| import org.apache.log4j.helpers.LogLog; |
| |
| |
| /** |
| * Abstract superclass of the other appenders in the package. |
| * |
| * This class provides the code for common functionality, such as |
| * support for threshold filtering and support for general filters. |
| * |
| * @since 0.8.1 |
| * @author Ceki Gülcü |
| * */ |
| public abstract class AppenderSkeleton implements Appender, OptionHandler { |
| |
| /** The layout variable does not need to be set if the appender |
| implementation has its own layout. */ |
| protected Layout layout; |
| |
| /** Appenders are named. */ |
| protected String name; |
| |
| /** |
| There is no level threshold filtering by default. */ |
| protected Priority threshold; |
| |
| /** |
| It is assumed and enforced that errorHandler is never null. |
| */ |
| protected ErrorHandler errorHandler = new OnlyOnceErrorHandler(); |
| |
| /** The first filter in the filter chain. Set to <code>null</code> |
| initially. */ |
| protected Filter headFilter; |
| /** The last filter in the filter chain. */ |
| protected Filter tailFilter; |
| |
| /** |
| Is this appender closed? |
| */ |
| protected boolean closed = false; |
| |
| /** |
| * Create new instance. |
| */ |
| public AppenderSkeleton() { |
| super(); |
| } |
| |
| /** |
| * Create new instance. |
| * Provided for compatibility with log4j 1.3. |
| * |
| * @param isActive true if appender is ready for use upon construction. |
| * Not used in log4j 1.2.x. |
| * @since 1.2.15 |
| */ |
| protected AppenderSkeleton(final boolean isActive) { |
| super(); |
| } |
| |
| |
| |
| /** |
| Derived appenders should override this method if option structure |
| requires it. */ |
| public |
| void activateOptions() { |
| } |
| |
| |
| /** |
| Add a filter to end of the filter list. |
| |
| @since 0.9.0 |
| */ |
| public |
| void addFilter(Filter newFilter) { |
| if(headFilter == null) { |
| headFilter = tailFilter = newFilter; |
| } else { |
| tailFilter.setNext(newFilter); |
| tailFilter = newFilter; |
| } |
| } |
| |
| /** |
| Subclasses of <code>AppenderSkeleton</code> should implement this |
| method to perform actual logging. See also {@link #doAppend |
| AppenderSkeleton.doAppend} method. |
| |
| @since 0.9.0 |
| */ |
| abstract |
| protected |
| void append(LoggingEvent event); |
| |
| |
| /** |
| Clear the filters chain. |
| |
| @since 0.9.0 */ |
| public |
| void clearFilters() { |
| headFilter = tailFilter = null; |
| } |
| |
| /** |
| Finalize this appender by calling the derived class' |
| <code>close</code> method. |
| |
| @since 0.8.4 */ |
| public |
| void finalize() { |
| // An appender might be closed then garbage collected. There is no |
| // point in closing twice. |
| if(this.closed) |
| return; |
| |
| LogLog.debug("Finalizing appender named ["+name+"]."); |
| close(); |
| } |
| |
| |
| /** |
| Return the currently set {@link ErrorHandler} for this |
| Appender. |
| |
| @since 0.9.0 */ |
| public |
| ErrorHandler getErrorHandler() { |
| return this.errorHandler; |
| } |
| |
| |
| /** |
| Returns the head Filter. |
| |
| @since 1.1 |
| */ |
| public |
| Filter getFilter() { |
| return headFilter; |
| } |
| |
| /** |
| Return the first filter in the filter chain for this |
| Appender. The return value may be <code>null</code> if no is |
| filter is set. |
| |
| */ |
| public |
| final |
| Filter getFirstFilter() { |
| return headFilter; |
| } |
| |
| /** |
| Returns the layout of this appender. The value may be null. |
| */ |
| public |
| Layout getLayout() { |
| return layout; |
| } |
| |
| |
| /** |
| Returns the name of this FileAppender. |
| */ |
| public |
| final |
| String getName() { |
| return this.name; |
| } |
| |
| /** |
| Returns this appenders threshold level. See the {@link |
| #setThreshold} method for the meaning of this option. |
| |
| @since 1.1 */ |
| public |
| Priority getThreshold() { |
| return threshold; |
| } |
| |
| |
| /** |
| Check whether the message level is below the appender's |
| threshold. If there is no threshold set, then the return value is |
| always <code>true</code>. |
| |
| */ |
| public |
| boolean isAsSevereAsThreshold(Priority priority) { |
| return ((threshold == null) || priority.isGreaterOrEqual(threshold)); |
| } |
| |
| |
| /** |
| * This method performs threshold checks and invokes filters before |
| * delegating actual logging to the subclasses specific {@link |
| * AppenderSkeleton#append} method. |
| * */ |
| public |
| synchronized |
| void doAppend(LoggingEvent event) { |
| if(closed) { |
| LogLog.error("Attempted to append to closed appender named ["+name+"]."); |
| return; |
| } |
| |
| if(!isAsSevereAsThreshold(event.getLevel())) { |
| return; |
| } |
| |
| Filter f = this.headFilter; |
| |
| FILTER_LOOP: |
| while(f != null) { |
| switch(f.decide(event)) { |
| case Filter.DENY: return; |
| case Filter.ACCEPT: break FILTER_LOOP; |
| case Filter.NEUTRAL: f = f.getNext(); |
| } |
| } |
| |
| this.append(event); |
| } |
| |
| /** |
| Set the {@link ErrorHandler} for this Appender. |
| @since 0.9.0 |
| */ |
| public |
| synchronized |
| void setErrorHandler(ErrorHandler eh) { |
| if(eh == null) { |
| // We do not throw exception here since the cause is probably a |
| // bad config file. |
| LogLog.warn("You have tried to set a null error-handler."); |
| } else { |
| this.errorHandler = eh; |
| } |
| } |
| |
| /** |
| Set the layout for this appender. Note that some appenders have |
| their own (fixed) layouts or do not use one. For example, the |
| {@link org.apache.log4j.net.SocketAppender} ignores the layout set |
| here. |
| */ |
| public |
| void setLayout(Layout layout) { |
| this.layout = layout; |
| } |
| |
| |
| /** |
| Set the name of this Appender. |
| */ |
| public |
| void setName(String name) { |
| this.name = name; |
| } |
| |
| |
| /** |
| Set the threshold level. All log events with lower level |
| than the threshold level are ignored by the appender. |
| |
| <p>In configuration files this option is specified by setting the |
| value of the <b>Threshold</b> option to a level |
| string, such as "DEBUG", "INFO" and so on. |
| |
| @since 0.8.3 */ |
| public |
| void setThreshold(Priority threshold) { |
| this.threshold = threshold; |
| } |
| } |