1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.appender;
18
19 import java.io.Serializable;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.concurrent.TimeUnit;
23 import java.util.zip.Deflater;
24
25 import org.apache.logging.log4j.core.Appender;
26 import org.apache.logging.log4j.core.Core;
27 import org.apache.logging.log4j.core.Filter;
28 import org.apache.logging.log4j.core.Layout;
29 import org.apache.logging.log4j.core.LogEvent;
30 import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
31 import org.apache.logging.log4j.core.appender.rolling.DirectFileRolloverStrategy;
32 import org.apache.logging.log4j.core.appender.rolling.DirectWriteRolloverStrategy;
33 import org.apache.logging.log4j.core.appender.rolling.RollingFileManager;
34 import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
35 import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
36 import org.apache.logging.log4j.core.config.Configuration;
37 import org.apache.logging.log4j.core.config.Property;
38 import org.apache.logging.log4j.core.config.plugins.Plugin;
39 import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
40 import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
41 import org.apache.logging.log4j.core.config.plugins.PluginElement;
42 import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
43 import org.apache.logging.log4j.core.net.Advertiser;
44 import org.apache.logging.log4j.core.util.Booleans;
45 import org.apache.logging.log4j.core.util.Integers;
46
47
48
49
50 @Plugin(name = RollingFileAppender.PLUGIN_NAME, category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
51 public final class RollingFileAppender extends AbstractOutputStreamAppender<RollingFileManager> {
52
53 public static final String PLUGIN_NAME = "RollingFile";
54
55
56
57
58
59
60
61
62 public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
63 implements org.apache.logging.log4j.core.util.Builder<RollingFileAppender> {
64
65 @PluginBuilderAttribute
66 private String fileName;
67
68 @PluginBuilderAttribute
69 @Required
70 private String filePattern;
71
72 @PluginBuilderAttribute
73 private boolean append = true;
74
75 @PluginBuilderAttribute
76 private boolean locking;
77
78 @PluginElement("Policy")
79 @Required
80 private TriggeringPolicy policy;
81
82 @PluginElement("Strategy")
83 private RolloverStrategy strategy;
84
85 @PluginBuilderAttribute
86 private boolean advertise;
87
88 @PluginBuilderAttribute
89 private String advertiseUri;
90
91 @PluginBuilderAttribute
92 private boolean createOnDemand;
93
94 @PluginBuilderAttribute
95 private String filePermissions;
96
97 @PluginBuilderAttribute
98 private String fileOwner;
99
100 @PluginBuilderAttribute
101 private String fileGroup;
102
103 @Override
104 public RollingFileAppender build() {
105
106
107 final boolean isBufferedIo = isBufferedIo();
108 final int bufferSize = getBufferSize();
109 if (getName() == null) {
110 LOGGER.error("RollingFileAppender '{}': No name provided.", getName());
111 return null;
112 }
113
114 if (!isBufferedIo && bufferSize > 0) {
115 LOGGER.warn("RollingFileAppender '{}': The bufferSize is set to {} but bufferedIO is not true", getName(), bufferSize);
116 }
117
118 if (filePattern == null) {
119 LOGGER.error("RollingFileAppender '{}': No file name pattern provided.", getName());
120 return null;
121 }
122
123 if (policy == null) {
124 LOGGER.error("RollingFileAppender '{}': No TriggeringPolicy provided.", getName());
125 return null;
126 }
127
128 if (strategy == null) {
129 if (fileName != null) {
130 strategy = DefaultRolloverStrategy.newBuilder()
131 .withCompressionLevelStr(String.valueOf(Deflater.DEFAULT_COMPRESSION))
132 .withConfig(getConfiguration())
133 .build();
134 } else {
135 strategy = DirectWriteRolloverStrategy.newBuilder()
136 .withCompressionLevelStr(String.valueOf(Deflater.DEFAULT_COMPRESSION))
137 .withConfig(getConfiguration())
138 .build();
139 }
140 } else if (fileName == null && !(strategy instanceof DirectFileRolloverStrategy)) {
141 LOGGER.error("RollingFileAppender '{}': When no file name is provided a DirectFilenameRolloverStrategy must be configured");
142 return null;
143 }
144
145 final Layout<? extends Serializable> layout = getOrCreateLayout();
146 final RollingFileManager manager = RollingFileManager.getFileManager(fileName, filePattern, append,
147 isBufferedIo, policy, strategy, advertiseUri, layout, bufferSize, isImmediateFlush(),
148 createOnDemand, filePermissions, fileOwner, fileGroup, getConfiguration());
149 if (manager == null) {
150 return null;
151 }
152
153 manager.initialize();
154
155 return new RollingFileAppender(getName(), layout, getFilter(), manager, fileName, filePattern,
156 isIgnoreExceptions(), isImmediateFlush(), advertise ? getConfiguration().getAdvertiser() : null,
157 getPropertyArray());
158 }
159
160 public String getAdvertiseUri() {
161 return advertiseUri;
162 }
163
164 public String getFileName() {
165 return fileName;
166 }
167
168 public boolean isAdvertise() {
169 return advertise;
170 }
171
172 public boolean isAppend() {
173 return append;
174 }
175
176 public boolean isCreateOnDemand() {
177 return createOnDemand;
178 }
179
180 public boolean isLocking() {
181 return locking;
182 }
183
184 public String getFilePermissions() {
185 return filePermissions;
186 }
187
188 public String getFileOwner() {
189 return fileOwner;
190 }
191
192 public String getFileGroup() {
193 return fileGroup;
194 }
195
196 public B withAdvertise(final boolean advertise) {
197 this.advertise = advertise;
198 return asBuilder();
199 }
200
201 public B withAdvertiseUri(final String advertiseUri) {
202 this.advertiseUri = advertiseUri;
203 return asBuilder();
204 }
205
206 public B withAppend(final boolean append) {
207 this.append = append;
208 return asBuilder();
209 }
210
211 public B withFileName(final String fileName) {
212 this.fileName = fileName;
213 return asBuilder();
214 }
215
216 public B withCreateOnDemand(final boolean createOnDemand) {
217 this.createOnDemand = createOnDemand;
218 return asBuilder();
219 }
220
221 public B withLocking(final boolean locking) {
222 this.locking = locking;
223 return asBuilder();
224 }
225
226 public String getFilePattern() {
227 return filePattern;
228 }
229
230 public TriggeringPolicy getPolicy() {
231 return policy;
232 }
233
234 public RolloverStrategy getStrategy() {
235 return strategy;
236 }
237
238 public B withFilePattern(final String filePattern) {
239 this.filePattern = filePattern;
240 return asBuilder();
241 }
242
243 public B withPolicy(final TriggeringPolicy policy) {
244 this.policy = policy;
245 return asBuilder();
246 }
247
248 public B withStrategy(final RolloverStrategy strategy) {
249 this.strategy = strategy;
250 return asBuilder();
251 }
252
253 public B withFilePermissions(final String filePermissions) {
254 this.filePermissions = filePermissions;
255 return asBuilder();
256 }
257
258 public B withFileOwner(final String fileOwner) {
259 this.fileOwner = fileOwner;
260 return asBuilder();
261 }
262
263 public B withFileGroup(final String fileGroup) {
264 this.fileGroup = fileGroup;
265 return asBuilder();
266 }
267
268 }
269
270 private static final int DEFAULT_BUFFER_SIZE = 8192;
271
272 private final String fileName;
273 private final String filePattern;
274 private Object advertisement;
275 private final Advertiser advertiser;
276
277 private RollingFileAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
278 final RollingFileManager manager, final String fileName, final String filePattern,
279 final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser,
280 final Property[] properties) {
281 super(name, layout, filter, ignoreExceptions, immediateFlush, properties, manager);
282 if (advertiser != null) {
283 final Map<String, String> configuration = new HashMap<>(layout.getContentFormat());
284 configuration.put("contentType", layout.getContentType());
285 configuration.put("name", name);
286 advertisement = advertiser.advertise(configuration);
287 }
288 this.fileName = fileName;
289 this.filePattern = filePattern;
290 this.advertiser = advertiser;
291 }
292
293 @Override
294 public boolean stop(final long timeout, final TimeUnit timeUnit) {
295 setStopping();
296 final boolean stopped = super.stop(timeout, timeUnit, false);
297 if (advertiser != null) {
298 advertiser.unadvertise(advertisement);
299 }
300 setStopped();
301 return stopped;
302 }
303
304
305
306
307
308
309 @Override
310 public void append(final LogEvent event) {
311 getManager().checkRollover(event);
312 super.append(event);
313 }
314
315
316
317
318
319 public String getFileName() {
320 return fileName;
321 }
322
323
324
325
326
327 public String getFilePattern() {
328 return filePattern;
329 }
330
331
332
333
334
335
336 public <T extends TriggeringPolicy> T getTriggeringPolicy() {
337 return getManager().getTriggeringPolicy();
338 }
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362 @Deprecated
363 public static <B extends Builder<B>> RollingFileAppender createAppender(
364
365 final String fileName,
366 final String filePattern,
367 final String append,
368 final String name,
369 final String bufferedIO,
370 final String bufferSizeStr,
371 final String immediateFlush,
372 final TriggeringPolicy policy,
373 final RolloverStrategy strategy,
374 final Layout<? extends Serializable> layout,
375 final Filter filter,
376 final String ignore,
377 final String advertise,
378 final String advertiseUri,
379 final Configuration config) {
380
381 final int bufferSize = Integers.parseInt(bufferSizeStr, DEFAULT_BUFFER_SIZE);
382
383 return RollingFileAppender.<B>newBuilder()
384 .withAdvertise(Boolean.parseBoolean(advertise))
385 .withAdvertiseUri(advertiseUri)
386 .withAppend(Booleans.parseBoolean(append, true))
387 .withBufferedIo(Booleans.parseBoolean(bufferedIO, true))
388 .withBufferSize(bufferSize)
389 .setConfiguration(config)
390 .withFileName(fileName)
391 .withFilePattern(filePattern).setFilter(filter).setIgnoreExceptions(Booleans.parseBoolean(ignore, true))
392 .withImmediateFlush(Booleans.parseBoolean(immediateFlush, true)).setLayout(layout)
393 .withCreateOnDemand(false)
394 .withLocking(false).setName(name)
395 .withPolicy(policy)
396 .withStrategy(strategy)
397 .build();
398
399 }
400
401
402
403
404
405
406
407 @PluginBuilderFactory
408 public static <B extends Builder<B>> B newBuilder() {
409 return new Builder<B>().asBuilder();
410 }
411 }