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