| /* |
| * 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.logging.log4j.core.config; |
| |
| import java.util.Objects; |
| |
| import org.apache.logging.log4j.Level; |
| import org.apache.logging.log4j.core.Appender; |
| import org.apache.logging.log4j.core.Filter; |
| import org.apache.logging.log4j.core.LogEvent; |
| import org.apache.logging.log4j.core.appender.AppenderLoggingException; |
| import org.apache.logging.log4j.core.filter.AbstractFilterable; |
| import org.apache.logging.log4j.core.filter.Filterable; |
| import org.apache.logging.log4j.util.PerformanceSensitive; |
| |
| /** |
| * Wraps an {@link Appender} with details an appender implementation shouldn't need to know about. |
| */ |
| public class AppenderControl extends AbstractFilterable { |
| |
| private final ThreadLocal<AppenderControl> recursive = new ThreadLocal<>(); |
| private final Appender appender; |
| private final Level level; |
| private final int intLevel; |
| private final String appenderName; |
| |
| /** |
| * Constructor. |
| * |
| * @param appender The target Appender. |
| * @param level the Level to filter on. |
| * @param filter the Filter(s) to apply. |
| */ |
| public AppenderControl(final Appender appender, final Level level, final Filter filter) { |
| super(filter, null); |
| this.appender = appender; |
| this.appenderName = appender.getName(); |
| this.level = level; |
| this.intLevel = level == null ? Level.ALL.intLevel() : level.intLevel(); |
| start(); |
| } |
| |
| /** |
| * Returns the name the appender had when this AppenderControl was constructed. |
| * |
| * @return the appender name |
| */ |
| public String getAppenderName() { |
| return appenderName; |
| } |
| |
| /** |
| * Returns the Appender. |
| * |
| * @return the Appender. |
| */ |
| public Appender getAppender() { |
| return appender; |
| } |
| |
| /** |
| * Call the appender. |
| * |
| * @param event The event to process. |
| */ |
| public void callAppender(final LogEvent event) { |
| if (shouldSkip(event)) { |
| return; |
| } |
| callAppenderPreventRecursion(event); |
| } |
| |
| private boolean shouldSkip(final LogEvent event) { |
| return isFilteredByAppenderControl(event) || isFilteredByLevel(event) || isRecursiveCall(); |
| } |
| |
| @PerformanceSensitive |
| private boolean isFilteredByAppenderControl(final LogEvent event) { |
| final Filter filter = getFilter(); |
| return filter != null && Filter.Result.DENY == filter.filter(event); |
| } |
| |
| @PerformanceSensitive |
| private boolean isFilteredByLevel(final LogEvent event) { |
| return level != null && intLevel < event.getLevel().intLevel(); |
| } |
| |
| @PerformanceSensitive |
| private boolean isRecursiveCall() { |
| if (recursive.get() != null) { |
| appenderErrorHandlerMessage("Recursive call to appender "); |
| return true; |
| } |
| return false; |
| } |
| |
| private String appenderErrorHandlerMessage(final String prefix) { |
| final String result = createErrorMsg(prefix); |
| appender.getHandler().error(result); |
| return result; |
| } |
| |
| private void callAppenderPreventRecursion(final LogEvent event) { |
| try { |
| recursive.set(this); |
| callAppender0(event); |
| } finally { |
| recursive.set(null); |
| } |
| } |
| |
| private void callAppender0(final LogEvent event) { |
| ensureAppenderStarted(); |
| if (!isFilteredByAppender(event)) { |
| tryCallAppender(event); |
| } |
| } |
| |
| private void ensureAppenderStarted() { |
| if (!appender.isStarted()) { |
| handleError("Attempted to append to non-started appender "); |
| } |
| } |
| |
| private void handleError(final String prefix) { |
| final String msg = appenderErrorHandlerMessage(prefix); |
| if (!appender.ignoreExceptions()) { |
| throw new AppenderLoggingException(msg); |
| } |
| } |
| |
| private String createErrorMsg(final String prefix) { |
| return prefix + appender.getName(); |
| } |
| |
| private boolean isFilteredByAppender(final LogEvent event) { |
| return appender instanceof Filterable && ((Filterable) appender).isFiltered(event); |
| } |
| |
| private void tryCallAppender(final LogEvent event) { |
| try { |
| appender.append(event); |
| } catch (final RuntimeException error) { |
| handleAppenderError(event, error); |
| } catch (final Exception error) { |
| handleAppenderError(event, new AppenderLoggingException(error)); |
| } |
| } |
| |
| private void handleAppenderError(final LogEvent event, final RuntimeException ex) { |
| appender.getHandler().error(createErrorMsg("An exception occurred processing Appender "), event, ex); |
| if (!appender.ignoreExceptions()) { |
| throw ex; |
| } |
| } |
| |
| // AppenderControl is a helper object whose purpose is to make it |
| // easier for LoggerConfig to manage and invoke Appenders. |
| // LoggerConfig manages Appenders by their name. To facilitate this, |
| // two AppenderControl objects are considered equal if and only |
| // if they have the same appender name. |
| @Override |
| public boolean equals(final Object obj) { |
| if (obj == this) { |
| return true; |
| } |
| if (!(obj instanceof AppenderControl)) { |
| return false; |
| } |
| final AppenderControl other = (AppenderControl) obj; |
| return Objects.equals(appenderName, other.appenderName); |
| } |
| |
| @Override |
| public int hashCode() { |
| return appenderName.hashCode(); |
| } |
| |
| @Override |
| public String toString() { |
| return super.toString() + "[appender=" + appender + ", appenderName=" + appenderName + ", level=" + level |
| + ", intLevel=" + intLevel + ", recursive=" + recursive + ", filter=" + getFilter() + "]"; |
| } |
| } |