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;
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;
public AppenderControl(final Appender appender, final Level level, final Filter filter) {
super(filter);
this.appender = appender;
this.appenderName = appender.getName();
this.level = level;
this.intLevel = level == null ? Level.ALL.intLevel() : level.intLevel();
start();
}
public String getAppenderName() {
return appenderName;
}
public Appender getAppender() {
return appender;
}
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 ex) {
handleAppenderError(event, ex);
} catch (final Exception ex) {
handleAppenderError(event, new AppenderLoggingException(ex));
}
}
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;
}
}
@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() + "]";
}
}