001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements. See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache license, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License. You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the license for the specific language governing permissions and
015     * limitations under the license.
016     */
017    package org.apache.logging.log4j.core.config;
018    
019    import java.io.Serializable;
020    
021    import org.apache.logging.log4j.Level;
022    import org.apache.logging.log4j.core.Appender;
023    import org.apache.logging.log4j.core.Filter;
024    import org.apache.logging.log4j.core.LogEvent;
025    import org.apache.logging.log4j.core.appender.AppenderRuntimeException;
026    import org.apache.logging.log4j.core.filter.AbstractFilterable;
027    import org.apache.logging.log4j.core.filter.Filterable;
028    
029    /**
030     * Wraps an {@link Appender} with details an appender implementation shouldn't need to know about.
031     * @param <T> The appender's Serializable type.
032     */
033    public class AppenderControl<T extends Serializable> extends AbstractFilterable {
034    
035        private final ThreadLocal<AppenderControl<T>> recursive = new ThreadLocal<AppenderControl<T>>();
036    
037        private final Appender<T> appender;
038    
039        private final Level level;
040    
041        private final int intLevel;
042    
043        /**
044         * Constructor.
045         * @param appender The target Appender.
046         * @param level the Level to filter on.
047         * @param filter the Filter(s) to apply.
048         */
049        public AppenderControl(final Appender<T> appender, final Level level, final Filter filter) {
050            super(filter);
051            this.appender = appender;
052            this.level = level;
053            this.intLevel = level == null ? Level.ALL.intLevel() : level.intLevel();
054            startFilter();
055        }
056    
057        /**
058         * Returns the Appender.
059         * @return the Appender.
060         */
061        public Appender<T> getAppender() {
062            return appender;
063        }
064    
065        /**
066         * Call the appender.
067         * @param event The event to process.
068         */
069        public void callAppender(final LogEvent event) {
070            if (getFilter() != null) {
071                final Filter.Result r = getFilter().filter(event);
072                if (r == Filter.Result.DENY) {
073                    return;
074                }
075            }
076            if (level != null) {
077                if (intLevel < event.getLevel().intLevel()) {
078                    return;
079                }
080            }
081            if (recursive.get() != null) {
082                appender.getHandler().error("Recursive call to appender " + appender.getName());
083                return;
084            }
085            try {
086                recursive.set(this);
087    
088                if (!appender.isStarted()) {
089                    appender.getHandler().error("Attempted to append to non-started appender " + appender.getName());
090    
091                    if (!appender.isExceptionSuppressed()) {
092                        throw new AppenderRuntimeException(
093                            "Attempted to append to non-started appender " + appender.getName());
094                    }
095                }
096    
097                if (appender instanceof Filterable && ((Filterable) appender).isFiltered(event)) {
098                    return;
099                }
100    
101                try {
102                    appender.append(event);
103                } catch (final RuntimeException ex) {
104                    appender.getHandler().error("An exception occurred processing Appender " + appender.getName(), ex);
105                    if (!appender.isExceptionSuppressed()) {
106                        throw ex;
107                    }
108                } catch (final Exception ex) {
109                    appender.getHandler().error("An exception occurred processing Appender " + appender.getName(), ex);
110                    if (!appender.isExceptionSuppressed()) {
111                        throw new AppenderRuntimeException(ex);
112                    }
113                }
114            } finally {
115                recursive.set(null);
116            }
117        }
118    
119    }