package ch.qos.logback.core.rolling;
import static ch.qos.logback.core.CoreConstants.CODES_URL;
import static ch.qos.logback.core.CoreConstants.MORE_INFO_PREFIX;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.FileAppender;
import ch.qos.logback.core.rolling.helper.CompressionMode;
import ch.qos.logback.core.rolling.helper.FileNamePattern;
import ch.qos.logback.core.util.ContextUtil;
public class RollingFileAppender<E> extends FileAppender<E> {
File currentlyActiveFile;
TriggeringPolicy<E> triggeringPolicy;
RollingPolicy rollingPolicy;
static private String RFA_NO_TP_URL = CODES_URL + "#rfa_no_tp";
static private String RFA_NO_RP_URL = CODES_URL + "#rfa_no_rp";
static private String COLLISION_URL = CODES_URL + "#rfa_collision";
static private String RFA_LATE_FILE_URL = CODES_URL + "#rfa_file_after";
public void start() {
if (triggeringPolicy == null) {
addWarn("No TriggeringPolicy was set for the RollingFileAppender named " + getName());
addWarn(MORE_INFO_PREFIX + RFA_NO_TP_URL);
return;
}
if (!triggeringPolicy.isStarted()) {
addWarn("TriggeringPolicy has not started. RollingFileAppender will not start");
return;
}
if (checkForCollisionsInPreviousRollingFileAppenders()) {
addError("Collisions detected with FileAppender/RollingAppender instances defined earlier. Aborting.");
addError(MORE_INFO_PREFIX + COLLISION_WITH_EARLIER_APPENDER_URL);
return;
}
if (!append) {
addWarn("Append mode is mandatory for RollingFileAppender. Defaulting to append=true.");
append = true;
}
if (rollingPolicy == null) {
addError("No RollingPolicy was set for the RollingFileAppender named " + getName());
addError(MORE_INFO_PREFIX + RFA_NO_RP_URL);
return;
}
if (checkForFileAndPatternCollisions()) {
addError("File property collides with fileNamePattern. Aborting.");
addError(MORE_INFO_PREFIX + COLLISION_URL);
return;
}
if (isPrudent()) {
if (rawFileProperty() != null) {
addWarn("Setting \"File\" property to null on account of prudent mode");
setFile(null);
}
if (rollingPolicy.getCompressionMode() != CompressionMode.NONE) {
addError("Compression is not supported in prudent mode. Aborting");
return;
}
}
currentlyActiveFile = new File(getFile());
addInfo("Active log file name: " + getFile());
super.start();
}
private boolean checkForFileAndPatternCollisions() {
if (triggeringPolicy instanceof RollingPolicyBase) {
final RollingPolicyBase base = (RollingPolicyBase) triggeringPolicy;
final FileNamePattern fileNamePattern = base.fileNamePattern;
if (fileNamePattern != null && fileName != null) {
String regex = fileNamePattern.toRegex();
return fileName.matches(regex);
}
}
return false;
}
private boolean checkForCollisionsInPreviousRollingFileAppenders() {
boolean collisionResult = false;
if (triggeringPolicy instanceof RollingPolicyBase) {
final RollingPolicyBase base = (RollingPolicyBase) triggeringPolicy;
final FileNamePattern fileNamePattern = base.fileNamePattern;
boolean collisionsDetected = innerCheckForFileNamePatternCollisionInPreviousRFA(fileNamePattern);
if (collisionsDetected)
collisionResult = true;
}
return collisionResult;
}
private boolean innerCheckForFileNamePatternCollisionInPreviousRFA(FileNamePattern fileNamePattern) {
boolean collisionsDetected = false;
@SuppressWarnings("unchecked")
Map<String, FileNamePattern> map = (Map<String, FileNamePattern>) context.getObject(CoreConstants.RFA_FILENAME_PATTERN_COLLISION_MAP);
if (map == null) {
return collisionsDetected;
}
for (Entry<String, FileNamePattern> entry : map.entrySet()) {
if (fileNamePattern.equals(entry.getValue())) {
addErrorForCollision("FileNamePattern", entry.getValue().toString(), entry.getKey());
collisionsDetected = true;
}
}
if (name != null) {
map.put(getName(), fileNamePattern);
}
return collisionsDetected;
}
@Override
public void stop() {
super.stop();
if (rollingPolicy != null)
rollingPolicy.stop();
if (triggeringPolicy != null)
triggeringPolicy.stop();
Map<String, FileNamePattern> map = ContextUtil.getFilenamePatternCollisionMap(context);
if (map != null && getName() != null)
map.remove(getName());
}
@Override
public void setFile(String file) {
if (file != null && ((triggeringPolicy != null) || (rollingPolicy != null))) {
addError("File property must be set before any triggeringPolicy or rollingPolicy properties");
addError(MORE_INFO_PREFIX + RFA_LATE_FILE_URL);
}
super.setFile(file);
}
@Override
public String getFile() {
return rollingPolicy.getActiveFileName();
}
public void rollover() {
lock.lock();
try {
this.closeOutputStream();
attemptRollover();
attemptOpenFile();
} finally {
lock.unlock();
}
}
private void attemptOpenFile() {
try {
currentlyActiveFile = new File(rollingPolicy.getActiveFileName());
this.openFile(rollingPolicy.getActiveFileName());
} catch (IOException e) {
addError("setFile(" + fileName + ", false) call failed.", e);
}
}
private void attemptRollover() {
try {
rollingPolicy.rollover();
} catch (RolloverFailure rf) {
addWarn("RolloverFailure occurred. Deferring roll-over.");
this.append = true;
}
}
@Override
protected void subAppend(E event) {
synchronized (triggeringPolicy) {
if (triggeringPolicy.isTriggeringEvent(currentlyActiveFile, event)) {
rollover();
}
}
super.subAppend(event);
}
public RollingPolicy getRollingPolicy() {
return rollingPolicy;
}
public TriggeringPolicy<E> getTriggeringPolicy() {
return triggeringPolicy;
}
@SuppressWarnings("unchecked")
public void setRollingPolicy(RollingPolicy policy) {
rollingPolicy = policy;
if (rollingPolicy instanceof TriggeringPolicy) {
triggeringPolicy = (TriggeringPolicy<E>) policy;
}
}
public void setTriggeringPolicy(TriggeringPolicy<E> policy) {
triggeringPolicy = policy;
if (policy instanceof RollingPolicy) {
rollingPolicy = (RollingPolicy) policy;
}
}
}