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 public void serialize(final LogEvent event, StringBuilder stringBuilder) {
220 eventSerializer.toSerializable(event, stringBuilder);
221 }
222
223 @Override
224 public void encode(final LogEvent event, final ByteBufferDestination destination) {
225 if (!(eventSerializer instanceof Serializer2)) {
226 super.encode(event, destination);
227 return;
228 }
229 final StringBuilder text = toText((Serializer2) eventSerializer, event, getStringBuilder());
230 final Encoder<StringBuilder> encoder = getStringBuilderEncoder();
231 encoder.encode(text, destination);
232 trimToMaxSize(text);
233 }
234
235
236
237
238
239
240
241
242 private StringBuilder toText(final Serializer2 serializer, final LogEvent event,
243 final StringBuilder destination) {
244 return serializer.toSerializable(event, destination);
245 }
246
247
248
249
250
251
252 public static PatternParser createPatternParser(final Configuration config) {
253 if (config == null) {
254 return new PatternParser(config, KEY, LogEventPatternConverter.class);
255 }
256 PatternParser parser = config.getComponent(KEY);
257 if (parser == null) {
258 parser = new PatternParser(config, KEY, LogEventPatternConverter.class);
259 config.addComponent(KEY, parser);
260 parser = config.getComponent(KEY);
261 }
262 return parser;
263 }
264
265 @Override
266 public String toString() {
267 return patternSelector == null ? conversionPattern : patternSelector.toString();
268 }
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294 @PluginFactory
295 @Deprecated
296 public static PatternLayout createLayout(
297 @PluginAttribute(value = "pattern", defaultString = DEFAULT_CONVERSION_PATTERN) final String pattern,
298 @PluginElement("PatternSelector") final PatternSelector patternSelector,
299 @PluginConfiguration final Configuration config,
300 @PluginElement("Replace") final RegexReplacement replace,
301
302 @PluginAttribute(value = "charset") final Charset charset,
303 @PluginAttribute(value = "alwaysWriteExceptions", defaultBoolean = true) final boolean alwaysWriteExceptions,
304 @PluginAttribute(value = "noConsoleNoAnsi") final boolean noConsoleNoAnsi,
305 @PluginAttribute("header") final String headerPattern,
306 @PluginAttribute("footer") final String footerPattern) {
307 return newBuilder()
308 .withPattern(pattern)
309 .withPatternSelector(patternSelector)
310 .withConfiguration(config)
311 .withRegexReplacement(replace)
312 .withCharset(charset)
313 .withAlwaysWriteExceptions(alwaysWriteExceptions)
314 .withNoConsoleNoAnsi(noConsoleNoAnsi)
315 .withHeader(headerPattern)
316 .withFooter(footerPattern)
317 .build();
318 }
319
320 private static class PatternSerializer implements Serializer, Serializer2, LocationAware {
321
322 private final PatternFormatter[] formatters;
323 private final RegexReplacement replace;
324
325 private PatternSerializer(final PatternFormatter[] formatters, final RegexReplacement replace) {
326 super();
327 this.formatters = formatters;
328 this.replace = replace;
329 }
330
331 @Override
332 public String toSerializable(final LogEvent event) {
333 final StringBuilder sb = getStringBuilder();
334 try {
335 return toSerializable(event, sb).toString();
336 } finally {
337 trimToMaxSize(sb);
338 }
339 }
340
341 @Override
342 public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) {
343 final int len = formatters.length;
344 for (int i = 0; i < len; i++) {
345 formatters[i].format(event, buffer);
346 }
347 if (replace != null) {
348 String str = buffer.toString();
349 str = replace.format(str);
350 buffer.setLength(0);
351 buffer.append(str);
352 }
353 return buffer;
354 }
355
356 @Override
357 public boolean requiresLocation() {
358 for (PatternFormatter formatter : formatters) {
359 if (formatter.requiresLocation()) {
360 return true;
361 }
362 }
363 return false;
364 }
365
366 @Override
367 public String toString() {
368 final StringBuilder builder = new StringBuilder();
369 builder.append(super.toString());
370 builder.append("[formatters=");
371 builder.append(Arrays.toString(formatters));
372 builder.append(", replace=");
373 builder.append(replace);
374 builder.append("]");
375 return builder.toString();
376 }
377 }
378
379 public static class SerializerBuilder implements org.apache.logging.log4j.core.util.Builder<Serializer> {
380
381 private Configuration configuration;
382 private RegexReplacement replace;
383 private String pattern;
384 private String defaultPattern;
385 private PatternSelector patternSelector;
386 private boolean alwaysWriteExceptions;
387 private boolean disableAnsi;
388 private boolean noConsoleNoAnsi;
389
390 @Override
391 public Serializer build() {
392 if (Strings.isEmpty(pattern) && Strings.isEmpty(defaultPattern)) {
393 return null;
394 }
395 if (patternSelector == null) {
396 try {
397 final PatternParser parser = createPatternParser(configuration);
398 final List<PatternFormatter> list = parser.parse(pattern == null ? defaultPattern : pattern,
399 alwaysWriteExceptions, disableAnsi, noConsoleNoAnsi);
400 final PatternFormatter[] formatters = list.toArray(new PatternFormatter[0]);
401 return new PatternSerializer(formatters, replace);
402 } catch (final RuntimeException ex) {
403 throw new IllegalArgumentException("Cannot parse pattern '" + pattern + "'", ex);
404 }
405 }
406 return new PatternSelectorSerializer(patternSelector, replace);
407 }
408
409 public SerializerBuilder setConfiguration(final Configuration configuration) {
410 this.configuration = configuration;
411 return this;
412 }
413
414 public SerializerBuilder setReplace(final RegexReplacement replace) {
415 this.replace = replace;
416 return this;
417 }
418
419 public SerializerBuilder setPattern(final String pattern) {
420 this.pattern = pattern;
421 return this;
422 }
423
424 public SerializerBuilder setDefaultPattern(final String defaultPattern) {
425 this.defaultPattern = defaultPattern;
426 return this;
427 }
428
429 public SerializerBuilder setPatternSelector(final PatternSelector patternSelector) {
430 this.patternSelector = patternSelector;
431 return this;
432 }
433
434 public SerializerBuilder setAlwaysWriteExceptions(final boolean alwaysWriteExceptions) {
435 this.alwaysWriteExceptions = alwaysWriteExceptions;
436 return this;
437 }
438
439 public SerializerBuilder setDisableAnsi(final boolean disableAnsi) {
440 this.disableAnsi = disableAnsi;
441 return this;
442 }
443
444 public SerializerBuilder setNoConsoleNoAnsi(final boolean noConsoleNoAnsi) {
445 this.noConsoleNoAnsi = noConsoleNoAnsi;
446 return this;
447 }
448
449 }
450
451 private static class PatternSelectorSerializer implements Serializer, Serializer2, LocationAware {
452
453 private final PatternSelector patternSelector;
454 private final RegexReplacement replace;
455
456 private PatternSelectorSerializer(final PatternSelector patternSelector, final RegexReplacement replace) {
457 super();
458 this.patternSelector = patternSelector;
459 this.replace = replace;
460 }
461
462 @Override
463 public String toSerializable(final LogEvent event) {
464 final StringBuilder sb = getStringBuilder();
465 try {
466 return toSerializable(event, sb).toString();
467 } finally {
468 trimToMaxSize(sb);
469 }
470 }
471
472 @Override
473 public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) {
474 final PatternFormatter[] formatters = patternSelector.getFormatters(event);
475 final int len = formatters.length;
476 for (int i = 0; i < len; i++) {
477 formatters[i].format(event, buffer);
478 }
479 if (replace != null) {
480 String str = buffer.toString();
481 str = replace.format(str);
482 buffer.setLength(0);
483 buffer.append(str);
484 }
485 return buffer;
486 }
487
488 @Override
489 public boolean requiresLocation() {
490 return patternSelector instanceof LocationAware && ((LocationAware) patternSelector).requiresLocation();
491 }
492
493 @Override
494 public String toString() {
495 final StringBuilder builder = new StringBuilder();
496 builder.append(super.toString());
497 builder.append("[patternSelector=");
498 builder.append(patternSelector);
499 builder.append(", replace=");
500 builder.append(replace);
501 builder.append("]");
502 return builder.toString();
503 }
504 }
505
506
507
508
509
510
511
512
513 public static PatternLayout createDefaultLayout() {
514 return newBuilder().build();
515 }
516
517
518
519
520
521
522
523
524
525
526 public static PatternLayout createDefaultLayout(final Configuration configuration) {
527 return newBuilder().withConfiguration(configuration).build();
528 }
529
530
531
532
533
534
535 @PluginBuilderFactory
536 public static Builder newBuilder() {
537 return new Builder();
538 }
539
540
541
542
543 public static class Builder implements org.apache.logging.log4j.core.util.Builder<PatternLayout> {
544
545 @PluginBuilderAttribute
546 private String pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;
547
548 @PluginElement("PatternSelector")
549 private PatternSelector patternSelector;
550
551 @PluginConfiguration
552 private Configuration configuration;
553
554 @PluginElement("Replace")
555 private RegexReplacement regexReplacement;
556
557
558 @PluginBuilderAttribute
559 private Charset charset = Charset.defaultCharset();
560
561 @PluginBuilderAttribute
562 private boolean alwaysWriteExceptions = true;
563
564 @PluginBuilderAttribute
565 private boolean disableAnsi = !useAnsiEscapeCodes();
566
567 @PluginBuilderAttribute
568 private boolean noConsoleNoAnsi;
569
570 @PluginBuilderAttribute
571 private String header;
572
573 @PluginBuilderAttribute
574 private String footer;
575
576 private Builder() {
577 }
578
579 private boolean useAnsiEscapeCodes() {
580 final PropertiesUtil propertiesUtil = PropertiesUtil.getProperties();
581 final boolean isPlatformSupportsAnsi = !propertiesUtil.isOsWindows();
582 final boolean isJansiRequested = !propertiesUtil.getBooleanProperty("log4j.skipJansi", true);
583 return isPlatformSupportsAnsi || isJansiRequested;
584 }
585
586
587
588
589
590 public Builder withPattern(final String pattern) {
591 this.pattern = pattern;
592 return this;
593 }
594
595
596
597
598
599 public Builder withPatternSelector(final PatternSelector patternSelector) {
600 this.patternSelector = patternSelector;
601 return this;
602 }
603
604
605
606
607
608 public Builder withConfiguration(final Configuration configuration) {
609 this.configuration = configuration;
610 return this;
611 }
612
613
614
615
616
617 public Builder withRegexReplacement(final RegexReplacement regexReplacement) {
618 this.regexReplacement = regexReplacement;
619 return this;
620 }
621
622
623
624
625
626 public Builder withCharset(final Charset charset) {
627
628 if (charset != null) {
629 this.charset = charset;
630 }
631 return this;
632 }
633
634
635
636
637
638 public Builder withAlwaysWriteExceptions(final boolean alwaysWriteExceptions) {
639 this.alwaysWriteExceptions = alwaysWriteExceptions;
640 return this;
641 }
642
643
644
645
646
647
648 public Builder withDisableAnsi(final boolean disableAnsi) {
649 this.disableAnsi = disableAnsi;
650 return this;
651 }
652
653
654
655
656
657 public Builder withNoConsoleNoAnsi(final boolean noConsoleNoAnsi) {
658 this.noConsoleNoAnsi = noConsoleNoAnsi;
659 return this;
660 }
661
662
663
664
665
666 public Builder withHeader(final String header) {
667 this.header = header;
668 return this;
669 }
670
671
672
673
674
675 public Builder withFooter(final String footer) {
676 this.footer = footer;
677 return this;
678 }
679
680 @Override
681 public PatternLayout build() {
682
683 if (configuration == null) {
684 configuration = new DefaultConfiguration();
685 }
686 return new PatternLayout(configuration, regexReplacement, pattern, patternSelector, charset,
687 alwaysWriteExceptions, disableAnsi, noConsoleNoAnsi, header, footer);
688 }
689 }
690
691 public Serializer getEventSerializer() {
692 return eventSerializer;
693 }
694 }