1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.layout;
18
19 import java.nio.charset.Charset;
20 import java.util.Arrays;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24
25 import org.apache.logging.log4j.core.Layout;
26 import org.apache.logging.log4j.core.LogEvent;
27 import org.apache.logging.log4j.core.config.Configuration;
28 import org.apache.logging.log4j.core.config.DefaultConfiguration;
29 import org.apache.logging.log4j.core.config.Node;
30 import org.apache.logging.log4j.core.config.plugins.Plugin;
31 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
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.config.plugins.PluginConfiguration;
35 import org.apache.logging.log4j.core.config.plugins.PluginElement;
36 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
37 import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
38 import org.apache.logging.log4j.core.pattern.PatternFormatter;
39 import org.apache.logging.log4j.core.pattern.PatternParser;
40 import org.apache.logging.log4j.core.pattern.RegexReplacement;
41 import org.apache.logging.log4j.util.Strings;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 @Plugin(name = "PatternLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
58 public final class PatternLayout extends AbstractStringLayout {
59
60
61
62
63
64 public static final String DEFAULT_CONVERSION_PATTERN = "%m%n";
65
66
67
68
69 public static final String TTCC_CONVERSION_PATTERN = "%r [%t] %p %c %x - %m%n";
70
71
72
73
74 public static final String SIMPLE_CONVERSION_PATTERN = "%d [%t] %p %c - %m%n";
75
76
77 public static final String KEY = "Converter";
78
79
80
81
82 private final String conversionPattern;
83 private final PatternSelector patternSelector;
84 private final Serializer eventSerializer;
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 private PatternLayout(final Configuration config, final RegexReplacement replace, final String eventPattern,
102 final PatternSelector patternSelector, final Charset charset, final boolean alwaysWriteExceptions,
103 final boolean noConsoleNoAnsi, final String headerPattern, final String footerPattern) {
104 super(config, charset,
105 createSerializer(config, replace, headerPattern, null, patternSelector, alwaysWriteExceptions,
106 noConsoleNoAnsi),
107 createSerializer(config, replace, footerPattern, null, patternSelector, alwaysWriteExceptions,
108 noConsoleNoAnsi));
109 this.conversionPattern = eventPattern;
110 this.patternSelector = patternSelector;
111 this.eventSerializer = createSerializer(config, replace, eventPattern, DEFAULT_CONVERSION_PATTERN,
112 patternSelector, alwaysWriteExceptions, noConsoleNoAnsi);
113 }
114
115 public static Serializer createSerializer(final Configuration configuration, final RegexReplacement replace,
116 final String pattern, final String defaultPattern, final PatternSelector patternSelector,
117 final boolean alwaysWriteExceptions, final boolean noConsoleNoAnsi) {
118 if (Strings.isEmpty(pattern) && Strings.isEmpty(defaultPattern)) {
119 return null;
120 }
121 if (patternSelector == null) {
122 try {
123 final PatternParser parser = createPatternParser(configuration);
124 final List<PatternFormatter> list = parser.parse(pattern == null ? defaultPattern : pattern,
125 alwaysWriteExceptions, noConsoleNoAnsi);
126 final PatternFormatter[] formatters = list.toArray(new PatternFormatter[0]);
127 return new PatternSerializer(formatters, replace);
128 } catch (final RuntimeException ex) {
129 throw new IllegalArgumentException("Cannot parse pattern '" + pattern + "'", ex);
130 }
131 }
132 return new PatternSelectorSerializer(patternSelector, replace);
133 }
134
135
136
137
138
139
140 public String getConversionPattern() {
141 return conversionPattern;
142 }
143
144
145
146
147
148
149
150
151
152
153
154 @Override
155 public Map<String, String> getContentFormat() {
156 final Map<String, String> result = new HashMap<>();
157 result.put("structured", "false");
158 result.put("formatType", "conversion");
159 result.put("format", conversionPattern);
160 return result;
161 }
162
163
164
165
166
167
168
169 @Override
170 public String toSerializable(final LogEvent event) {
171 return eventSerializer.toSerializable(event);
172 }
173
174 @Override
175 public void encode(final LogEvent event, final ByteBufferDestination destination) {
176 if (!(eventSerializer instanceof Serializer2)) {
177 super.encode(event, destination);
178 return;
179 }
180 final StringBuilder text = toText((Serializer2) eventSerializer, event, getStringBuilder());
181 final Encoder<StringBuilder> encoder = getStringBuilderEncoder();
182 encoder.encode(text, destination);
183 }
184
185
186
187
188
189
190
191
192 private StringBuilder toText(final Serializer2 serializer, final LogEvent event,
193 final StringBuilder destination) {
194 return serializer.toSerializable(event, destination);
195 }
196
197
198
199
200
201
202 public static PatternParser createPatternParser(final Configuration config) {
203 if (config == null) {
204 return new PatternParser(config, KEY, LogEventPatternConverter.class);
205 }
206 PatternParser parser = config.getComponent(KEY);
207 if (parser == null) {
208 parser = new PatternParser(config, KEY, LogEventPatternConverter.class);
209 config.addComponent(KEY, parser);
210 parser = config.getComponent(KEY);
211 }
212 return parser;
213 }
214
215 @Override
216 public String toString() {
217 return patternSelector == null ? conversionPattern : patternSelector.toString();
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243 @PluginFactory
244 public static PatternLayout createLayout(
245 @PluginAttribute(value = "pattern", defaultString = DEFAULT_CONVERSION_PATTERN) final String pattern,
246 @PluginElement("PatternSelector") final PatternSelector patternSelector,
247 @PluginConfiguration final Configuration config,
248 @PluginElement("Replace") final RegexReplacement replace,
249
250 @PluginAttribute(value = "charset") final Charset charset,
251 @PluginAttribute(value = "alwaysWriteExceptions", defaultBoolean = true) final boolean alwaysWriteExceptions,
252 @PluginAttribute(value = "noConsoleNoAnsi", defaultBoolean = false) final boolean noConsoleNoAnsi,
253 @PluginAttribute("header") final String headerPattern,
254 @PluginAttribute("footer") final String footerPattern) {
255 return newBuilder()
256 .withPattern(pattern)
257 .withPatternSelector(patternSelector)
258 .withConfiguration(config)
259 .withRegexReplacement(replace)
260 .withCharset(charset)
261 .withAlwaysWriteExceptions(alwaysWriteExceptions)
262 .withNoConsoleNoAnsi(noConsoleNoAnsi)
263 .withHeader(headerPattern)
264 .withFooter(footerPattern)
265 .build();
266 }
267
268 private static class PatternSerializer implements Serializer, Serializer2 {
269
270 private final PatternFormatter[] formatters;
271 private final RegexReplacement replace;
272
273 private PatternSerializer(final PatternFormatter[] formatters, final RegexReplacement replace) {
274 super();
275 this.formatters = formatters;
276 this.replace = replace;
277 }
278
279 @Override
280 public String toSerializable(final LogEvent event) {
281 return toSerializable(event, getStringBuilder()).toString();
282 }
283
284 @Override
285 public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) {
286 final int len = formatters.length;
287 for (int i = 0; i < len; i++) {
288 formatters[i].format(event, buffer);
289 }
290 if (replace != null) {
291 String str = buffer.toString();
292 str = replace.format(str);
293 buffer.setLength(0);
294 buffer.append(str);
295 }
296 return buffer;
297 }
298
299 @Override
300 public String toString() {
301 final StringBuilder builder = new StringBuilder();
302 builder.append(super.toString());
303 builder.append("[formatters=");
304 builder.append(Arrays.toString(formatters));
305 builder.append(", replace=");
306 builder.append(replace);
307 builder.append("]");
308 return builder.toString();
309 }
310 }
311
312 private static class PatternSelectorSerializer implements Serializer, Serializer2 {
313
314 private final PatternSelector patternSelector;
315 private final RegexReplacement replace;
316
317 private PatternSelectorSerializer(final PatternSelector patternSelector, final RegexReplacement replace) {
318 super();
319 this.patternSelector = patternSelector;
320 this.replace = replace;
321 }
322
323 @Override
324 public String toSerializable(final LogEvent event) {
325 return toSerializable(event, getStringBuilder()).toString();
326 }
327
328 @Override
329 public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) {
330 final PatternFormatter[] formatters = patternSelector.getFormatters(event);
331 final int len = formatters.length;
332 for (int i = 0; i < len; i++) {
333 formatters[i].format(event, buffer);
334 }
335 if (replace != null) {
336 String str = buffer.toString();
337 str = replace.format(str);
338 buffer.setLength(0);
339 buffer.append(str);
340 }
341 return buffer;
342 }
343
344 @Override
345 public String toString() {
346 final StringBuilder builder = new StringBuilder();
347 builder.append(super.toString());
348 builder.append("[patternSelector=");
349 builder.append(patternSelector);
350 builder.append(", replace=");
351 builder.append(replace);
352 builder.append("]");
353 return builder.toString();
354 }
355 }
356
357
358
359
360
361
362
363
364 public static PatternLayout createDefaultLayout() {
365 return newBuilder().build();
366 }
367
368
369
370
371
372
373
374
375
376
377 public static PatternLayout createDefaultLayout(final Configuration configuration) {
378 return newBuilder().withConfiguration(configuration).build();
379 }
380
381
382
383
384
385
386 @PluginBuilderFactory
387 public static Builder newBuilder() {
388 return new Builder();
389 }
390
391
392
393
394 public static class Builder implements org.apache.logging.log4j.core.util.Builder<PatternLayout> {
395
396 @PluginBuilderAttribute
397 private String pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;
398
399 @PluginElement("PatternSelector")
400 private PatternSelector patternSelector = null;
401
402 @PluginConfiguration
403 private Configuration configuration = null;
404
405 @PluginElement("Replace")
406 private RegexReplacement regexReplacement = null;
407
408
409 @PluginBuilderAttribute
410 private Charset charset = Charset.defaultCharset();
411
412 @PluginBuilderAttribute
413 private boolean alwaysWriteExceptions = true;
414
415 @PluginBuilderAttribute
416 private boolean noConsoleNoAnsi = false;
417
418 @PluginBuilderAttribute
419 private String header = null;
420
421 @PluginBuilderAttribute
422 private String footer = null;
423
424 private Builder() {
425 }
426
427
428
429 public Builder withPattern(final String pattern) {
430 this.pattern = pattern;
431 return this;
432 }
433
434 public Builder withPatternSelector(final PatternSelector patternSelector) {
435 this.patternSelector = patternSelector;
436 return this;
437 }
438
439 public Builder withConfiguration(final Configuration configuration) {
440 this.configuration = configuration;
441 return this;
442 }
443
444 public Builder withRegexReplacement(final RegexReplacement regexReplacement) {
445 this.regexReplacement = regexReplacement;
446 return this;
447 }
448
449 public Builder withCharset(final Charset charset) {
450
451 if (charset != null) {
452 this.charset = charset;
453 }
454 return this;
455 }
456
457 public Builder withAlwaysWriteExceptions(final boolean alwaysWriteExceptions) {
458 this.alwaysWriteExceptions = alwaysWriteExceptions;
459 return this;
460 }
461
462 public Builder withNoConsoleNoAnsi(final boolean noConsoleNoAnsi) {
463 this.noConsoleNoAnsi = noConsoleNoAnsi;
464 return this;
465 }
466
467 public Builder withHeader(final String header) {
468 this.header = header;
469 return this;
470 }
471
472 public Builder withFooter(final String footer) {
473 this.footer = footer;
474 return this;
475 }
476
477 @Override
478 public PatternLayout build() {
479
480 if (configuration == null) {
481 configuration = new DefaultConfiguration();
482 }
483 return new PatternLayout(configuration, regexReplacement, pattern, patternSelector, charset,
484 alwaysWriteExceptions, noConsoleNoAnsi, header, footer);
485 }
486 }
487 }