1   /*
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v2.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  
15  package ch.qos.logback.classic.pattern;
16  
17  import java.util.List;
18  
19  import org.slf4j.event.KeyValuePair;
20  
21  import ch.qos.logback.classic.spi.ILoggingEvent;
22  import ch.qos.logback.core.CoreConstants;
23  
24  /**
25   * Convert the contents of {@link KeyValuePair} list to a String.
26   * 
27   * Assuming the list contains the list {k1, v1}, {k2, v2}, the String output
28   * will be "k1=v1 k2=v2", without the quotes.
29   *
30   * 
31   * @since 1.3.0
32   * @author Ceki Gülcü
33   *
34   */
35  public class KeyValuePairConverter extends ClassicConverter {
36  
37      static final String DOUBLE_OPTION_STR = "DOUBLE";
38      static final String SINGLE_OPTION_STR = "SINGLE";
39      static final String NONE_OPTION_STR = "NONE";
40  
41      enum ValueQuoteSpecification {
42          NONE, SINGLE, DOUBLE;
43  
44          Character asChar() {
45              switch (this) {
46              case NONE:
47                  return null;
48              case DOUBLE:
49                  return '"';
50              case SINGLE:
51                  return '\'';
52              default:
53                  throw new IllegalStateException();
54              }
55          }
56      }
57  
58      ValueQuoteSpecification valueQuoteSpec = ValueQuoteSpecification.DOUBLE;
59  
60      public void start() {
61          String optStr = getFirstOption();
62          valueQuoteSpec = optionStrToSpec(optStr);
63          super.start();
64      }
65  
66      private ValueQuoteSpecification optionStrToSpec(String optStr) {
67          if (optStr == null)
68              return ValueQuoteSpecification.DOUBLE;
69          if (DOUBLE_OPTION_STR.equalsIgnoreCase(optStr))
70              return ValueQuoteSpecification.DOUBLE;
71          if (SINGLE_OPTION_STR.equalsIgnoreCase(optStr))
72              return ValueQuoteSpecification.SINGLE;
73          if (NONE_OPTION_STR.equalsIgnoreCase(optStr))
74              return ValueQuoteSpecification.NONE;
75          return ValueQuoteSpecification.DOUBLE;
76      }
77  
78      @Override
79      public String convert(ILoggingEvent event) {
80  
81          List<KeyValuePair> kvpList = event.getKeyValuePairs();
82          if (kvpList == null || kvpList.isEmpty()) {
83              return CoreConstants.EMPTY_STRING;
84          }
85  
86          StringBuilder sb = new StringBuilder();
87          for (int i = 0; i < kvpList.size(); i++) {
88              KeyValuePair kvp = kvpList.get(i);
89              if (i != 0)
90                  sb.append(' ');
91              sb.append(String.valueOf(kvp.key));
92              sb.append('=');
93              Character quoteChar = valueQuoteSpec.asChar();
94              if (quoteChar != null)
95                  sb.append(quoteChar);
96              sb.append(String.valueOf(kvp.value));
97              if (quoteChar != null)
98                  sb.append(quoteChar);
99          }
100 
101         return sb.toString();
102     }
103 
104 }