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 %notEmpty{%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
102
103 private PatternLayout(final Configuration config, final RegexReplacement replace, final String eventPattern,
104 final PatternSelector patternSelector, final Charset charset, final boolean alwaysWriteExceptions,
105 final boolean disableAnsi, final boolean noConsoleNoAnsi, final String headerPattern,
106 final String footerPattern) {
107 super(config, charset,
108 newSerializerBuilder()
109 .setConfiguration(config)
110 .setReplace(replace)
111 .setPatternSelector(patternSelector)
112 .setAlwaysWriteExceptions(alwaysWriteExceptions)
113 .setDisableAnsi(disableAnsi)
114 .setNoConsoleNoAnsi(noConsoleNoAnsi)
115 .setPattern(headerPattern)
116 .build(),
117 newSerializerBuilder()
118 .setConfiguration(config)
119 .setReplace(replace)
120 .setPatternSelector(patternSelector)
121 .setAlwaysWriteExceptions(alwaysWriteExceptions)
122 .setDisableAnsi(disableAnsi)
123 .setNoConsoleNoAnsi(noConsoleNoAnsi)
124 .setPattern(footerPattern)
125 .build());
126 this.conversionPattern = eventPattern;
127 this.patternSelector = patternSelector;
128 this.eventSerializer = newSerializerBuilder()
129 .setConfiguration(config)
130 .setReplace(replace)
131 .setPatternSelector(patternSelector)
132 .setAlwaysWriteExceptions(alwaysWriteExceptions)
133 .setDisableAnsi(disableAnsi)
134 .setNoConsoleNoAnsi(noConsoleNoAnsi)
135 .setPattern(eventPattern)
136 .setDefaultPattern(DEFAULT_CONVERSION_PATTERN)
137 .build();
138 }
139
140 public static SerializerBuilder newSerializerBuilder() {
141 return new SerializerBuilder();
142 }
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 @Deprecated
158 public static Serializer createSerializer(final Configuration configuration, final RegexReplacement replace,
159 final String pattern, final String defaultPattern, final PatternSelector patternSelector,
160 final boolean alwaysWriteExceptions, final boolean noConsoleNoAnsi) {
161 final SerializerBuilder builder = newSerializerBuilder();
162 builder.setAlwaysWriteExceptions(alwaysWriteExceptions);
163 builder.setConfiguration(configuration);
164 builder.setDefaultPattern(defaultPattern);
165 builder.setNoConsoleNoAnsi(noConsoleNoAnsi);
166 builder.setPattern(pattern);
167 builder.setPatternSelector(patternSelector);
168 builder.setReplace(replace);
169 return builder.build();
170 }
171
172
173
174
175
176
177 public String getConversionPattern() {
178 return conversionPattern;
179 }
180
181
182
183
184
185
186
187
188
189
190
191 @Override
192 public Map<String, String> getContentFormat() {
193 final Map<String, String> result = new HashMap<>();
194 result.put("structured", "false");
195 result.put("formatType", "conversion");
196 result.put("format", conversionPattern);
197 return result;
198 }
199
200
201
202
203
204
205
206 @Override
207 public String toSerializable(final LogEvent event) {
208 return eventSerializer.toSerializable(event);
209 }
210
211 @Override
212 public void encode(final LogEvent event, final ByteBufferDestination destination) {
213 if (!(eventSerializer instanceof Serializer2)) {
214 super.encode(event, destination);
215 return;
216 }
217 final StringBuilder text = toText((Serializer2) eventSerializer, event, getStringBuilder());
218 final Encoder<StringBuilder> encoder = getStringBuilderEncoder();
219 encoder.encode(text, destination);
220 trimToMaxSize(text);
221 }
222
223
224
225
226
227
228
229
230 private StringBuilder toText(final Serializer2 serializer, final LogEvent event,
231 final StringBuilder destination) {
232 return serializer.toSerializable(event, destination);
233 }
234
235
236
237
238
239
240 public static PatternParser createPatternParser(final Configuration config) {
241 if (config == null) {
242 return new PatternParser(config, KEY, LogEventPatternConverter.class);
243 }
244 PatternParser parser = config.getComponent(KEY);
245 if (parser == null) {
246 parser = new PatternParser(config, KEY, LogEventPatternConverter.class);
247 config.addComponent(KEY, parser);
248 parser = config.getComponent(KEY);
249 }
250 return parser;
251 }
252
253 @Override
254 public String toString() {
255 return patternSelector == null ? conversionPattern : patternSelector.toString();
256 }
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282 @PluginFactory
283 @Deprecated
284 public static PatternLayout createLayout(
285 @PluginAttribute(value = "pattern", defaultString = DEFAULT_CONVERSION_PATTERN) final String pattern,
286 @PluginElement("PatternSelector") final PatternSelector patternSelector,
287 @PluginConfiguration final Configuration config,
288 @PluginElement("Replace") final RegexReplacement replace,
289
290 @PluginAttribute(value = "charset") final Charset charset,
291 @PluginAttribute(value = "alwaysWriteExceptions", defaultBoolean = true) final boolean alwaysWriteExceptions,
292 @PluginAttribute(value = "noConsoleNoAnsi") final boolean noConsoleNoAnsi,
293 @PluginAttribute("header") final String headerPattern,
294 @PluginAttribute("footer") final String footerPattern) {
295 return newBuilder()
296 .withPattern(pattern)
297 .withPatternSelector(patternSelector)
298 .withConfiguration(config)
299 .withRegexReplacement(replace)
300 .withCharset(charset)
301 .withAlwaysWriteExceptions(alwaysWriteExceptions)
302 .withNoConsoleNoAnsi(noConsoleNoAnsi)
303 .withHeader(headerPattern)
304 .withFooter(footerPattern)
305 .build();
306 }
307
308 private static class PatternSerializer implements Serializer, Serializer2 {
309
310 private final PatternFormatter[] formatters;
311 private final RegexReplacement replace;
312
313 private PatternSerializer(final PatternFormatter[] formatters, final RegexReplacement replace) {
314 super();
315 this.formatters = formatters;
316 this.replace = replace;
317 }
318
319 @Override
320 public String toSerializable(final LogEvent event) {
321 final StringBuilder sb = getStringBuilder();
322 try {
323 return toSerializable(event, sb).toString();
324 } finally {
325 trimToMaxSize(sb);
326 }
327 }
328
329 @Override
330 public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) {
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("[formatters=");
349 builder.append(Arrays.toString(formatters));
350 builder.append(", replace=");
351 builder.append(replace);
352 builder.append("]");
353 return builder.toString();
354 }
355 }
356
357 public static class SerializerBuilder implements org.apache.logging.log4j.core.util.Builder<Serializer> {
358
359 private Configuration configuration;
360 private RegexReplacement replace;
361 private String pattern;
362 private String defaultPattern;
363 private PatternSelector patternSelector;
364 private boolean alwaysWriteExceptions;
365 private boolean disableAnsi;
366 private boolean noConsoleNoAnsi;
367
368 @Override
369 public Serializer build() {
370 if (Strings.isEmpty(pattern) && Strings.isEmpty(defaultPattern)) {
371 return null;
372 }
373 if (patternSelector == null) {
374 try {
375 final PatternParser parser = createPatternParser(configuration);
376 final List<PatternFormatter> list = parser.parse(pattern == null ? defaultPattern : pattern,
377 alwaysWriteExceptions, disableAnsi, noConsoleNoAnsi);
378 final PatternFormatter[] formatters = list.toArray(new PatternFormatter[0]);
379 return new PatternSerializer(formatters, replace);
380 } catch (final RuntimeException ex) {
381 throw new IllegalArgumentException("Cannot parse pattern '" + pattern + "'", ex);
382 }
383 }
384 return new PatternSelectorSerializer(patternSelector, replace);
385 }
386
387 public SerializerBuilder setConfiguration(final Configuration configuration) {
388 this.configuration = configuration;
389 return this;
390 }
391
392 public SerializerBuilder setReplace(final RegexReplacement replace) {
393 this.replace = replace;
394 return this;
395 }
396
397 public SerializerBuilder setPattern(final String pattern) {
398 this.pattern = pattern;
399 return this;
400 }
401
402 public SerializerBuilder setDefaultPattern(final String defaultPattern) {
403 this.defaultPattern = defaultPattern;
404 return this;
405 }
406
407 public SerializerBuilder setPatternSelector(final PatternSelector patternSelector) {
408 this.patternSelector = patternSelector;
409 return this;
410 }
411
412 public SerializerBuilder setAlwaysWriteExceptions(final boolean alwaysWriteExceptions) {
413 this.alwaysWriteExceptions = alwaysWriteExceptions;
414 return this;
415 }
416
417 public SerializerBuilder setDisableAnsi(final boolean disableAnsi) {
418 this.disableAnsi = disableAnsi;
419 return this;
420 }
421
422 public SerializerBuilder setNoConsoleNoAnsi(final boolean noConsoleNoAnsi) {
423 this.noConsoleNoAnsi = noConsoleNoAnsi;
424 return this;
425 }
426
427 }
428
429 private static class PatternSelectorSerializer implements Serializer, Serializer2 {
430
431 private final PatternSelector patternSelector;
432 private final RegexReplacement replace;
433
434 private PatternSelectorSerializer(final PatternSelector patternSelector, final RegexReplacement replace) {
435 super();
436 this.patternSelector = patternSelector;
437 this.replace = replace;
438 }
439
440 @Override
441 public String toSerializable(final LogEvent event) {
442 final StringBuilder sb = getStringBuilder();
443 try {
444 return toSerializable(event, sb).toString();
445 } finally {
446 trimToMaxSize(sb);
447 }
448 }
449
450 @Override
451 public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) {
452 final PatternFormatter[] formatters = patternSelector.getFormatters(event);
453 final int len = formatters.length;
454 for (int i = 0; i < len; i++) {
455 formatters[i].format(event, buffer);
456 }
457 if (replace != null) {
458 String str = buffer.toString();
459 str = replace.format(str);
460 buffer.setLength(0);
461 buffer.append(str);
462 }
463 return buffer;
464 }
465
466 @Override
467 public String toString() {
468 final StringBuilder builder = new StringBuilder();
469 builder.append(super.toString());
470 builder.append("[patternSelector=");
471 builder.append(patternSelector);
472 builder.append(", replace=");
473 builder.append(replace);
474 builder.append("]");
475 return builder.toString();
476 }
477 }
478
479
480
481
482
483
484
485
486 public static PatternLayout createDefaultLayout() {
487 return newBuilder().build();
488 }
489
490
491
492
493
494
495
496
497
498
499 public static PatternLayout createDefaultLayout(final Configuration configuration) {
500 return newBuilder().withConfiguration(configuration).build();
501 }
502
503
504
505
506
507
508 @PluginBuilderFactory
509 public static Builder newBuilder() {
510 return new Builder();
511 }
512
513
514
515
516 public static class Builder implements org.apache.logging.log4j.core.util.Builder<PatternLayout> {
517
518 @PluginBuilderAttribute
519 private String pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;
520
521 @PluginElement("PatternSelector")
522 private PatternSelector patternSelector;
523
524 @PluginConfiguration
525 private Configuration configuration;
526
527 @PluginElement("Replace")
528 private RegexReplacement regexReplacement;
529
530
531 @PluginBuilderAttribute
532 private Charset charset = Charset.defaultCharset();
533
534 @PluginBuilderAttribute
535 private boolean alwaysWriteExceptions = true;
536
537 @PluginBuilderAttribute
538 private boolean disableAnsi;
539
540 @PluginBuilderAttribute
541 private boolean noConsoleNoAnsi;
542
543 @PluginBuilderAttribute
544 private String header;
545
546 @PluginBuilderAttribute
547 private String footer;
548
549 private Builder() {
550 }
551
552
553
554
555
556
557 public Builder withPattern(final String pattern) {
558 this.pattern = pattern;
559 return this;
560 }
561
562
563
564
565
566 public Builder withPatternSelector(final PatternSelector patternSelector) {
567 this.patternSelector = patternSelector;
568 return this;
569 }
570
571
572
573
574
575 public Builder withConfiguration(final Configuration configuration) {
576 this.configuration = configuration;
577 return this;
578 }
579
580
581
582
583
584 public Builder withRegexReplacement(final RegexReplacement regexReplacement) {
585 this.regexReplacement = regexReplacement;
586 return this;
587 }
588
589
590
591
592
593 public Builder withCharset(final Charset charset) {
594
595 if (charset != null) {
596 this.charset = charset;
597 }
598 return this;
599 }
600
601
602
603
604
605 public Builder withAlwaysWriteExceptions(final boolean alwaysWriteExceptions) {
606 this.alwaysWriteExceptions = alwaysWriteExceptions;
607 return this;
608 }
609
610
611
612
613
614 public Builder withDisableAnsi(final boolean disableAnsi) {
615 this.disableAnsi = disableAnsi;
616 return this;
617 }
618
619
620
621
622
623 public Builder withNoConsoleNoAnsi(final boolean noConsoleNoAnsi) {
624 this.noConsoleNoAnsi = noConsoleNoAnsi;
625 return this;
626 }
627
628
629
630
631
632 public Builder withHeader(final String header) {
633 this.header = header;
634 return this;
635 }
636
637
638
639
640
641 public Builder withFooter(final String footer) {
642 this.footer = footer;
643 return this;
644 }
645
646 @Override
647 public PatternLayout build() {
648
649 if (configuration == null) {
650 configuration = new DefaultConfiguration();
651 }
652 return new PatternLayout(configuration, regexReplacement, pattern, patternSelector, charset,
653 alwaysWriteExceptions, disableAnsi, noConsoleNoAnsi, header, footer);
654 }
655 }
656 }