Skip to content

Commit e7d9459

Browse files
committed
migrate conversionWord to model based configuration, add MaskedKeyValuePairConverter
Signed-off-by: Ceki Gulcu <[email protected]>
1 parent 500203f commit e7d9459

File tree

8 files changed

+324
-109
lines changed

8 files changed

+324
-109
lines changed

logback-classic/src/main/java/ch/qos/logback/classic/PatternLayout.java

+3
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ public class PatternLayout extends PatternLayoutBase<ILoggingEvent> {
128128
DEFAULT_CONVERTER_MAP.put("kvp", KeyValuePairConverter.class.getName());
129129
CONVERTER_CLASS_TO_KEY_MAP.put(KeyValuePairConverter.class.getName(), "kvp");
130130

131+
DEFAULT_CONVERTER_MAP.put("maskedKvp", MaskedKeyValuePairConverter.class.getName());
132+
CONVERTER_CLASS_TO_KEY_MAP.put(MaskedKeyValuePairConverter.class.getName(), "maskedKvp");
133+
131134
DEFAULT_CONVERTER_MAP.put("property", PropertyConverter.class.getName());
132135

133136
DEFAULT_CONVERTER_MAP.put("n", LineSeparatorConverter.class.getName());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Logback: the reliable, generic, fast and flexible logging framework.
3+
* Copyright (C) 1999-2024, 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 v1.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+
18+
import ch.qos.logback.classic.spi.ILoggingEvent;
19+
import ch.qos.logback.core.CoreConstants;
20+
import org.slf4j.event.KeyValuePair;
21+
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
25+
import static ch.qos.logback.classic.pattern.KeyValuePairConverter.*;
26+
27+
/**
28+
* Similar to {@link KeyValuePairConverter} with the added ability to mask the values of specified keys.
29+
* <p>
30+
* Assuming the specified key is k2, and the kvp list of an event contains {k1, v1}, {k2, v2}, the String output
31+
* will be "k1=v1 k2=XXX", without the quotes.
32+
*
33+
* @author Ceki G&uuml;lc&uuml;
34+
* @since 1.5.7
35+
*/
36+
37+
38+
public class MaskedKeyValuePairConverter extends ClassicConverter {
39+
public static final String MASK = "XXX";
40+
List<String> optionList;
41+
List<String> maskList = new ArrayList<>();
42+
KeyValuePairConverter.ValueQuoteSpecification valueQuoteSpec = KeyValuePairConverter.ValueQuoteSpecification.DOUBLE;
43+
44+
public void start() {
45+
this.optionList = getOptionList();
46+
KeyValuePairConverter.ValueQuoteSpecification extractedSpec = extractSpec(this.optionList);
47+
if (extractedSpec == null) {
48+
maskList = optionList;
49+
} else {
50+
valueQuoteSpec = extractedSpec;
51+
maskList = optionList.subList(1, optionList.size());
52+
}
53+
54+
checkMaskListForExtraQuoteSpecs(maskList);
55+
56+
super.start();
57+
}
58+
59+
private void checkMaskListForExtraQuoteSpecs(List<String> maskList) {
60+
if(maskList == null || maskList.isEmpty())
61+
return;
62+
if(maskList.contains(DOUBLE_OPTION_STR)) {
63+
addWarn("quote spec "+DOUBLE_OPTION_STR+ " found in the wrong order");
64+
}
65+
if(maskList.contains(SINGLE_OPTION_STR)) {
66+
addWarn("extra quote spec "+SINGLE_OPTION_STR+ " found in the wrong order");
67+
}
68+
if(maskList.contains(NONE_OPTION_STR)) {
69+
addWarn("extra quote spec "+NONE_OPTION_STR+ " found in the wrong order");
70+
}
71+
}
72+
73+
74+
KeyValuePairConverter.ValueQuoteSpecification extractSpec(List<String> optionList) {
75+
76+
if (optionList == null || optionList.isEmpty()) {
77+
return null;
78+
}
79+
80+
String firstOption = optionList.get(0);
81+
82+
if (DOUBLE_OPTION_STR.equalsIgnoreCase(firstOption)) {
83+
return KeyValuePairConverter.ValueQuoteSpecification.DOUBLE;
84+
} else if (SINGLE_OPTION_STR.equalsIgnoreCase(firstOption)) {
85+
return KeyValuePairConverter.ValueQuoteSpecification.SINGLE;
86+
} else if (NONE_OPTION_STR.equalsIgnoreCase(firstOption)) {
87+
return KeyValuePairConverter.ValueQuoteSpecification.NONE;
88+
} else {
89+
return null;
90+
}
91+
}
92+
93+
@Override
94+
public String convert(ILoggingEvent event) {
95+
96+
List<KeyValuePair> kvpList = event.getKeyValuePairs();
97+
if (kvpList == null || kvpList.isEmpty()) {
98+
return CoreConstants.EMPTY_STRING;
99+
}
100+
101+
StringBuilder sb = new StringBuilder();
102+
for (int i = 0; i < kvpList.size(); i++) {
103+
KeyValuePair kvp = kvpList.get(i);
104+
if (i != 0)
105+
sb.append(' ');
106+
sb.append(String.valueOf(kvp.key));
107+
sb.append('=');
108+
Character quoteChar = valueQuoteSpec.asChar();
109+
if (quoteChar != null)
110+
sb.append(quoteChar);
111+
if (maskList.contains(kvp.key))
112+
sb.append(MASK);
113+
else
114+
sb.append(String.valueOf(kvp.value));
115+
if (quoteChar != null)
116+
sb.append(quoteChar);
117+
}
118+
119+
return sb.toString();
120+
}
121+
}

logback-classic/src/test/java/ch/qos/logback/classic/pattern/KeyValuePairConverterTest.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* Logback: the reliable, generic, fast and flexible logging framework.
3-
* Copyright (C) 1999-2021, QOS.ch. All rights reserved.
3+
* Copyright (C) 1999-2024, QOS.ch. All rights reserved.
44
*
55
* This program and the accompanying materials are dual-licensed under
66
* either the terms of the Eclipse Public License v1.0 as published by
@@ -44,6 +44,14 @@ public void tearDown() throws Exception {
4444
converter = null;
4545
}
4646

47+
@Test
48+
public void smoke() {
49+
event.addKeyValuePair(new KeyValuePair("a", "b"));
50+
event.addKeyValuePair(new KeyValuePair("k", "v"));
51+
String result = converter.convert(event);
52+
assertEquals("a=\"b\" k=\"v\"", result);
53+
}
54+
4755
@Test
4856
public void testWithNullKVPList() {
4957
// event.getKeyValuePairs().add(new KeyValuePair("k", "v"));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Logback: the reliable, generic, fast and flexible logging framework.
3+
* Copyright (C) 1999-2024, 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 v1.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 ch.qos.logback.classic.Level;
18+
import ch.qos.logback.classic.Logger;
19+
import ch.qos.logback.classic.LoggerContext;
20+
import ch.qos.logback.classic.spi.LoggingEvent;
21+
import ch.qos.logback.core.status.Status;
22+
import ch.qos.logback.core.status.testUtil.StatusChecker;
23+
import ch.qos.logback.core.util.StatusPrinter2;
24+
import org.junit.jupiter.api.AfterEach;
25+
import org.junit.jupiter.api.BeforeEach;
26+
import org.junit.jupiter.api.Test;
27+
import org.slf4j.event.KeyValuePair;
28+
29+
import java.util.List;
30+
31+
import static org.junit.jupiter.api.Assertions.assertEquals;
32+
33+
public class MaskedKeyValuePairConverterTest {
34+
35+
LoggerContext lc = new LoggerContext();
36+
MaskedKeyValuePairConverter converter;
37+
LoggingEvent event;
38+
39+
StatusChecker statusChecker = new StatusChecker(lc);
40+
StatusPrinter2 statusPrinter2 = new StatusPrinter2();
41+
42+
@BeforeEach
43+
public void setUp() throws Exception {
44+
converter = new MaskedKeyValuePairConverter();
45+
converter.setContext(lc);
46+
}
47+
48+
@AfterEach
49+
public void tearDown() throws Exception {
50+
lc = null;
51+
converter.stop();
52+
converter = null;
53+
}
54+
55+
@Test
56+
public void smoke() {
57+
event = createLoggingEvent();
58+
converter.setOptionList(List.of("k1"));
59+
converter.start();
60+
61+
event.addKeyValuePair(new KeyValuePair("k1", "v1"));
62+
event.addKeyValuePair(new KeyValuePair("k2", "v2"));
63+
64+
String result = converter.convert(event);
65+
assertEquals("k1=\""+MaskedKeyValuePairConverter.MASK+"\" k2=\"v2\"", result);
66+
}
67+
68+
@Test
69+
public void smokeSingle() {
70+
event = createLoggingEvent();
71+
converter.setOptionList(List.of("SINGLE", "k1"));
72+
converter.start();
73+
74+
event.addKeyValuePair(new KeyValuePair("k1", "v1"));
75+
event.addKeyValuePair(new KeyValuePair("k2", "v2"));
76+
77+
String result = converter.convert(event);
78+
assertEquals("k1='"+MaskedKeyValuePairConverter.MASK+"' k2='v2'", result);
79+
}
80+
81+
@Test
82+
public void wrongOrder() {
83+
event = createLoggingEvent();
84+
converter.setOptionList(List.of("k1", "SINGLE"));
85+
converter.start();
86+
87+
event.addKeyValuePair(new KeyValuePair("k1", "v1"));
88+
event.addKeyValuePair(new KeyValuePair("k2", "v2"));
89+
90+
statusPrinter2.print(lc);
91+
statusChecker.assertContainsMatch(Status.WARN, "extra quote spec SINGLE found in the wrong order");
92+
String result = converter.convert(event);
93+
assertEquals("k1=\""+MaskedKeyValuePairConverter.MASK+"\" k2=\"v2\"", result);
94+
}
95+
96+
@Test
97+
public void testWithOnelKVP() {
98+
event = createLoggingEvent();
99+
converter.setOptionList(List.of("k"));
100+
converter.start();
101+
event.addKeyValuePair(new KeyValuePair("k", "v"));
102+
String result = converter.convert(event);
103+
assertEquals("k=\""+MaskedKeyValuePairConverter.MASK+"\"", result);
104+
}
105+
106+
107+
108+
private LoggingEvent createLoggingEvent() {
109+
LoggingEvent le = new LoggingEvent(this.getClass().getName(), lc.getLogger(Logger.ROOT_LOGGER_NAME),
110+
Level.DEBUG, "test message", null, null);
111+
return le;
112+
}
113+
114+
}

logback-core/src/main/java/ch/qos/logback/core/joran/JoranConfiguratorBase.java

+1-24
Original file line numberDiff line numberDiff line change
@@ -129,30 +129,7 @@ public SaxEventInterpretationContext getInterpretationContext() {
129129

130130
@Override
131131
protected void addModelHandlerAssociations(DefaultProcessor defaultProcessor) {
132-
// code moved to ModelClassToModelHandlerLinkerBase
133-
// the code below is inactive
134-
defaultProcessor.addHandler(ImportModel.class, ImportModelHandler::makeInstance);
135-
136-
defaultProcessor.addHandler(ShutdownHookModel.class, ShutdownHookModelHandler::makeInstance);
137-
defaultProcessor.addHandler(SequenceNumberGeneratorModel.class, SequenceNumberGeneratorModelHandler::makeInstance);
138-
139-
defaultProcessor.addHandler(EventEvaluatorModel.class, EventEvaluatorModelHandler::makeInstance);
140-
defaultProcessor.addHandler(DefineModel.class, DefineModelHandler::makeInstance);
141-
defaultProcessor.addHandler(IncludeModel.class, IncludeModelHandler::makeInstance);
142-
143-
144-
defaultProcessor.addHandler(ParamModel.class, ParamModelHandler::makeInstance);
145-
defaultProcessor.addHandler(PropertyModel.class, PropertyModelHandler::makeInstance);
146-
defaultProcessor.addHandler(TimestampModel.class, TimestampModelHandler::makeInstance);
147-
defaultProcessor.addHandler(StatusListenerModel.class, StatusListenerModelHandler::makeInstance);
148-
defaultProcessor.addHandler(ImplicitModel.class, ImplicitModelHandler::makeInstance);
149-
150-
defaultProcessor.addHandler(IfModel.class, IfModelHandler::makeInstance);
151-
defaultProcessor.addHandler(ThenModel.class, ThenModelHandler::makeInstance);
152-
defaultProcessor.addHandler(ElseModel.class, ElseModelHandler::makeInstance);
153-
154-
defaultProcessor.addHandler(SiftModel.class, SiftModelHandler::makeInstance);
155-
132+
// Please note that code previously here moved to ModelClassToModelHandlerLinkerBase
156133
}
157134

158135
}

logback-core/src/main/java/ch/qos/logback/core/joran/ModelClassToModelHandlerLinkerBase.java

+4-26
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,11 @@
1515
package ch.qos.logback.core.joran;
1616

1717
import ch.qos.logback.core.Context;
18-
import ch.qos.logback.core.model.DefineModel;
19-
import ch.qos.logback.core.model.EventEvaluatorModel;
20-
import ch.qos.logback.core.model.ImplicitModel;
21-
import ch.qos.logback.core.model.ImportModel;
22-
import ch.qos.logback.core.model.IncludeModel;
23-
import ch.qos.logback.core.model.ParamModel;
24-
import ch.qos.logback.core.model.PropertyModel;
25-
import ch.qos.logback.core.model.SequenceNumberGeneratorModel;
26-
import ch.qos.logback.core.model.SerializeModelModel;
27-
import ch.qos.logback.core.model.ShutdownHookModel;
28-
import ch.qos.logback.core.model.SiftModel;
29-
import ch.qos.logback.core.model.StatusListenerModel;
30-
import ch.qos.logback.core.model.TimestampModel;
18+
import ch.qos.logback.core.model.*;
3119
import ch.qos.logback.core.model.conditional.ElseModel;
3220
import ch.qos.logback.core.model.conditional.IfModel;
3321
import ch.qos.logback.core.model.conditional.ThenModel;
34-
import ch.qos.logback.core.model.processor.DefaultProcessor;
35-
import ch.qos.logback.core.model.processor.DefineModelHandler;
36-
import ch.qos.logback.core.model.processor.EventEvaluatorModelHandler;
37-
import ch.qos.logback.core.model.processor.ImplicitModelHandler;
38-
import ch.qos.logback.core.model.processor.ImportModelHandler;
39-
import ch.qos.logback.core.model.processor.IncludeModelHandler;
40-
import ch.qos.logback.core.model.processor.NOPModelHandler;
41-
import ch.qos.logback.core.model.processor.PropertyModelHandler;
42-
import ch.qos.logback.core.model.processor.SequenceNumberGeneratorModelHandler;
43-
import ch.qos.logback.core.model.processor.SerializeModelModelHandler;
44-
import ch.qos.logback.core.model.processor.ShutdownHookModelHandler;
45-
import ch.qos.logback.core.model.processor.StatusListenerModelHandler;
46-
import ch.qos.logback.core.model.processor.TimestampModelHandler;
22+
import ch.qos.logback.core.model.processor.*;
4723
import ch.qos.logback.core.model.processor.conditional.ElseModelHandler;
4824
import ch.qos.logback.core.model.processor.conditional.IfModelHandler;
4925
import ch.qos.logback.core.model.processor.conditional.ThenModelHandler;
@@ -74,6 +50,8 @@ public void link(DefaultProcessor defaultProcessor) {
7450
defaultProcessor.addHandler(SerializeModelModel.class, SerializeModelModelHandler::makeInstance);
7551

7652
defaultProcessor.addHandler(EventEvaluatorModel.class, EventEvaluatorModelHandler::makeInstance);
53+
defaultProcessor.addHandler(ConversionRuleModel.class, ConversionRuleModelHandler::makeInstance);
54+
7755
defaultProcessor.addHandler(DefineModel.class, DefineModelHandler::makeInstance);
7856
defaultProcessor.addHandler(IncludeModel.class, IncludeModelHandler::makeInstance);
7957

0 commit comments

Comments
 (0)