001/* 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2023, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014 015package ch.qos.logback.classic.encoder; 016 017import ch.qos.logback.classic.spi.ILoggingEvent; 018import ch.qos.logback.classic.spi.IThrowableProxy; 019import ch.qos.logback.classic.spi.LoggerContextVO; 020import ch.qos.logback.classic.spi.StackTraceElementProxy; 021import ch.qos.logback.core.CoreConstants; 022import ch.qos.logback.core.encoder.EncoderBase; 023import org.slf4j.Marker; 024import org.slf4j.event.KeyValuePair; 025 026import java.util.List; 027import java.util.Map; 028import java.util.Set; 029 030import static ch.qos.logback.core.CoreConstants.COLON_CHAR; 031import static ch.qos.logback.core.CoreConstants.COMMA_CHAR; 032import static ch.qos.logback.core.CoreConstants.DOUBLE_QUOTE_CHAR; 033import static ch.qos.logback.core.CoreConstants.UTF_8_CHARSET; 034import static ch.qos.logback.core.encoder.JsonEscapeUtil.jsonEscapeString; 035import static ch.qos.logback.core.model.ModelConstants.NULL_STR; 036 037/** 038 * JSON encoder that produces one JSON object per line in JSON Lines format, suitable for structured logging. 039 * Each {@link ILoggingEvent} is encoded into a JSON object containing fields such as timestamp, level, message, 040 * and optional elements like MDC properties, markers, and stack traces. 041 * 042 * <p>This encoder supports extensive configuration through boolean flags to include or exclude specific fields 043 * in the output, allowing customization for different logging needs. For example, you can enable/disable 044 * sequence numbers, nanoseconds, thread names, logger context, markers, MDC, key-value pairs, arguments, 045 * and throwable information.</p> 046 * 047 * <p>The encoder is designed for extensibility: subclasses can override protected methods (e.g., 048 * {@link #appendLoggerContext}, {@link #appendThrowableProxy}, {@link #appendMarkers}) to customize 049 * how specific parts of the JSON are generated. Additionally, the {@link #appendCustomFields} hook 050 * allows appending custom top-level fields to the JSON object.</p> 051 * 052 * <h3>Configuration</h3> 053 * <p>Use the setter methods (e.g., {@link #setWithSequenceNumber}, {@link #setWithTimestamp}) to control 054 * which fields are included. By default, most fields are enabled except {@code withFormattedMessage}.</p> 055 * 056 * <h3>Example Usage</h3> 057 * <pre>{@code 058 * <appender name="JSON" class="ch.qos.logback.core.ConsoleAppender"> 059 * <encoder class="ch.qos.logback.classic.encoder.JsonEncoder"> 060 * <withSequenceNumber>false</withSequenceNumber> 061 * <withNanoseconds>false</withNanoseconds> 062 * <withThreadName>false</withThreadName> 063 * </encoder> 064 * </appender> 065 * }</pre> 066 * 067 * <p>This produces output similar to the following (on a single line): 068 * </p> 069 * 070 * <pre>{"timestamp":1640995200000,"level":"INFO","loggerName":"com.example.MyClass","context":{"name":"default","birthdate":1640995200000,"properties":{}},"message":"Hello World"}</pre> 071 * 072 * @see <a href="https://jsonlines.org/">JSON Lines</a> 073 * @see <a href="https://datatracker.ietf.org/doc/html/rfc8259">RFC 8259 (The JavaScript Object Notation (JSON) Data Interchange Format)</a> 074 * @see ch.qos.logback.core.encoder.EncoderBase 075 * @since 1.3.8/1.4.8 076 * @author Ceki Gülcü 077 */ 078public class JsonEncoder extends EncoderBase<ILoggingEvent> { 079 static final boolean DO_NOT_ADD_QUOTE_KEY = false; 080 static final boolean ADD_QUOTE_KEY = true; 081 static int DEFAULT_SIZE = 1024; 082 static int DEFAULT_SIZE_WITH_THROWABLE = DEFAULT_SIZE * 8; 083 084 static byte[] EMPTY_BYTES = new byte[0]; 085 086 public static final String CONTEXT_ATTR_NAME = "context"; 087 public static final String NAME_ATTR_NAME = "name"; 088 public static final String BIRTHDATE_ATTR_NAME = "birthdate"; 089 public static final String CONTEXT_PROPERTIES_ATTR_NAME = "properties"; 090 091 public static final String TIMESTAMP_ATTR_NAME = "timestamp"; 092 093 public static final String NANOSECONDS_ATTR_NAME = "nanoseconds"; 094 095 public static final String SEQUENCE_NUMBER_ATTR_NAME = "sequenceNumber"; 096 097 public static final String LEVEL_ATTR_NAME = "level"; 098 public static final String MARKERS_ATTR_NAME = "markers"; 099 public static final String THREAD_NAME_ATTR_NAME = "threadName"; 100 public static final String MDC_ATTR_NAME = "mdc"; 101 public static final String LOGGER_ATTR_NAME = "loggerName"; 102 103 public static final String MESSAGE_ATTR_NAME = "message"; 104 105 public static final String FORMATTED_MESSAGE_ATTR_NAME = "formattedMessage"; 106 107 public static final String ARGUMENT_ARRAY_ATTR_NAME = "arguments"; 108 public static final String KEY_VALUE_PAIRS_ATTR_NAME = "kvpList"; 109 110 public static final String THROWABLE_ATTR_NAME = "throwable"; 111 112 private static final String CYCLIC_THROWABLE_ATTR_NAME = "cyclic"; 113 114 public static final String CAUSE_ATTR_NAME = "cause"; 115 116 public static final String SUPPRESSED_ATTR_NAME = "suppressed"; 117 118 public static final String COMMON_FRAMES_COUNT_ATTR_NAME = "commonFramesCount"; 119 120 public static final String CLASS_NAME_ATTR_NAME = "className"; 121 public static final String METHOD_NAME_ATTR_NAME = "methodName"; 122 private static final String FILE_NAME_ATTR_NAME = "fileName"; 123 private static final String LINE_NUMBER_ATTR_NAME = "lineNumber"; 124 125 public static final String STEP_ARRAY_NAME_ATTRIBUTE = "stepArray"; 126 127 protected static final char OPEN_OBJ = '{'; 128 protected static final char CLOSE_OBJ = '}'; 129 protected static final char OPEN_ARRAY = '['; 130 protected static final char CLOSE_ARRAY = ']'; 131 132 protected static final char QUOTE = DOUBLE_QUOTE_CHAR; 133 protected static final char SP = ' '; 134 protected static final char ENTRY_SEPARATOR = COLON_CHAR; 135 136 protected static final String COL_SP = ": "; 137 138 protected static final String QUOTE_COL = "\":"; 139 140 protected static final char VALUE_SEPARATOR = COMMA_CHAR; 141 142 private boolean withSequenceNumber = true; 143 144 private boolean withTimestamp = true; 145 private boolean withNanoseconds = true; 146 147 private boolean withLevel = true; 148 private boolean withThreadName = true; 149 private boolean withLoggerName = true; 150 private boolean withContext = true; 151 private boolean withMarkers = true; 152 private boolean withMDC = true; 153 private boolean withKVPList = true; 154 private boolean withMessage = true; 155 private boolean withArguments = true; 156 private boolean withThrowable = true; 157 private boolean withFormattedMessage = false; 158 159 @Override 160 public byte[] headerBytes() { 161 return EMPTY_BYTES; 162 } 163 164 @Override 165 public byte[] encode(ILoggingEvent event) { 166 final int initialCapacity = event.getThrowableProxy() == null ? DEFAULT_SIZE : DEFAULT_SIZE_WITH_THROWABLE; 167 StringBuilder sb = new StringBuilder(initialCapacity); 168 sb.append(OPEN_OBJ); 169 170 if (withSequenceNumber) { 171 appenderMemberWithLongValue(sb, SEQUENCE_NUMBER_ATTR_NAME, event.getSequenceNumber()); 172 } 173 174 if (withTimestamp) { 175 appendValueSeparator(sb, withSequenceNumber); 176 appenderMemberWithLongValue(sb, TIMESTAMP_ATTR_NAME, event.getTimeStamp()); 177 } 178 179 if (withNanoseconds) { 180 appendValueSeparator(sb, withSequenceNumber, withTimestamp); 181 appenderMemberWithLongValue(sb, NANOSECONDS_ATTR_NAME, event.getNanoseconds()); 182 } 183 184 if (withLevel) { 185 appendValueSeparator(sb, withNanoseconds, withSequenceNumber, withTimestamp); 186 String levelStr = event.getLevel() != null ? event.getLevel().levelStr : NULL_STR; 187 appenderMember(sb, LEVEL_ATTR_NAME, levelStr); 188 } 189 190 if (withThreadName) { 191 appendValueSeparator(sb, withLevel, withNanoseconds, withSequenceNumber, withTimestamp); 192 appenderMember(sb, THREAD_NAME_ATTR_NAME, jsonEscape(event.getThreadName())); 193 } 194 195 if (withLoggerName) { 196 appendValueSeparator(sb, withThreadName, withLevel, withNanoseconds, withSequenceNumber, withTimestamp); 197 appenderMember(sb, LOGGER_ATTR_NAME, event.getLoggerName()); 198 } 199 200 if (withContext) { 201 // at this stage we assume that at least one field was written 202 sb.append(VALUE_SEPARATOR); 203 appendLoggerContext(sb, event.getLoggerContextVO()); 204 } 205 206 if (withMarkers) 207 appendMarkers(sb, event); 208 209 if (withMDC) 210 appendMDC(sb, event); 211 212 if (withKVPList) 213 appendKeyValuePairs(sb, event); 214 215 if (withMessage) { 216 sb.append(VALUE_SEPARATOR); 217 appenderMember(sb, MESSAGE_ATTR_NAME, jsonEscape(event.getMessage())); 218 } 219 220 if (withFormattedMessage) { 221 sb.append(VALUE_SEPARATOR); 222 appenderMember(sb, FORMATTED_MESSAGE_ATTR_NAME, jsonEscape(event.getFormattedMessage())); 223 } 224 225 if (withArguments) { 226 appendArgumentArray(sb, event); 227 } 228 229 if (withThrowable) 230 appendThrowableProxy(sb, THROWABLE_ATTR_NAME, event.getThrowableProxy()); 231 232 // allow subclasses to append custom top-level fields; default implementation is a no-op 233 appendCustomFields(sb, event); 234 235 sb.append(CLOSE_OBJ); 236 sb.append(CoreConstants.JSON_LINE_SEPARATOR); 237 return sb.toString().getBytes(UTF_8_CHARSET); 238 } 239 240 /** 241 * Append a JSON value separator (a comma) to the provided {@link StringBuilder} 242 * when any of the supplied boolean flags indicate that a subsequent element 243 * is present. 244 * 245 * <p>Callers pass a sequence of booleans that represent whether subsequent 246 * JSON members will be written. If at least one of those booleans is 247 * {@code true}, this method appends a single comma (',') to separate JSON 248 * fields.</p> 249 * 250 * <p>This method is protected so subclasses that extend the encoder can 251 * reuse or override the logic for inserting separators between generated 252 * JSON members.</p> 253 * 254 * @param sb the {@link StringBuilder} to append the separator to; must not be {@code null} 255 * @param subsequentConditionals one or more booleans indicating whether 256 * subsequent JSON elements will be written. 257 * If any value is {@code true}, a comma is appended. 258 */ 259 protected void appendValueSeparator(StringBuilder sb, boolean... subsequentConditionals) { 260 boolean enabled = false; 261 for (boolean subsequent : subsequentConditionals) { 262 if (subsequent) { 263 enabled = true; 264 break; 265 } 266 } 267 268 if (enabled) 269 sb.append(VALUE_SEPARATOR); 270 } 271 272 protected void appendLoggerContext(StringBuilder sb, LoggerContextVO loggerContextVO) { 273 274 sb.append(QUOTE).append(CONTEXT_ATTR_NAME).append(QUOTE_COL); 275 if (loggerContextVO == null) { 276 sb.append(NULL_STR); 277 return; 278 } 279 280 sb.append(OPEN_OBJ); 281 appenderMember(sb, NAME_ATTR_NAME, nullSafeStr(loggerContextVO.getName())); 282 sb.append(VALUE_SEPARATOR); 283 appenderMemberWithLongValue(sb, BIRTHDATE_ATTR_NAME, loggerContextVO.getBirthTime()); 284 sb.append(VALUE_SEPARATOR); 285 286 appendMap(sb, CONTEXT_PROPERTIES_ATTR_NAME, loggerContextVO.getPropertyMap()); 287 sb.append(CLOSE_OBJ); 288 289 } 290 291 protected void appendMap(StringBuilder sb, String attrName, Map<String, String> map) { 292 sb.append(QUOTE).append(attrName).append(QUOTE_COL); 293 if (map == null) { 294 sb.append(NULL_STR); 295 return; 296 } 297 298 sb.append(OPEN_OBJ); 299 300 boolean addComma = false; 301 Set<Map.Entry<String, String>> entries = map.entrySet(); 302 for (Map.Entry<String, String> entry : entries) { 303 if (addComma) { 304 sb.append(VALUE_SEPARATOR); 305 } 306 addComma = true; 307 appenderMember(sb, jsonEscapedToString(entry.getKey()), jsonEscapedToString(entry.getValue())); 308 } 309 310 sb.append(CLOSE_OBJ); 311 } 312 313 protected void appendThrowableProxy(StringBuilder sb, String attributeName, IThrowableProxy itp) { 314 appendThrowableProxy(sb, attributeName, itp, true); 315 } 316 317 protected void appendThrowableProxy(StringBuilder sb, String attributeName, IThrowableProxy itp, boolean appendValueSeparator) { 318 319 if (appendValueSeparator) 320 sb.append(VALUE_SEPARATOR); 321 322 // in the nominal case, attributeName != null. However, attributeName will be null for suppressed 323 // IThrowableProxy array, in which case no attribute name is needed 324 if (attributeName != null) { 325 sb.append(QUOTE).append(attributeName).append(QUOTE_COL); 326 if (itp == null) { 327 sb.append(NULL_STR); 328 return; 329 } 330 } 331 332 sb.append(OPEN_OBJ); 333 334 appenderMember(sb, CLASS_NAME_ATTR_NAME, nullSafeStr(itp.getClassName())); 335 336 sb.append(VALUE_SEPARATOR); 337 appenderMember(sb, MESSAGE_ATTR_NAME, jsonEscape(itp.getMessage())); 338 339 if (itp.isCyclic()) { 340 sb.append(VALUE_SEPARATOR); 341 appenderMember(sb, CYCLIC_THROWABLE_ATTR_NAME, jsonEscape("true")); 342 } 343 344 sb.append(VALUE_SEPARATOR); 345 appendSTEPArray(sb, itp.getStackTraceElementProxyArray(), itp.getCommonFrames()); 346 347 if (itp.getCommonFrames() != 0) { 348 sb.append(VALUE_SEPARATOR); 349 appenderMemberWithIntValue(sb, COMMON_FRAMES_COUNT_ATTR_NAME, itp.getCommonFrames()); 350 } 351 352 IThrowableProxy cause = itp.getCause(); 353 if (cause != null) { 354 appendThrowableProxy(sb, CAUSE_ATTR_NAME, cause); 355 } 356 357 IThrowableProxy[] suppressedArray = itp.getSuppressed(); 358 if (suppressedArray != null && suppressedArray.length != 0) { 359 sb.append(VALUE_SEPARATOR); 360 sb.append(QUOTE).append(SUPPRESSED_ATTR_NAME).append(QUOTE_COL); 361 sb.append(OPEN_ARRAY); 362 363 boolean first = true; 364 for (IThrowableProxy suppressedITP : suppressedArray) { 365 appendThrowableProxy(sb, null, suppressedITP, !first); 366 if (first) 367 first = false; 368 } 369 sb.append(CLOSE_ARRAY); 370 } 371 372 sb.append(CLOSE_OBJ); 373 374 } 375 376 protected void appendSTEPArray(StringBuilder sb, StackTraceElementProxy[] stepArray, int commonFrames) { 377 sb.append(QUOTE).append(STEP_ARRAY_NAME_ATTRIBUTE).append(QUOTE_COL).append(OPEN_ARRAY); 378 379 // If there are no stack trace elements, write an empty array and return early. 380 if (stepArray == null || stepArray.length == 0) { 381 sb.append(CLOSE_ARRAY); 382 return; 383 } 384 385 int len = stepArray.length; 386 387 if (commonFrames >= len) { 388 commonFrames = 0; 389 } 390 391 for (int i = 0; i < len - commonFrames; i++) { 392 if (i != 0) 393 sb.append(VALUE_SEPARATOR); 394 395 StackTraceElementProxy step = stepArray[i]; 396 397 sb.append(OPEN_OBJ); 398 StackTraceElement ste = step.getStackTraceElement(); 399 400 appenderMember(sb, CLASS_NAME_ATTR_NAME, nullSafeStr(ste.getClassName())); 401 sb.append(VALUE_SEPARATOR); 402 403 appenderMember(sb, METHOD_NAME_ATTR_NAME, nullSafeStr(ste.getMethodName())); 404 sb.append(VALUE_SEPARATOR); 405 406 appenderMember(sb, FILE_NAME_ATTR_NAME, nullSafeStr(ste.getFileName())); 407 sb.append(VALUE_SEPARATOR); 408 409 appenderMemberWithIntValue(sb, LINE_NUMBER_ATTR_NAME, ste.getLineNumber()); 410 sb.append(CLOSE_OBJ); 411 412 } 413 414 sb.append(CLOSE_ARRAY); 415 } 416 417 /** 418 * Hook allowing subclasses to append additional fields into the root JSON object. 419 * Default implementation is a no-op. 420 * 421 * <p>Subclasses may append additional top-level JSON members here. If a 422 * subclass writes additional members it should prepend them with 423 * {@link #VALUE_SEPARATOR} (a comma) if necessary to keep the JSON valid. 424 * Implementations must not close the root JSON object or write the final 425 * line separator; {@link JsonEncoder} handles those.</p> 426 * 427 * @param sb the StringBuilder that accumulates the JSON output; never null 428 * @param event the logging event being encoded; never null 429 */ 430 protected void appendCustomFields(StringBuilder sb, ILoggingEvent event) { 431 // no-op by default; subclasses may append VALUE_SEPARATOR then their fields 432 } 433 434 protected void appenderMember(StringBuilder sb, String key, String value) { 435 sb.append(QUOTE).append(key).append(QUOTE_COL).append(QUOTE).append(value).append(QUOTE); 436 } 437 438 protected void appenderMemberWithIntValue(StringBuilder sb, String key, int value) { 439 sb.append(QUOTE).append(key).append(QUOTE_COL).append(value); 440 } 441 442 protected void appenderMemberWithLongValue(StringBuilder sb, String key, long value) { 443 sb.append(QUOTE).append(key).append(QUOTE_COL).append(value); 444 } 445 446 protected void appendKeyValuePairs(StringBuilder sb, ILoggingEvent event) { 447 List<KeyValuePair> kvpList = event.getKeyValuePairs(); 448 if (kvpList == null || kvpList.isEmpty()) 449 return; 450 451 sb.append(VALUE_SEPARATOR); 452 sb.append(QUOTE).append(KEY_VALUE_PAIRS_ATTR_NAME).append(QUOTE_COL).append(SP).append(OPEN_ARRAY); 453 final int len = kvpList.size(); 454 for (int i = 0; i < len; i++) { 455 if (i != 0) 456 sb.append(VALUE_SEPARATOR); 457 KeyValuePair kvp = kvpList.get(i); 458 sb.append(OPEN_OBJ); 459 appenderMember(sb, jsonEscapedToString(kvp.key), jsonEscapedToString(kvp.value)); 460 sb.append(CLOSE_OBJ); 461 } 462 sb.append(CLOSE_ARRAY); 463 } 464 465 protected void appendArgumentArray(StringBuilder sb, ILoggingEvent event) { 466 Object[] argumentArray = event.getArgumentArray(); 467 if (argumentArray == null) 468 return; 469 470 sb.append(VALUE_SEPARATOR); 471 sb.append(QUOTE).append(ARGUMENT_ARRAY_ATTR_NAME).append(QUOTE_COL).append(SP).append(OPEN_ARRAY); 472 final int len = argumentArray.length; 473 for (int i = 0; i < len; i++) { 474 if (i != 0) 475 sb.append(VALUE_SEPARATOR); 476 sb.append(QUOTE).append(jsonEscapedToString(argumentArray[i])).append(QUOTE); 477 478 } 479 sb.append(CLOSE_ARRAY); 480 } 481 482 protected void appendMarkers(StringBuilder sb, ILoggingEvent event) { 483 List<Marker> markerList = event.getMarkerList(); 484 if (markerList == null) 485 return; 486 487 sb.append(VALUE_SEPARATOR); 488 sb.append(QUOTE).append(MARKERS_ATTR_NAME).append(QUOTE_COL).append(SP).append(OPEN_ARRAY); 489 final int len = markerList.size(); 490 for (int i = 0; i < len; i++) { 491 if (i != 0) 492 sb.append(VALUE_SEPARATOR); 493 sb.append(QUOTE).append(jsonEscapedToString(markerList.get(i))).append(QUOTE); 494 495 } 496 sb.append(CLOSE_ARRAY); 497 } 498 499 private String jsonEscapedToString(Object o) { 500 if (o == null) 501 return NULL_STR; 502 return jsonEscapeString(o.toString()); 503 } 504 505 private String nullSafeStr(String s) { 506 if (s == null) 507 return NULL_STR; 508 return s; 509 } 510 511 private String jsonEscape(String s) { 512 if (s == null) 513 return NULL_STR; 514 return jsonEscapeString(s); 515 } 516 517 protected void appendMDC(StringBuilder sb, ILoggingEvent event) { 518 Map<String, String> map = event.getMDCPropertyMap(); 519 sb.append(VALUE_SEPARATOR); 520 sb.append(QUOTE).append(MDC_ATTR_NAME).append(QUOTE_COL).append(SP).append(OPEN_OBJ); 521 if (isNotEmptyMap(map)) { 522 Set<Map.Entry<String, String>> entrySet = map.entrySet(); 523 int i = 0; 524 for (Map.Entry<String, String> entry : entrySet) { 525 if (i != 0) 526 sb.append(VALUE_SEPARATOR); 527 appenderMember(sb, jsonEscapedToString(entry.getKey()), jsonEscapedToString(entry.getValue())); 528 i++; 529 } 530 531 } 532 sb.append(CLOSE_OBJ); 533 } 534 535 /** 536 * Return {@code true} when the provided map is non-null and non-empty. 537 * 538 * @param map the map to check; may be null 539 * @return {@code true} if the map contains at least one entry 540 */ 541 boolean isNotEmptyMap(Map<?, ?> map) { 542 if (map == null) 543 return false; 544 return !map.isEmpty(); 545 } 546 547 @Override 548 public byte[] footerBytes() { 549 return EMPTY_BYTES; 550 } 551 552 /** 553 * Set whether the sequence number is included in each encoded event. 554 * @param withSequenceNumber {@code true} to include the sequence number in the output 555 * @since 1.5.0 556 */ 557 public void setWithSequenceNumber(boolean withSequenceNumber) { 558 this.withSequenceNumber = withSequenceNumber; 559 } 560 561 /** 562 * Set whether the event timestamp is included in each encoded event. 563 * @param withTimestamp {@code true} to include the event timestamp in the output 564 * @since 1.5.0 565 */ 566 public void setWithTimestamp(boolean withTimestamp) { 567 this.withTimestamp = withTimestamp; 568 } 569 570 /** 571 * Set whether nanoseconds will be included in the timestamp output. 572 * @param withNanoseconds {@code true} to include nanoseconds in the timestamp output 573 * @since 1.5.0 574 */ 575 public void setWithNanoseconds(boolean withNanoseconds) { 576 this.withNanoseconds = withNanoseconds; 577 } 578 579 /** 580 * Enable or disable the inclusion of the log level in the encoded output. 581 * 582 * @param withLevel {@code true} to include the log level. Default is {@code true}. 583 */ 584 public void setWithLevel(boolean withLevel) { 585 this.withLevel = withLevel; 586 } 587 588 /** 589 * Enable or disable the inclusion of the thread name in the encoded output. 590 * 591 * @param withThreadName {@code true} to include the thread name. Default is {@code true}. 592 */ 593 public void setWithThreadName(boolean withThreadName) { 594 this.withThreadName = withThreadName; 595 } 596 597 /** 598 * Enable or disable the inclusion of the logger name in the encoded output. 599 * 600 * @param withLoggerName {@code true} to include the logger name. Default is {@code true}. 601 */ 602 public void setWithLoggerName(boolean withLoggerName) { 603 this.withLoggerName = withLoggerName; 604 } 605 606 /** 607 * Enable or disable the inclusion of the logger context information. 608 * 609 * @param withContext {@code true} to include the logger context. Default is {@code true}. 610 */ 611 public void setWithContext(boolean withContext) { 612 this.withContext = withContext; 613 } 614 615 /** 616 * Enable or disable the inclusion of markers in the encoded output. 617 * 618 * @param withMarkers {@code true} to include markers. Default is {@code true}. 619 */ 620 public void setWithMarkers(boolean withMarkers) { 621 this.withMarkers = withMarkers; 622 } 623 624 /** 625 * Enable or disable the inclusion of MDC properties in the encoded output. 626 * 627 * @param withMDC {@code true} to include MDC properties. Default is {@code true}. 628 */ 629 public void setWithMDC(boolean withMDC) { 630 this.withMDC = withMDC; 631 } 632 633 /** 634 * Enable or disable the inclusion of key-value pairs attached to the logging event. 635 * 636 * @param withKVPList {@code true} to include the key/value pairs list. Default is {@code true}. 637 */ 638 public void setWithKVPList(boolean withKVPList) { 639 this.withKVPList = withKVPList; 640 } 641 642 /** 643 * Enable or disable the inclusion of the raw message text in the encoded output. 644 * 645 * @param withMessage {@code true} to include the message. Default is {@code true}. 646 */ 647 public void setWithMessage(boolean withMessage) { 648 this.withMessage = withMessage; 649 } 650 651 /** 652 * Enable or disable the inclusion of the event argument array in the encoded output. 653 * 654 * @param withArguments {@code true} to include the argument array. Default is {@code true}. 655 */ 656 public void setWithArguments(boolean withArguments) { 657 this.withArguments = withArguments; 658 } 659 660 /** 661 * Enable or disable the inclusion of throwable information in the encoded output. 662 * 663 * @param withThrowable {@code true} to include throwable/stacktrace information. Default is {@code true}. 664 */ 665 public void setWithThrowable(boolean withThrowable) { 666 this.withThrowable = withThrowable; 667 } 668 669 /** 670 * Enable or disable the inclusion of the formatted message in the encoded output. 671 * 672 * @param withFormattedMessage {@code true} to include the formatted message. Default is {@code false}. 673 */ 674 public void setWithFormattedMessage(boolean withFormattedMessage) { 675 this.withFormattedMessage = withFormattedMessage; 676 } 677 678 }