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; 018 019import ch.qos.logback.core.CoreConstants; 020import ch.qos.logback.core.joran.spi.NoAutoStart; 021import ch.qos.logback.core.rolling.helper.ArchiveRemover; 022import ch.qos.logback.core.rolling.helper.CompressionMode; 023import ch.qos.logback.core.rolling.helper.FileFilterUtil; 024import ch.qos.logback.core.rolling.helper.SizeAndTimeBasedArchiveRemover; 025import ch.qos.logback.core.util.Duration; 026import ch.qos.logback.core.util.FileSize; 027 028/** 029 * This class implement {@link TimeBasedFileNamingAndTriggeringPolicy} 030 * interface extending {@link TimeBasedFileNamingAndTriggeringPolicyBase}. This class is intended to be nested 031 * within a {@link SizeAndTimeBasedFileNamingAndTriggeringPolicy} instance. However, it can also be instantiated directly for testing purposes. 032 * 033 * @author Ceki Gülcü 034 * 035 * @param <E> 036 */ 037@NoAutoStart 038public class SizeAndTimeBasedFileNamingAndTriggeringPolicy<E> extends TimeBasedFileNamingAndTriggeringPolicyBase<E> { 039 040 enum Usage { 041 EMBEDDED, DIRECT 042 } 043 044 volatile int currentPeriodsCounter = 0; 045 FileSize maxFileSize; 046 047 Duration checkIncrement = null; 048 049 static String MISSING_INT_TOKEN = "Missing integer token, that is %i, in FileNamePattern ["; 050 static String MISSING_DATE_TOKEN = "Missing date token, that is %d, in FileNamePattern ["; 051 052 private final Usage usage; 053 054 //InvocationGate invocationGate = new SimpleInvocationGate(); 055 056 public SizeAndTimeBasedFileNamingAndTriggeringPolicy() { 057 this(Usage.DIRECT); 058 } 059 060 public SizeAndTimeBasedFileNamingAndTriggeringPolicy(Usage usage) { 061 this.usage = usage; 062 } 063 064 public LengthCounter lengthCounter = new LengthCounterBase(); 065 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 lengthCounter.reset(); 165 return true; 166 } 167 168 boolean result = checkSizeBasedTrigger(activeFile, currentTime); 169 if(result) 170 lengthCounter.reset(); 171 return result; 172 } 173 174 private boolean checkSizeBasedTrigger(File activeFile, long currentTime) { 175 // next check for roll-over based on size 176 //if (invocationGate.isTooSoon(currentTime)) { 177 // return false; 178 //} 179 180 if (activeFile == null) { 181 addWarn("activeFile == null"); 182 return false; 183 } 184 if (maxFileSize == null) { 185 addWarn("maxFileSize = null"); 186 return false; 187 } 188 189 190 191 if (lengthCounter.getLength() >= maxFileSize.getSize()) { 192 193 elapsedPeriodsFileName = tbrp.fileNamePatternWithoutCompSuffix.convertMultipleArguments(dateInCurrentPeriod, 194 currentPeriodsCounter); 195 currentPeriodsCounter++; 196 197 return true; 198 } 199 200 return false; 201 } 202 203 public Duration getCheckIncrement() { 204 return null; 205 } 206 207 public void setCheckIncrement(Duration checkIncrement) { 208 addWarn("Since version 1.5.8, 'checkIncrement' property has no effect"); 209 } 210 211 @Override 212 public String getCurrentPeriodsFileNameWithoutCompressionSuffix() { 213 return tbrp.fileNamePatternWithoutCompSuffix.convertMultipleArguments(dateInCurrentPeriod, 214 currentPeriodsCounter); 215 } 216 217 public void setMaxFileSize(FileSize aMaxFileSize) { 218 this.maxFileSize = aMaxFileSize; 219 } 220 221 @Override 222 public LengthCounter getLengthCounter() { 223 return lengthCounter; 224 } 225}