1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.appender.rolling;
18
19 import org.apache.logging.log4j.Logger;
20 import org.apache.logging.log4j.core.appender.rolling.helper.Action;
21 import org.apache.logging.log4j.core.appender.rolling.helper.FileRenameAction;
22 import org.apache.logging.log4j.core.appender.rolling.helper.GZCompressAction;
23 import org.apache.logging.log4j.core.appender.rolling.helper.ZipCompressAction;
24 import org.apache.logging.log4j.core.config.Configuration;
25 import org.apache.logging.log4j.core.config.plugins.Plugin;
26 import org.apache.logging.log4j.core.config.plugins.PluginAttr;
27 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
28 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
29 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
30 import org.apache.logging.log4j.status.StatusLogger;
31
32 import java.io.File;
33 import java.util.ArrayList;
34 import java.util.List;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 @Plugin(name = "DefaultRolloverStrategy", type = "Core", printObject = true)
66 public class DefaultRolloverStrategy implements RolloverStrategy {
67
68
69
70 protected static final Logger LOGGER = StatusLogger.getLogger();
71
72 private static final int MIN_WINDOW_SIZE = 1;
73 private static final int DEFAULT_WINDOW_SIZE = 7;
74
75
76
77
78 private final int maxIndex;
79
80
81
82
83 private final int minIndex;
84
85 private final StrSubstitutor subst;
86
87
88
89
90
91
92 protected DefaultRolloverStrategy(int min, int max, StrSubstitutor subst) {
93 minIndex = min;
94 maxIndex = max;
95 this.subst = subst;
96 }
97
98
99
100
101
102
103
104 public RolloverDescription rollover(RollingFileManager manager) throws SecurityException {
105 if (maxIndex >= 0) {
106 int purgeStart = minIndex;
107
108 if (!purge(purgeStart, maxIndex, manager)) {
109 return null;
110 }
111
112 StringBuilder buf = new StringBuilder();
113 manager.getProcessor().formatFileName(buf, purgeStart);
114 String currentFileName = manager.getFileName();
115
116 String renameTo = subst.replace(buf);
117 String compressedName = renameTo;
118 Action compressAction = null;
119
120 if (renameTo.endsWith(".gz")) {
121 renameTo = renameTo.substring(0, renameTo.length() - 3);
122 compressAction = new GZCompressAction(new File(renameTo), new File(compressedName), true);
123 } else if (renameTo.endsWith(".zip")) {
124 renameTo = renameTo.substring(0, renameTo.length() - 4);
125 compressAction = new ZipCompressAction(new File(renameTo), new File(compressedName), true);
126 }
127
128 FileRenameAction renameAction =
129 new FileRenameAction(new File(currentFileName), new File(renameTo), false);
130
131 return new RolloverDescriptionImpl(currentFileName, false, renameAction, compressAction);
132 }
133
134 return null;
135 }
136
137
138
139
140
141
142
143
144
145 private boolean purge(final int lowIndex, final int highIndex, RollingFileManager manager) {
146 int suffixLength = 0;
147
148 List<FileRenameAction> renames = new ArrayList<FileRenameAction>();
149 StringBuilder buf = new StringBuilder();
150 manager.getProcessor().formatFileName(buf, lowIndex);
151
152 String lowFilename = subst.replace(buf);
153
154 if (lowFilename.endsWith(".gz")) {
155 suffixLength = 3;
156 } else if (lowFilename.endsWith(".zip")) {
157 suffixLength = 4;
158 }
159
160 for (int i = lowIndex; i <= highIndex; i++) {
161 File toRename = new File(lowFilename);
162 boolean isBase = false;
163
164 if (suffixLength > 0) {
165 File toRenameBase =
166 new File(lowFilename.substring(0, lowFilename.length() - suffixLength));
167
168 if (toRename.exists()) {
169 if (toRenameBase.exists()) {
170 toRenameBase.delete();
171 }
172 } else {
173 toRename = toRenameBase;
174 isBase = true;
175 }
176 }
177
178 if (toRename.exists()) {
179
180
181
182
183 if (i == highIndex) {
184 if (!toRename.delete()) {
185 return false;
186 }
187
188 break;
189 }
190
191
192
193
194 buf.setLength(0);
195 manager.getProcessor().formatFileName(buf, i + 1);
196
197 String highFilename = subst.replace(buf);
198 String renameTo = highFilename;
199
200 if (isBase) {
201 renameTo = highFilename.substring(0, highFilename.length() - suffixLength);
202 }
203
204 renames.add(new FileRenameAction(toRename, new File(renameTo), true));
205 lowFilename = highFilename;
206 } else {
207 break;
208 }
209 }
210
211
212
213
214 for (int i = renames.size() - 1; i >= 0; i--) {
215 Action action = renames.get(i);
216
217 try {
218 if (!action.execute()) {
219 return false;
220 }
221 } catch (Exception ex) {
222 LOGGER.warn("Exception during purge in RollingFileAppender", ex);
223 return false;
224 }
225 }
226
227 return true;
228 }
229
230 @Override
231 public String toString() {
232 return "DefaultRolloverStrategy(min=" + minIndex + ", max=" + maxIndex + ")";
233 }
234
235
236
237
238
239
240
241
242 @PluginFactory
243 public static DefaultRolloverStrategy createStrategy(@PluginAttr("max") String max,
244 @PluginAttr("min") String min,
245 @PluginConfiguration Configuration config) {
246
247 int minIndex;
248 if (min != null) {
249 minIndex = Integer.parseInt(min);
250 if (minIndex < 1) {
251 LOGGER.error("Minimum window size too small. Limited to " + MIN_WINDOW_SIZE);
252 minIndex = MIN_WINDOW_SIZE;
253 }
254 } else {
255 minIndex = MIN_WINDOW_SIZE;
256 }
257 int maxIndex;
258 if (max != null) {
259 maxIndex = Integer.parseInt(max);
260 if (maxIndex < minIndex) {
261 maxIndex = minIndex < DEFAULT_WINDOW_SIZE ? DEFAULT_WINDOW_SIZE : minIndex;
262 LOGGER.error("Maximum window size must be greater than the minimum windows size. Set to " + maxIndex);
263 }
264 } else {
265 maxIndex = DEFAULT_WINDOW_SIZE;
266 }
267 return new DefaultRolloverStrategy(minIndex, maxIndex, config.getSubst());
268 }
269
270 }