001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. Copyright (C) 1999-2015, QOS.ch. All rights 003 * reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under either the terms of the Eclipse Public License 006 * v1.0 as published by the Eclipse Foundation 007 * 008 * or (per the licensee's choosing) 009 * 010 * under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. 011 */ 012package ch.qos.logback.core.rolling; 013 014import static ch.qos.logback.core.CoreConstants.MANUAL_URL_PREFIX; 015 016import java.io.File; 017import java.time.Instant; 018import java.util.Date; 019 020import ch.qos.logback.core.CoreConstants; 021import ch.qos.logback.core.joran.spi.NoAutoStart; 022import ch.qos.logback.core.rolling.helper.ArchiveRemover; 023import ch.qos.logback.core.rolling.helper.CompressionMode; 024import ch.qos.logback.core.rolling.helper.FileFilterUtil; 025import ch.qos.logback.core.rolling.helper.SizeAndTimeBasedArchiveRemover; 026import ch.qos.logback.core.util.Duration; 027import ch.qos.logback.core.util.FileSize; 028import ch.qos.logback.core.util.DefaultInvocationGate; 029import ch.qos.logback.core.util.InvocationGate; 030import ch.qos.logback.core.util.SimpleInvocationGate; 031 032/** 033 * This class implement {@link TimeBasedFileNamingAndTriggeringPolicy} 034 * interface extending {@link TimeBasedFileNamingAndTriggeringPolicyBase}. This class is intended to be nested 035 * within a {@link SizeAndTimeBasedFNATP} instance. However, it can also be instantiated directly for testing purposes. 036 * 037 * @author Ceki Gülcü 038 * 039 * @param <E> 040 */ 041@NoAutoStart 042public class SizeAndTimeBasedFNATP<E> extends TimeBasedFileNamingAndTriggeringPolicyBase<E> { 043 044 enum Usage { 045 EMBEDDED, DIRECT 046 } 047 048 volatile int currentPeriodsCounter = 0; 049 FileSize maxFileSize; 050 051 Duration checkIncrement = null; 052 053 static String MISSING_INT_TOKEN = "Missing integer token, that is %i, in FileNamePattern ["; 054 static String MISSING_DATE_TOKEN = "Missing date token, that is %d, in FileNamePattern ["; 055 056 private final Usage usage; 057 058 InvocationGate invocationGate = new SimpleInvocationGate(); 059 060 public SizeAndTimeBasedFNATP() { 061 this(Usage.DIRECT); 062 } 063 064 public SizeAndTimeBasedFNATP(Usage usage) { 065 this.usage = usage; 066 } 067 068 @Override 069 public void start() { 070 // we depend on certain fields having been initialized in super class 071 super.start(); 072 073 if (usage == Usage.DIRECT) { 074 addWarn(CoreConstants.SIZE_AND_TIME_BASED_FNATP_IS_DEPRECATED); 075 addWarn("For more information see " + MANUAL_URL_PREFIX + "appenders.html#SizeAndTimeBasedRollingPolicy"); 076 } 077 078 if (!super.isErrorFree()) 079 return; 080 081 if (maxFileSize == null) { 082 addError("maxFileSize property is mandatory."); 083 withErrors(); 084 } 085 086 if (checkIncrement != null) 087 invocationGate = new SimpleInvocationGate(checkIncrement); 088 089 if (!validateDateAndIntegerTokens()) { 090 withErrors(); 091 return; 092 } 093 094 archiveRemover = createArchiveRemover(); 095 archiveRemover.setContext(context); 096 097 // we need to get the correct value of currentPeriodsCounter. 098 // usually the value is 0, unless the appender or the application 099 // is stopped and restarted within the same period 100 String regex = tbrp.fileNamePattern.toRegexForFixedDate(dateInCurrentPeriod); 101 String stemRegex = FileFilterUtil.afterLastSlash(regex); 102 103 computeCurrentPeriodsHighestCounterValue(stemRegex); 104 105 if (isErrorFree()) { 106 started = true; 107 } 108 } 109 110 private boolean validateDateAndIntegerTokens() { 111 boolean inError = false; 112 if (tbrp.fileNamePattern.getIntegerTokenConverter() == null) { 113 inError = true; 114 addError(MISSING_INT_TOKEN + tbrp.fileNamePatternStr + "]"); 115 addError(CoreConstants.SEE_MISSING_INTEGER_TOKEN); 116 } 117 if (tbrp.fileNamePattern.getPrimaryDateTokenConverter() == null) { 118 inError = true; 119 addError(MISSING_DATE_TOKEN + tbrp.fileNamePatternStr + "]"); 120 } 121 122 return !inError; 123 } 124 125 protected ArchiveRemover createArchiveRemover() { 126 return new SizeAndTimeBasedArchiveRemover(tbrp.fileNamePattern, rc); 127 } 128 129 void computeCurrentPeriodsHighestCounterValue(final String stemRegex) { 130 File file = new File(getCurrentPeriodsFileNameWithoutCompressionSuffix()); 131 File parentDir = file.getParentFile(); 132 133 File[] matchingFileArray = FileFilterUtil.filesInFolderMatchingStemRegex(parentDir, stemRegex); 134 135 if (matchingFileArray == null || matchingFileArray.length == 0) { 136 currentPeriodsCounter = 0; 137 return; 138 } 139 currentPeriodsCounter = FileFilterUtil.findHighestCounter(matchingFileArray, stemRegex); 140 141 // if parent raw file property is not null, then the next 142 // counter is max found counter+1 143 if (tbrp.getParentsRawFileProperty() != null || (tbrp.compressionMode != CompressionMode.NONE)) { 144 // TODO test me 145 currentPeriodsCounter++; 146 } 147 } 148 149 @Override 150 public boolean isTriggeringEvent(File activeFile, final E event) { 151 152 long currentTime = getCurrentTime(); 153 long localNextCheck = atomicNextCheck.get(); 154 155 // first check for roll-over based on time 156 if (currentTime >= localNextCheck) { 157 long nextCheckCandidate = computeNextCheck(currentTime); 158 atomicNextCheck.set(nextCheckCandidate); 159 Instant instantInElapsedPeriod = dateInCurrentPeriod; 160 elapsedPeriodsFileName = tbrp.fileNamePatternWithoutCompSuffix.convertMultipleArguments( 161 instantInElapsedPeriod, currentPeriodsCounter); 162 currentPeriodsCounter = 0; 163 setDateInCurrentPeriod(currentTime); 164 165 return true; 166 } 167 168 return checkSizeBasedTrigger(activeFile, currentTime); 169 } 170 171 private boolean checkSizeBasedTrigger(File activeFile, long currentTime) { 172 // next check for roll-over based on size 173 if (invocationGate.isTooSoon(currentTime)) { 174 return false; 175 } 176 177 if (activeFile == null) { 178 addWarn("activeFile == null"); 179 return false; 180 } 181 if (maxFileSize == null) { 182 addWarn("maxFileSize = null"); 183 return false; 184 } 185 if (activeFile.length() >= maxFileSize.getSize()) { 186 187 elapsedPeriodsFileName = tbrp.fileNamePatternWithoutCompSuffix.convertMultipleArguments(dateInCurrentPeriod, 188 currentPeriodsCounter); 189 currentPeriodsCounter++; 190 return true; 191 } 192 193 return false; 194 } 195 196 public Duration getCheckIncrement() { 197 return checkIncrement; 198 } 199 200 public void setCheckIncrement(Duration checkIncrement) { 201 this.checkIncrement = checkIncrement; 202 } 203 204 @Override 205 public String getCurrentPeriodsFileNameWithoutCompressionSuffix() { 206 return tbrp.fileNamePatternWithoutCompSuffix.convertMultipleArguments(dateInCurrentPeriod, 207 currentPeriodsCounter); 208 } 209 210 public void setMaxFileSize(FileSize aMaxFileSize) { 211 this.maxFileSize = aMaxFileSize; 212 } 213 214}