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
24 import org.apache.logging.log4j.core.Appender;
25 import org.apache.logging.log4j.core.Core;
26 import org.apache.logging.log4j.core.Filter;
27 import org.apache.logging.log4j.core.Layout;
28 import org.apache.logging.log4j.core.LogEvent;
29 import org.apache.logging.log4j.core.config.Configuration;
30 import org.apache.logging.log4j.core.config.plugins.Plugin;
31 import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
32 import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
33 import org.apache.logging.log4j.core.net.Advertiser;
34 import org.apache.logging.log4j.core.util.Booleans;
35 import org.apache.logging.log4j.core.util.Integers;
36
37
38
39
40
41
42 @Plugin(name = "MemoryMappedFile", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
43 public final class MemoryMappedFileAppender extends AbstractOutputStreamAppender<MemoryMappedFileManager> {
44
45
46
47
48
49
50
51 public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
52 implements org.apache.logging.log4j.core.util.Builder<MemoryMappedFileAppender> {
53
54 @PluginBuilderAttribute("fileName")
55 private String fileName;
56
57 @PluginBuilderAttribute("append")
58 private boolean append = true;
59
60 @PluginBuilderAttribute("regionLength")
61 private int regionLength = MemoryMappedFileManager.DEFAULT_REGION_LENGTH;
62
63 @PluginBuilderAttribute("advertise")
64 private boolean advertise;
65
66 @PluginBuilderAttribute("advertiseURI")
67 private String advertiseURI;
68
69 @Override
70 public MemoryMappedFileAppender build() {
71 final String name = getName();
72 final int actualRegionLength = determineValidRegionLength(name, regionLength);
73
74 if (name == null) {
75 LOGGER.error("No name provided for MemoryMappedFileAppender");
76 return null;
77 }
78
79 if (fileName == null) {
80 LOGGER.error("No filename provided for MemoryMappedFileAppender with name " + name);
81 return null;
82 }
83 final Layout<? extends Serializable> layout = getOrCreateLayout();
84 final MemoryMappedFileManager manager = MemoryMappedFileManager.getFileManager(fileName, append, isImmediateFlush(),
85 actualRegionLength, advertiseURI, layout);
86 if (manager == null) {
87 return null;
88 }
89
90 return new MemoryMappedFileAppender(name, layout, getFilter(), manager, fileName, isIgnoreExceptions(), false,
91 advertise ? getConfiguration().getAdvertiser() : null);
92 }
93
94 public B setFileName(final String fileName) {
95 this.fileName = fileName;
96 return asBuilder();
97 }
98
99 public B setAppend(final boolean append) {
100 this.append = append;
101 return asBuilder();
102 }
103
104 public B setRegionLength(final int regionLength) {
105 this.regionLength = regionLength;
106 return asBuilder();
107 }
108
109 public B setAdvertise(final boolean advertise) {
110 this.advertise = advertise;
111 return asBuilder();
112 }
113
114 public B setAdvertiseURI(final String advertiseURI) {
115 this.advertiseURI = advertiseURI;
116 return asBuilder();
117 }
118
119 }
120
121 private static final int BIT_POSITION_1GB = 30;
122 private static final int MAX_REGION_LENGTH = 1 << BIT_POSITION_1GB;
123 private static final int MIN_REGION_LENGTH = 256;
124
125 private final String fileName;
126 private Object advertisement;
127 private final Advertiser advertiser;
128
129 private MemoryMappedFileAppender(final String name, final Layout<? extends Serializable> layout,
130 final Filter filter, final MemoryMappedFileManager manager, final String filename,
131 final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser) {
132 super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
133 if (advertiser != null) {
134 final Map<String, String> configuration = new HashMap<>(layout.getContentFormat());
135 configuration.putAll(manager.getContentFormat());
136 configuration.put("contentType", layout.getContentType());
137 configuration.put("name", name);
138 advertisement = advertiser.advertise(configuration);
139 }
140 this.fileName = filename;
141 this.advertiser = advertiser;
142 }
143
144 @Override
145 public boolean stop(final long timeout, final TimeUnit timeUnit) {
146 setStopping();
147 super.stop(timeout, timeUnit, false);
148 if (advertiser != null) {
149 advertiser.unadvertise(advertisement);
150 }
151 setStopped();
152 return true;
153 }
154
155
156
157
158
159
160 @Override
161 public void append(final LogEvent event) {
162
163
164
165
166
167
168
169 getManager().setEndOfBatch(event.isEndOfBatch());
170 super.append(event);
171 }
172
173
174
175
176
177
178 public String getFileName() {
179 return this.fileName;
180 }
181
182
183
184
185
186
187 public int getRegionLength() {
188 return getManager().getRegionLength();
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212 @Deprecated
213 public static <B extends Builder<B>> MemoryMappedFileAppender createAppender(
214
215 final String fileName,
216 final String append,
217 final String name,
218 final String immediateFlush,
219 final String regionLengthStr,
220 final String ignore,
221 final Layout<? extends Serializable> layout,
222 final Filter filter,
223 final String advertise,
224 final String advertiseURI,
225 final Configuration config) {
226
227
228 final boolean isAppend = Booleans.parseBoolean(append, true);
229 final boolean isImmediateFlush = Booleans.parseBoolean(immediateFlush, false);
230 final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
231 final boolean isAdvertise = Boolean.parseBoolean(advertise);
232 final int regionLength = Integers.parseInt(regionLengthStr, MemoryMappedFileManager.DEFAULT_REGION_LENGTH);
233
234
235 return MemoryMappedFileAppender.<B>newBuilder()
236 .setAdvertise(isAdvertise)
237 .setAdvertiseURI(advertiseURI)
238 .setAppend(isAppend)
239 .setConfiguration(config)
240 .setFileName(fileName)
241 .withFilter(filter)
242 .withIgnoreExceptions(ignoreExceptions)
243 .withImmediateFlush(isImmediateFlush)
244 .withLayout(layout)
245 .withName(name)
246 .setRegionLength(regionLength)
247 .build();
248
249 }
250
251 @PluginBuilderFactory
252 public static <B extends Builder<B>> B newBuilder() {
253 return new Builder<B>().asBuilder();
254 }
255
256
257
258
259 private static int determineValidRegionLength(final String name, final int regionLength) {
260 if (regionLength > MAX_REGION_LENGTH) {
261 LOGGER.info("MemoryMappedAppender[{}] Reduced region length from {} to max length: {}", name, regionLength,
262 MAX_REGION_LENGTH);
263 return MAX_REGION_LENGTH;
264 }
265 if (regionLength < MIN_REGION_LENGTH) {
266 LOGGER.info("MemoryMappedAppender[{}] Expanded region length from {} to min length: {}", name, regionLength,
267 MIN_REGION_LENGTH);
268 return MIN_REGION_LENGTH;
269 }
270 final int result = Integers.ceilingNextPowerOfTwo(regionLength);
271 if (regionLength != result) {
272 LOGGER.info("MemoryMappedAppender[{}] Rounded up region length from {} to next power of two: {}", name,
273 regionLength, result);
274 }
275 return result;
276 }
277 }