001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.layout; 018 019import java.nio.charset.Charset; 020import java.util.Arrays; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024 025import org.apache.logging.log4j.core.Layout; 026import org.apache.logging.log4j.core.LogEvent; 027import org.apache.logging.log4j.core.config.Configuration; 028import org.apache.logging.log4j.core.config.DefaultConfiguration; 029import org.apache.logging.log4j.core.config.Node; 030import org.apache.logging.log4j.core.config.plugins.Plugin; 031import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 032import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; 033import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; 034import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; 035import org.apache.logging.log4j.core.config.plugins.PluginElement; 036import org.apache.logging.log4j.core.config.plugins.PluginFactory; 037import org.apache.logging.log4j.core.impl.LocationAware; 038import org.apache.logging.log4j.core.pattern.FormattingInfo; 039import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; 040import org.apache.logging.log4j.core.pattern.PatternFormatter; 041import org.apache.logging.log4j.core.pattern.PatternParser; 042import org.apache.logging.log4j.core.pattern.RegexReplacement; 043import org.apache.logging.log4j.util.PropertiesUtil; 044import org.apache.logging.log4j.util.Strings; 045 046/** 047 * A flexible layout configurable with pattern string. 048 * <p> 049 * The goal of this class is to {@link org.apache.logging.log4j.core.Layout#toByteArray format} a {@link LogEvent} and 050 * return the results. The format of the result depends on the <em>conversion pattern</em>. 051 * </p> 052 * <p> 053 * The conversion pattern is closely related to the conversion pattern of the printf function in C. A conversion pattern 054 * is composed of literal text and format control expressions called <em>conversion specifiers</em>. 055 * </p> 056 * <p> 057 * See the Log4j Manual for details on the supported pattern converters. 058 * </p> 059 */ 060@Plugin(name = "PatternLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true) 061public final class PatternLayout extends AbstractStringLayout { 062 063 /** 064 * Default pattern string for log output. Currently set to the string <b>"%m%n"</b> which just prints the 065 * application supplied message. 066 */ 067 public static final String DEFAULT_CONVERSION_PATTERN = "%m%n"; 068 069 /** 070 * A conversion pattern equivalent to the TTCCLayout. Current value is <b>%r [%t] %p %c %notEmpty{%x }- %m%n</b>. 071 */ 072 public static final String TTCC_CONVERSION_PATTERN = "%r [%t] %p %c %notEmpty{%x }- %m%n"; 073 074 /** 075 * A simple pattern. Current value is <b>%d [%t] %p %c - %m%n</b>. 076 */ 077 public static final String SIMPLE_CONVERSION_PATTERN = "%d [%t] %p %c - %m%n"; 078 079 /** Key to identify pattern converters. */ 080 public static final String KEY = "Converter"; 081 082 /** 083 * Conversion pattern. 084 */ 085 private final String conversionPattern; 086 private final PatternSelector patternSelector; 087 private final Serializer eventSerializer; 088 089 /** 090 * Constructs a PatternLayout using the supplied conversion pattern. 091 * 092 * @param config The Configuration. 093 * @param replace The regular expression to match. 094 * @param eventPattern conversion pattern. 095 * @param patternSelector The PatternSelector. 096 * @param charset The character set. 097 * @param alwaysWriteExceptions Whether or not exceptions should always be handled in this pattern (if {@code true}, 098 * exceptions will be written even if the pattern does not specify so). 099 * @param disableAnsi 100 * If {@code "true"}, do not output ANSI escape codes 101 * @param noConsoleNoAnsi 102 * If {@code "true"} (default) and {@link System#console()} is null, do not output ANSI escape codes 103 * @param headerPattern header conversion pattern. 104 * @param footerPattern footer conversion pattern. 105 */ 106 private PatternLayout(final Configuration config, final RegexReplacement replace, final String eventPattern, 107 final PatternSelector patternSelector, final Charset charset, final boolean alwaysWriteExceptions, 108 final boolean disableAnsi, final boolean noConsoleNoAnsi, final String headerPattern, 109 final String footerPattern) { 110 super(config, charset, 111 newSerializerBuilder() 112 .setConfiguration(config) 113 .setReplace(replace) 114 .setPatternSelector(patternSelector) 115 .setAlwaysWriteExceptions(alwaysWriteExceptions) 116 .setDisableAnsi(disableAnsi) 117 .setNoConsoleNoAnsi(noConsoleNoAnsi) 118 .setPattern(headerPattern) 119 .build(), 120 newSerializerBuilder() 121 .setConfiguration(config) 122 .setReplace(replace) 123 .setPatternSelector(patternSelector) 124 .setAlwaysWriteExceptions(alwaysWriteExceptions) 125 .setDisableAnsi(disableAnsi) 126 .setNoConsoleNoAnsi(noConsoleNoAnsi) 127 .setPattern(footerPattern) 128 .build()); 129 this.conversionPattern = eventPattern; 130 this.patternSelector = patternSelector; 131 this.eventSerializer = newSerializerBuilder() 132 .setConfiguration(config) 133 .setReplace(replace) 134 .setPatternSelector(patternSelector) 135 .setAlwaysWriteExceptions(alwaysWriteExceptions) 136 .setDisableAnsi(disableAnsi) 137 .setNoConsoleNoAnsi(noConsoleNoAnsi) 138 .setPattern(eventPattern) 139 .setDefaultPattern(DEFAULT_CONVERSION_PATTERN) 140 .build(); 141 } 142 143 public static SerializerBuilder newSerializerBuilder() { 144 return new SerializerBuilder(); 145 } 146 147 @Override 148 public boolean requiresLocation() { 149 return eventSerializer instanceof LocationAware && ((LocationAware) eventSerializer).requiresLocation(); 150 } 151 152 153 /** 154 * Deprecated, use {@link #newSerializerBuilder()} instead. 155 * 156 * @param configuration 157 * @param replace 158 * @param pattern 159 * @param defaultPattern 160 * @param patternSelector 161 * @param alwaysWriteExceptions 162 * @param noConsoleNoAnsi 163 * @return a new Serializer. 164 * @deprecated Use {@link #newSerializerBuilder()} instead. 165 */ 166 @Deprecated 167 public static Serializer createSerializer(final Configuration configuration, final RegexReplacement replace, 168 final String pattern, final String defaultPattern, final PatternSelector patternSelector, 169 final boolean alwaysWriteExceptions, final boolean noConsoleNoAnsi) { 170 final SerializerBuilder builder = newSerializerBuilder(); 171 builder.setAlwaysWriteExceptions(alwaysWriteExceptions); 172 builder.setConfiguration(configuration); 173 builder.setDefaultPattern(defaultPattern); 174 builder.setNoConsoleNoAnsi(noConsoleNoAnsi); 175 builder.setPattern(pattern); 176 builder.setPatternSelector(patternSelector); 177 builder.setReplace(replace); 178 return builder.build(); 179 } 180 181 /** 182 * Gets the conversion pattern. 183 * 184 * @return the conversion pattern. 185 */ 186 public String getConversionPattern() { 187 return conversionPattern; 188 } 189 190 /** 191 * Gets this PatternLayout's content format. Specified by: 192 * <ul> 193 * <li>Key: "structured" Value: "false"</li> 194 * <li>Key: "formatType" Value: "conversion" (format uses the keywords supported by OptionConverter)</li> 195 * <li>Key: "format" Value: provided "conversionPattern" param</li> 196 * </ul> 197 * 198 * @return Map of content format keys supporting PatternLayout 199 */ 200 @Override 201 public Map<String, String> getContentFormat() { 202 final Map<String, String> result = new HashMap<>(); 203 result.put("structured", "false"); 204 result.put("formatType", "conversion"); 205 result.put("format", conversionPattern); 206 return result; 207 } 208 209 /** 210 * Formats a logging event to a writer. 211 * 212 * @param event logging event to be formatted. 213 * @return The event formatted as a String. 214 */ 215 @Override 216 public String toSerializable(final LogEvent event) { 217 return eventSerializer.toSerializable(event); 218 } 219 220 public void serialize(final LogEvent event, StringBuilder stringBuilder) { 221 eventSerializer.toSerializable(event, stringBuilder); 222 } 223 224 @Override 225 public void encode(final LogEvent event, final ByteBufferDestination destination) { 226 final StringBuilder text = toText(eventSerializer, event, getStringBuilder()); 227 final Encoder<StringBuilder> encoder = getStringBuilderEncoder(); 228 encoder.encode(text, destination); 229 trimToMaxSize(text); 230 } 231 232 /** 233 * Creates a text representation of the specified log event 234 * and writes it into the specified StringBuilder. 235 * <p> 236 * Implementations are free to return a new StringBuilder if they can 237 * detect in advance that the specified StringBuilder is too small. 238 */ 239 private StringBuilder toText(final Serializer2 serializer, final LogEvent event, 240 final StringBuilder destination) { 241 return serializer.toSerializable(event, destination); 242 } 243 244 /** 245 * Creates a PatternParser. 246 * @param config The Configuration. 247 * @return The PatternParser. 248 */ 249 public static PatternParser createPatternParser(final Configuration config) { 250 if (config == null) { 251 return new PatternParser(config, KEY, LogEventPatternConverter.class); 252 } 253 PatternParser parser = config.getComponent(KEY); 254 if (parser == null) { 255 parser = new PatternParser(config, KEY, LogEventPatternConverter.class); 256 config.addComponent(KEY, parser); 257 parser = config.getComponent(KEY); 258 } 259 return parser; 260 } 261 262 @Override 263 public String toString() { 264 return patternSelector == null ? conversionPattern : patternSelector.toString(); 265 } 266 267 /** 268 * Creates a pattern layout. 269 * 270 * @param pattern 271 * The pattern. If not specified, defaults to DEFAULT_CONVERSION_PATTERN. 272 * @param patternSelector 273 * Allows different patterns to be used based on some selection criteria. 274 * @param config 275 * The Configuration. Some Converters require access to the Interpolator. 276 * @param replace 277 * A Regex replacement String. 278 * @param charset 279 * The character set. The platform default is used if not specified. 280 * @param alwaysWriteExceptions 281 * If {@code "true"} (default) exceptions are always written even if the pattern contains no exception tokens. 282 * @param noConsoleNoAnsi 283 * If {@code "true"} (default is false) and {@link System#console()} is null, do not output ANSI escape codes 284 * @param headerPattern 285 * The footer to place at the top of the document, once. 286 * @param footerPattern 287 * The footer to place at the bottom of the document, once. 288 * @return The PatternLayout. 289 * @deprecated Use {@link #newBuilder()} instead. This will be private in a future version. 290 */ 291 @PluginFactory 292 @Deprecated 293 public static PatternLayout createLayout( 294 @PluginAttribute(value = "pattern", defaultString = DEFAULT_CONVERSION_PATTERN) final String pattern, 295 @PluginElement("PatternSelector") final PatternSelector patternSelector, 296 @PluginConfiguration final Configuration config, 297 @PluginElement("Replace") final RegexReplacement replace, 298 // LOG4J2-783 use platform default by default, so do not specify defaultString for charset 299 @PluginAttribute(value = "charset") final Charset charset, 300 @PluginAttribute(value = "alwaysWriteExceptions", defaultBoolean = true) final boolean alwaysWriteExceptions, 301 @PluginAttribute(value = "noConsoleNoAnsi") final boolean noConsoleNoAnsi, 302 @PluginAttribute("header") final String headerPattern, 303 @PluginAttribute("footer") final String footerPattern) { 304 return newBuilder() 305 .withPattern(pattern) 306 .withPatternSelector(patternSelector) 307 .withConfiguration(config) 308 .withRegexReplacement(replace) 309 .withCharset(charset) 310 .withAlwaysWriteExceptions(alwaysWriteExceptions) 311 .withNoConsoleNoAnsi(noConsoleNoAnsi) 312 .withHeader(headerPattern) 313 .withFooter(footerPattern) 314 .build(); 315 } 316 317 private interface PatternSerializer extends Serializer, Serializer2, LocationAware {} 318 319 private static final class NoFormatPatternSerializer implements PatternSerializer { 320 321 private final LogEventPatternConverter[] converters; 322 323 private NoFormatPatternSerializer(final PatternFormatter[] formatters) { 324 this.converters = new LogEventPatternConverter[formatters.length]; 325 for (int i = 0; i < formatters.length; i++) { 326 converters[i] = formatters[i].getConverter(); 327 } 328 } 329 330 @Override 331 public String toSerializable(final LogEvent event) { 332 final StringBuilder sb = getStringBuilder(); 333 try { 334 return toSerializable(event, sb).toString(); 335 } finally { 336 trimToMaxSize(sb); 337 } 338 } 339 340 @Override 341 public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) { 342 for (LogEventPatternConverter converter : converters) { 343 converter.format(event, buffer); 344 } 345 return buffer; 346 } 347 348 @Override 349 public boolean requiresLocation() { 350 for (LogEventPatternConverter converter : converters) { 351 if (converter instanceof LocationAware && ((LocationAware) converter).requiresLocation()) { 352 return true; 353 } 354 } 355 return false; 356 } 357 358 @Override 359 public String toString() { 360 return super.toString() + "[converters=" + Arrays.toString(converters) + "]"; 361 } 362 } 363 364 private static final class PatternFormatterPatternSerializer implements PatternSerializer { 365 366 private final PatternFormatter[] formatters; 367 368 private PatternFormatterPatternSerializer(final PatternFormatter[] formatters) { 369 this.formatters = formatters; 370 } 371 372 @Override 373 public String toSerializable(final LogEvent event) { 374 final StringBuilder sb = getStringBuilder(); 375 try { 376 return toSerializable(event, sb).toString(); 377 } finally { 378 trimToMaxSize(sb); 379 } 380 } 381 382 @Override 383 public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) { 384 for (PatternFormatter formatter : formatters) { 385 formatter.format(event, buffer); 386 } 387 return buffer; 388 } 389 390 @Override 391 public boolean requiresLocation() { 392 for (PatternFormatter formatter : formatters) { 393 if (formatter.requiresLocation()) { 394 return true; 395 } 396 } 397 return false; 398 } 399 400 @Override 401 public String toString() { 402 return super.toString() + 403 "[formatters=" + 404 Arrays.toString(formatters) + 405 "]"; 406 } 407 } 408 409 private static final class PatternSerializerWithReplacement implements Serializer, Serializer2, LocationAware { 410 411 private final PatternSerializer delegate; 412 private final RegexReplacement replace; 413 414 private PatternSerializerWithReplacement(final PatternSerializer delegate, final RegexReplacement replace) { 415 this.delegate = delegate; 416 this.replace = replace; 417 } 418 419 @Override 420 public String toSerializable(final LogEvent event) { 421 final StringBuilder sb = getStringBuilder(); 422 try { 423 return toSerializable(event, sb).toString(); 424 } finally { 425 trimToMaxSize(sb); 426 } 427 } 428 429 @Override 430 public StringBuilder toSerializable(final LogEvent event, final StringBuilder buf) { 431 StringBuilder buffer = delegate.toSerializable(event, buf); 432 String str = buffer.toString(); 433 str = replace.format(str); 434 buffer.setLength(0); 435 buffer.append(str); 436 return buffer; 437 } 438 439 @Override 440 public boolean requiresLocation() { 441 return delegate.requiresLocation(); 442 } 443 444 @Override 445 public String toString() { 446 return super.toString() + 447 "[delegate=" + 448 delegate + 449 ", replace=" + 450 replace + 451 "]"; 452 } 453 } 454 455 public static class SerializerBuilder implements org.apache.logging.log4j.core.util.Builder<Serializer> { 456 457 private Configuration configuration; 458 private RegexReplacement replace; 459 private String pattern; 460 private String defaultPattern; 461 private PatternSelector patternSelector; 462 private boolean alwaysWriteExceptions; 463 private boolean disableAnsi; 464 private boolean noConsoleNoAnsi; 465 466 @Override 467 public Serializer build() { 468 if (Strings.isEmpty(pattern) && Strings.isEmpty(defaultPattern)) { 469 return null; 470 } 471 if (patternSelector == null) { 472 try { 473 final PatternParser parser = createPatternParser(configuration); 474 final List<PatternFormatter> list = parser.parse(pattern == null ? defaultPattern : pattern, 475 alwaysWriteExceptions, disableAnsi, noConsoleNoAnsi); 476 final PatternFormatter[] formatters = list.toArray(PatternFormatter.EMPTY_ARRAY); 477 boolean hasFormattingInfo = false; 478 for (PatternFormatter formatter : formatters) { 479 FormattingInfo info = formatter.getFormattingInfo(); 480 if (info != null && info != FormattingInfo.getDefault()) { 481 hasFormattingInfo = true; 482 break; 483 } 484 } 485 PatternSerializer serializer = hasFormattingInfo 486 ? new PatternFormatterPatternSerializer(formatters) 487 : new NoFormatPatternSerializer(formatters); 488 return replace == null ? serializer : new PatternSerializerWithReplacement(serializer, replace); 489 } catch (final RuntimeException ex) { 490 throw new IllegalArgumentException("Cannot parse pattern '" + pattern + "'", ex); 491 } 492 } 493 return new PatternSelectorSerializer(patternSelector, replace); 494 } 495 496 public SerializerBuilder setConfiguration(final Configuration configuration) { 497 this.configuration = configuration; 498 return this; 499 } 500 501 public SerializerBuilder setReplace(final RegexReplacement replace) { 502 this.replace = replace; 503 return this; 504 } 505 506 public SerializerBuilder setPattern(final String pattern) { 507 this.pattern = pattern; 508 return this; 509 } 510 511 public SerializerBuilder setDefaultPattern(final String defaultPattern) { 512 this.defaultPattern = defaultPattern; 513 return this; 514 } 515 516 public SerializerBuilder setPatternSelector(final PatternSelector patternSelector) { 517 this.patternSelector = patternSelector; 518 return this; 519 } 520 521 public SerializerBuilder setAlwaysWriteExceptions(final boolean alwaysWriteExceptions) { 522 this.alwaysWriteExceptions = alwaysWriteExceptions; 523 return this; 524 } 525 526 public SerializerBuilder setDisableAnsi(final boolean disableAnsi) { 527 this.disableAnsi = disableAnsi; 528 return this; 529 } 530 531 public SerializerBuilder setNoConsoleNoAnsi(final boolean noConsoleNoAnsi) { 532 this.noConsoleNoAnsi = noConsoleNoAnsi; 533 return this; 534 } 535 536 } 537 538 private static final class PatternSelectorSerializer implements Serializer, Serializer2, LocationAware { 539 540 private final PatternSelector patternSelector; 541 private final RegexReplacement replace; 542 543 private PatternSelectorSerializer(final PatternSelector patternSelector, final RegexReplacement replace) { 544 this.patternSelector = patternSelector; 545 this.replace = replace; 546 } 547 548 @Override 549 public String toSerializable(final LogEvent event) { 550 final StringBuilder sb = getStringBuilder(); 551 try { 552 return toSerializable(event, sb).toString(); 553 } finally { 554 trimToMaxSize(sb); 555 } 556 } 557 558 @Override 559 public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) { 560 for (PatternFormatter formatter : patternSelector.getFormatters(event)) { 561 formatter.format(event, buffer); 562 } 563 if (replace != null) { // creates temporary objects 564 String str = buffer.toString(); 565 str = replace.format(str); 566 buffer.setLength(0); 567 buffer.append(str); 568 } 569 return buffer; 570 } 571 572 @Override 573 public boolean requiresLocation() { 574 return patternSelector instanceof LocationAware && ((LocationAware) patternSelector).requiresLocation(); 575 } 576 577 @Override 578 public String toString() { 579 final StringBuilder builder = new StringBuilder(); 580 builder.append(super.toString()); 581 builder.append("[patternSelector="); 582 builder.append(patternSelector); 583 builder.append(", replace="); 584 builder.append(replace); 585 builder.append("]"); 586 return builder.toString(); 587 } 588 } 589 590 /** 591 * Creates a PatternLayout using the default options. These options include using UTF-8, the default conversion 592 * pattern, exceptions being written, and with ANSI escape codes. 593 * 594 * @return the PatternLayout. 595 * @see #DEFAULT_CONVERSION_PATTERN Default conversion pattern 596 */ 597 public static PatternLayout createDefaultLayout() { 598 return newBuilder().build(); 599 } 600 601 /** 602 * Creates a PatternLayout using the default options and the given configuration. These options include using UTF-8, 603 * the default conversion pattern, exceptions being written, and with ANSI escape codes. 604 * 605 * @param configuration The Configuration. 606 * 607 * @return the PatternLayout. 608 * @see #DEFAULT_CONVERSION_PATTERN Default conversion pattern 609 */ 610 public static PatternLayout createDefaultLayout(final Configuration configuration) { 611 return newBuilder().withConfiguration(configuration).build(); 612 } 613 614 /** 615 * Creates a builder for a custom PatternLayout. 616 * 617 * @return a PatternLayout builder. 618 */ 619 @PluginBuilderFactory 620 public static Builder newBuilder() { 621 return new Builder(); 622 } 623 624 /** 625 * Custom PatternLayout builder. Use the {@link PatternLayout#newBuilder() builder factory method} to create this. 626 */ 627 public static class Builder implements org.apache.logging.log4j.core.util.Builder<PatternLayout> { 628 629 @PluginBuilderAttribute 630 private String pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN; 631 632 @PluginElement("PatternSelector") 633 private PatternSelector patternSelector; 634 635 @PluginConfiguration 636 private Configuration configuration; 637 638 @PluginElement("Replace") 639 private RegexReplacement regexReplacement; 640 641 // LOG4J2-783 use platform default by default 642 @PluginBuilderAttribute 643 private Charset charset = Charset.defaultCharset(); 644 645 @PluginBuilderAttribute 646 private boolean alwaysWriteExceptions = true; 647 648 @PluginBuilderAttribute 649 private boolean disableAnsi = !useAnsiEscapeCodes(); 650 651 @PluginBuilderAttribute 652 private boolean noConsoleNoAnsi; 653 654 @PluginBuilderAttribute 655 private String header; 656 657 @PluginBuilderAttribute 658 private String footer; 659 660 private Builder() { 661 } 662 663 private boolean useAnsiEscapeCodes() { 664 final PropertiesUtil propertiesUtil = PropertiesUtil.getProperties(); 665 final boolean isPlatformSupportsAnsi = !propertiesUtil.isOsWindows(); 666 final boolean isJansiRequested = !propertiesUtil.getBooleanProperty("log4j.skipJansi", true); 667 return isPlatformSupportsAnsi || isJansiRequested; 668 } 669 670 /** 671 * @param pattern 672 * The pattern. If not specified, defaults to DEFAULT_CONVERSION_PATTERN. 673 */ 674 public Builder withPattern(final String pattern) { 675 this.pattern = pattern; 676 return this; 677 } 678 679 /** 680 * @param patternSelector 681 * Allows different patterns to be used based on some selection criteria. 682 */ 683 public Builder withPatternSelector(final PatternSelector patternSelector) { 684 this.patternSelector = patternSelector; 685 return this; 686 } 687 688 /** 689 * @param configuration 690 * The Configuration. Some Converters require access to the Interpolator. 691 */ 692 public Builder withConfiguration(final Configuration configuration) { 693 this.configuration = configuration; 694 return this; 695 } 696 697 /** 698 * @param regexReplacement 699 * A Regex replacement 700 */ 701 public Builder withRegexReplacement(final RegexReplacement regexReplacement) { 702 this.regexReplacement = regexReplacement; 703 return this; 704 } 705 706 /** 707 * @param charset 708 * The character set. The platform default is used if not specified. 709 */ 710 public Builder withCharset(final Charset charset) { 711 // LOG4J2-783 if null, use platform default by default 712 if (charset != null) { 713 this.charset = charset; 714 } 715 return this; 716 } 717 718 /** 719 * @param alwaysWriteExceptions 720 * If {@code "true"} (default) exceptions are always written even if the pattern contains no exception tokens. 721 */ 722 public Builder withAlwaysWriteExceptions(final boolean alwaysWriteExceptions) { 723 this.alwaysWriteExceptions = alwaysWriteExceptions; 724 return this; 725 } 726 727 /** 728 * @param disableAnsi 729 * If {@code "true"} (default is value of system property `log4j.skipJansi`, or `true` if undefined), 730 * do not output ANSI escape codes 731 */ 732 public Builder withDisableAnsi(final boolean disableAnsi) { 733 this.disableAnsi = disableAnsi; 734 return this; 735 } 736 737 /** 738 * @param noConsoleNoAnsi 739 * If {@code "true"} (default is false) and {@link System#console()} is null, do not output ANSI escape codes 740 */ 741 public Builder withNoConsoleNoAnsi(final boolean noConsoleNoAnsi) { 742 this.noConsoleNoAnsi = noConsoleNoAnsi; 743 return this; 744 } 745 746 /** 747 * @param header 748 * The footer to place at the top of the document, once. 749 */ 750 public Builder withHeader(final String header) { 751 this.header = header; 752 return this; 753 } 754 755 /** 756 * @param footer 757 * The footer to place at the bottom of the document, once. 758 */ 759 public Builder withFooter(final String footer) { 760 this.footer = footer; 761 return this; 762 } 763 764 @Override 765 public PatternLayout build() { 766 // fall back to DefaultConfiguration 767 if (configuration == null) { 768 configuration = new DefaultConfiguration(); 769 } 770 return new PatternLayout(configuration, regexReplacement, pattern, patternSelector, charset, 771 alwaysWriteExceptions, disableAnsi, noConsoleNoAnsi, header, footer); 772 } 773 } 774 775 public Serializer getEventSerializer() { 776 return eventSerializer; 777 } 778}