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