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