1
2
3
4
5
6
7
8
9
10
11
12 package ch.qos.logback.core.rolling;
13
14 import static ch.qos.logback.core.CoreConstants.CODES_URL;
15 import static ch.qos.logback.core.CoreConstants.MORE_INFO_PREFIX;
16
17 import java.io.File;
18 import java.io.IOException;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import java.util.concurrent.locks.Lock;
22 import java.util.concurrent.locks.ReentrantLock;
23
24 import ch.qos.logback.core.CoreConstants;
25 import ch.qos.logback.core.FileAppender;
26 import ch.qos.logback.core.rolling.helper.CompressionMode;
27 import ch.qos.logback.core.rolling.helper.FileNamePattern;
28 import ch.qos.logback.core.util.ContextUtil;
29
30
31
32
33
34
35
36
37
38
39
40
41 public class RollingFileAppender<E> extends FileAppender<E> {
42 File currentlyActiveFile;
43 TriggeringPolicy<E> triggeringPolicy;
44 RollingPolicy rollingPolicy;
45
46 Lock triggeringPolicyLock = new ReentrantLock();
47
48 static private String RFA_NO_TP_URL = CODES_URL + "#rfa_no_tp";
49 static private String RFA_NO_RP_URL = CODES_URL + "#rfa_no_rp";
50 static private String COLLISION_URL = CODES_URL + "#rfa_collision";
51 static private String RFA_LATE_FILE_URL = CODES_URL + "#rfa_file_after";
52 static private String RFA_RESET_RP_OR_TP = CODES_URL + "#rfa_reset_rp_or_tp";
53
54 public void start() {
55 if (triggeringPolicy == null) {
56 addWarn("No TriggeringPolicy was set for the RollingFileAppender named " + getName());
57 addWarn(MORE_INFO_PREFIX + RFA_NO_TP_URL);
58 return;
59 }
60 if (!triggeringPolicy.isStarted()) {
61 addWarn("TriggeringPolicy has not started. RollingFileAppender will not start");
62 return;
63 }
64
65 if (checkForCollisionsInPreviousRollingFileAppenders()) {
66 addError("Collisions detected with FileAppender/RollingAppender instances defined earlier. Aborting.");
67 addError(MORE_INFO_PREFIX + COLLISION_WITH_EARLIER_APPENDER_URL);
68 return;
69 }
70
71
72 if (!append) {
73 addWarn("Append mode is mandatory for RollingFileAppender. Defaulting to append=true.");
74 append = true;
75 }
76
77 if (rollingPolicy == null) {
78 addError("No RollingPolicy was set for the RollingFileAppender named " + getName());
79 addError(MORE_INFO_PREFIX + RFA_NO_RP_URL);
80 return;
81 }
82
83
84 if (checkForFileAndPatternCollisions()) {
85 addError("File property collides with fileNamePattern. Aborting.");
86 addError(MORE_INFO_PREFIX + COLLISION_URL);
87 return;
88 }
89
90 if (isPrudent()) {
91 if (rawFileProperty() != null) {
92 addWarn("Setting \"File\" property to null on account of prudent mode");
93 setFile(null);
94 }
95 if (rollingPolicy.getCompressionMode() != CompressionMode.NONE) {
96 addError("Compression is not supported in prudent mode. Aborting");
97 return;
98 }
99 }
100
101 addInfo("Active log file name: " + getFile());
102 currentlyActiveFile = new File(getFile());
103 initializeLengthCounter();
104 super.start();
105 }
106
107
108
109 private boolean checkForFileAndPatternCollisions() {
110 if (triggeringPolicy instanceof RollingPolicyBase) {
111 final RollingPolicyBase base = (RollingPolicyBase) triggeringPolicy;
112 final FileNamePattern fileNamePattern = base.fileNamePattern;
113
114 if (fileNamePattern != null && fileName != null) {
115 String regex = fileNamePattern.toRegex();
116 return fileName.matches(regex);
117 }
118 }
119 return false;
120 }
121
122 private boolean checkForCollisionsInPreviousRollingFileAppenders() {
123 boolean collisionResult = false;
124 if (triggeringPolicy instanceof RollingPolicyBase) {
125 final RollingPolicyBase base = (RollingPolicyBase) triggeringPolicy;
126 final FileNamePattern fileNamePattern = base.fileNamePattern;
127 boolean collisionsDetected = innerCheckForFileNamePatternCollisionInPreviousRFA(fileNamePattern);
128 if (collisionsDetected)
129 collisionResult = true;
130 }
131 return collisionResult;
132 }
133
134 private boolean innerCheckForFileNamePatternCollisionInPreviousRFA(FileNamePattern fileNamePattern) {
135 boolean collisionsDetected = false;
136 @SuppressWarnings("unchecked") Map<String, FileNamePattern> map = (Map<String, FileNamePattern>) context.getObject(
137 CoreConstants.RFA_FILENAME_PATTERN_COLLISION_MAP);
138 if (map == null) {
139 return collisionsDetected;
140 }
141 for (Entry<String, FileNamePattern> entry : map.entrySet()) {
142 if (fileNamePattern.equals(entry.getValue())) {
143 addErrorForCollision("FileNamePattern", entry.getValue().toString(), entry.getKey());
144 collisionsDetected = true;
145 }
146 }
147 if (name != null) {
148 map.put(name, fileNamePattern);
149 }
150 return collisionsDetected;
151 }
152
153 private void initializeLengthCounter() {
154 if(getLengthCounter() != null && currentlyActiveFile.exists()) {
155 long currentFileLength = currentlyActiveFile.length();
156 addInfo("Setting currentFileLength to "+currentFileLength+ " for "+currentlyActiveFile);
157 incrementByteCount(currentFileLength);
158 }
159 }
160
161 @Override
162 public void stop() {
163 if (!isStarted()) {
164 return;
165 }
166 super.stop();
167
168 if (rollingPolicy != null)
169 rollingPolicy.stop();
170 if (triggeringPolicy != null)
171 triggeringPolicy.stop();
172
173 Map<String, FileNamePattern> map = ContextUtil.getFilenamePatternCollisionMap(context);
174 if (map != null && getName() != null)
175 map.remove(getName());
176
177 }
178
179 @Override
180 public void setFile(String file) {
181
182
183 if (file != null && ((triggeringPolicy != null) || (rollingPolicy != null))) {
184 addError("File property must be set before any triggeringPolicy or rollingPolicy properties");
185 addError(MORE_INFO_PREFIX + RFA_LATE_FILE_URL);
186 }
187 super.setFile(file);
188 }
189
190 @Override
191 public String getFile() {
192 return rollingPolicy.getActiveFileName();
193 }
194
195
196
197
198 public void rollover() {
199 streamWriteLock.lock();
200 try {
201
202
203
204
205
206 this.closeOutputStream();
207 attemptRollover();
208 attemptOpenFile();
209 } finally {
210 streamWriteLock.unlock();
211 }
212 }
213
214 private void attemptOpenFile() {
215 try {
216
217 currentlyActiveFile = new File(rollingPolicy.getActiveFileName());
218
219
220
221 this.openFile(rollingPolicy.getActiveFileName());
222 } catch (IOException e) {
223 addError("setFile(" + fileName + ", false) call failed.", e);
224 }
225 }
226
227 private void attemptRollover() {
228 try {
229 rollingPolicy.rollover();
230 } catch (RolloverFailure rf) {
231 addWarn("RolloverFailure occurred. Deferring roll-over.");
232
233 this.append = true;
234 }
235 }
236
237
238
239
240 @Override
241 protected void subAppend(E event) {
242
243
244
245
246
247
248
249
250 triggeringPolicyLock.lock();
251 try {
252 if (triggeringPolicy.isTriggeringEvent(currentlyActiveFile, event)) {
253 rollover();
254 }
255 } finally {
256 triggeringPolicyLock.unlock();
257 }
258
259 super.subAppend(event);
260 }
261
262 public RollingPolicy getRollingPolicy() {
263 return rollingPolicy;
264 }
265
266 public TriggeringPolicy<E> getTriggeringPolicy() {
267 return triggeringPolicy;
268 }
269
270
271
272
273
274
275
276
277 @SuppressWarnings("unchecked")
278 public void setRollingPolicy(RollingPolicy policy) {
279 if (this.rollingPolicy instanceof TriggeringPolicy) {
280 String className = rollingPolicy.getClass().getSimpleName();
281 addWarn("A rolling policy of type " + className + " was already set.");
282 addWarn("Note that " + className + " doubles as a TriggeringPolicy");
283 addWarn("See also " + RFA_RESET_RP_OR_TP);
284 }
285 this.rollingPolicy = policy;
286 if (this.rollingPolicy instanceof TriggeringPolicy) {
287 this.triggeringPolicy = (TriggeringPolicy<E>) policy;
288 }
289
290 }
291
292 public void setTriggeringPolicy(TriggeringPolicy<E> policy) {
293 if (triggeringPolicy instanceof RollingPolicy) {
294 String className = triggeringPolicy.getClass().getSimpleName();
295 addWarn("A triggering policy of type " + className + " was already set.");
296 addWarn("Note that " + className + " doubles as a RollingPolicy");
297 addWarn("See also " + RFA_RESET_RP_OR_TP);
298 }
299 triggeringPolicy = policy;
300 if (policy instanceof RollingPolicy) {
301 rollingPolicy = (RollingPolicy) policy;
302 }
303 }
304
305 @Override
306 protected void updateByteCount(byte[] byteArray) {
307 if(byteArray == null)
308 return;
309 incrementByteCount(byteArray.length);
310 }
311
312 void incrementByteCount(long increment) {
313 LengthCounter lengthCounter = getLengthCounter();
314 if (lengthCounter == null)
315 return;
316
317 if (increment > 0) {
318 lengthCounter.add(increment);
319 }
320 }
321
322 private LengthCounter getLengthCounter() {
323 return triggeringPolicy.getLengthCounter();
324 }
325
326 }