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