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 currentlyActiveFile = new File(getFile());
102 addInfo("Active log file name: " + getFile());
103 super.start();
104 }
105
106 private boolean checkForFileAndPatternCollisions() {
107 if (triggeringPolicy instanceof RollingPolicyBase) {
108 final RollingPolicyBase base = (RollingPolicyBase) triggeringPolicy;
109 final FileNamePattern fileNamePattern = base.fileNamePattern;
110
111 if (fileNamePattern != null && fileName != null) {
112 String regex = fileNamePattern.toRegex();
113 return fileName.matches(regex);
114 }
115 }
116 return false;
117 }
118
119 private boolean checkForCollisionsInPreviousRollingFileAppenders() {
120 boolean collisionResult = false;
121 if (triggeringPolicy instanceof RollingPolicyBase) {
122 final RollingPolicyBase base = (RollingPolicyBase) triggeringPolicy;
123 final FileNamePattern fileNamePattern = base.fileNamePattern;
124 boolean collisionsDetected = innerCheckForFileNamePatternCollisionInPreviousRFA(fileNamePattern);
125 if (collisionsDetected)
126 collisionResult = true;
127 }
128 return collisionResult;
129 }
130
131 private boolean innerCheckForFileNamePatternCollisionInPreviousRFA(FileNamePattern fileNamePattern) {
132 boolean collisionsDetected = false;
133 @SuppressWarnings("unchecked")
134 Map<String, FileNamePattern> map = (Map<String, FileNamePattern>) context.getObject(
135 CoreConstants.RFA_FILENAME_PATTERN_COLLISION_MAP);
136 if (map == null) {
137 return collisionsDetected;
138 }
139 for (Entry<String, FileNamePattern> entry : map.entrySet()) {
140 if (fileNamePattern.equals(entry.getValue())) {
141 addErrorForCollision("FileNamePattern", entry.getValue().toString(), entry.getKey());
142 collisionsDetected = true;
143 }
144 }
145 if (name != null) {
146 map.put(getName(), fileNamePattern);
147 }
148 return collisionsDetected;
149 }
150
151 @Override
152 public void stop() {
153 if (!isStarted()) {
154 return;
155 }
156 super.stop();
157
158 if (rollingPolicy != null)
159 rollingPolicy.stop();
160 if (triggeringPolicy != null)
161 triggeringPolicy.stop();
162
163 Map<String, FileNamePattern> map = ContextUtil.getFilenamePatternCollisionMap(context);
164 if (map != null && getName() != null)
165 map.remove(getName());
166
167 }
168
169 @Override
170 public void setFile(String file) {
171
172
173 if (file != null && ((triggeringPolicy != null) || (rollingPolicy != null))) {
174 addError("File property must be set before any triggeringPolicy or rollingPolicy properties");
175 addError(MORE_INFO_PREFIX + RFA_LATE_FILE_URL);
176 }
177 super.setFile(file);
178 }
179
180 @Override
181 public String getFile() {
182 return rollingPolicy.getActiveFileName();
183 }
184
185
186
187
188 public void rollover() {
189 streamWriteLock.lock();
190 try {
191
192
193
194
195
196 this.closeOutputStream();
197 attemptRollover();
198 attemptOpenFile();
199 } finally {
200 streamWriteLock.unlock();
201 }
202 }
203
204 private void attemptOpenFile() {
205 try {
206
207 currentlyActiveFile = new File(rollingPolicy.getActiveFileName());
208
209
210
211 this.openFile(rollingPolicy.getActiveFileName());
212 } catch (IOException e) {
213 addError("setFile(" + fileName + ", false) call failed.", e);
214 }
215 }
216
217 private void attemptRollover() {
218 try {
219 rollingPolicy.rollover();
220 } catch (RolloverFailure rf) {
221 addWarn("RolloverFailure occurred. Deferring roll-over.");
222
223 this.append = true;
224 }
225 }
226
227
228
229
230 @Override
231 protected void subAppend(E event) {
232
233
234
235
236
237
238
239
240 triggeringPolicyLock.lock();
241 try {
242 if (triggeringPolicy.isTriggeringEvent(currentlyActiveFile, event)) {
243 rollover();
244 }
245 } finally {
246 triggeringPolicyLock.unlock();
247 }
248
249 super.subAppend(event);
250 }
251
252 public RollingPolicy getRollingPolicy() {
253 return rollingPolicy;
254 }
255
256 public TriggeringPolicy<E> getTriggeringPolicy() {
257 return triggeringPolicy;
258 }
259
260
261
262
263
264
265
266
267 @SuppressWarnings("unchecked")
268 public void setRollingPolicy(RollingPolicy policy) {
269 if (rollingPolicy instanceof TriggeringPolicy) {
270 String className = rollingPolicy.getClass().getSimpleName();
271 addWarn("A rolling policy of type " + className + " was already set.");
272 addWarn("Note that " + className + " doubles as a TriggeringPolicy");
273 addWarn("See also "+RFA_RESET_RP_OR_TP);
274 }
275 rollingPolicy = policy;
276 if (rollingPolicy instanceof TriggeringPolicy) {
277 triggeringPolicy = (TriggeringPolicy<E>) policy;
278 }
279
280 }
281
282 public void setTriggeringPolicy(TriggeringPolicy<E> policy) {
283 if (triggeringPolicy instanceof RollingPolicy) {
284 String className = triggeringPolicy.getClass().getSimpleName();
285 addWarn("A triggering policy of type " + className + " was already set.");
286 addWarn("Note that " + className + " doubles as a RollingPolicy");
287 addWarn("See also "+RFA_RESET_RP_OR_TP);
288 }
289 triggeringPolicy = policy;
290 if (policy instanceof RollingPolicy) {
291 rollingPolicy = (RollingPolicy) policy;
292 }
293 }
294 }