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