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