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