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