Skip to content

Commit 44fbe63

Browse files
committed
MaskedKeyValuePairConverter test issues/828, NPE in AppeanderAttachableImpl issues/822
Signed-off-by: Ceki Gulcu <[email protected]>
1 parent e7d9459 commit 44fbe63

File tree

7 files changed

+262
-1
lines changed

7 files changed

+262
-1
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public final class Logger
7272
/**
7373
* It is assumed that once the 'aai' variable is set to a non-null value, it
7474
* will never be reset to null. it is further assumed that only place where the
75-
* 'aai'ariable is set is within the addAppender method. This method is
75+
* 'aai variable is set is within the addAppender method. This method is
7676
* synchronized on 'this' (Logger) protecting against simultaneous
7777
* re-configuration of this logger (a very unlikely scenario).
7878
*

logback-classic/src/main/java/ch/qos/logback/classic/pattern/MaskedKeyValuePairConverter.java

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
* Assuming the specified key is k2, and the kvp list of an event contains {k1, v1}, {k2, v2}, the String output
3131
* will be "k1=v1 k2=XXX", without the quotes.
3232
*
33+
* Value quotes can be specified as the first option, e.g %maskedKvp{SINGLE, k1}
34+
*
3335
* @author Ceki G&uuml;lc&uuml;
3436
* @since 1.5.7
3537
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<configuration>
2+
3+
4+
<appender name="LIST" class="ch.qos.logback.core.testUtil.StringListAppender">
5+
<layout class="ch.qos.logback.classic.PatternLayout">
6+
<Pattern>%sample - %msg</Pattern>
7+
</layout>
8+
</appender>
9+
10+
<conversionRule conversionWord="sample"
11+
converterClass="ch.qos.logback.classic.pattern.SampleConverter" />
12+
13+
<root level="debug">
14+
<appender-ref ref="LIST" />
15+
</root>
16+
</configuration>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<included>
2+
3+
4+
<appender name="LIST" class="ch.qos.logback.core.testUtil.StringListAppender">
5+
<layout class="ch.qos.logback.classic.PatternLayout">
6+
<Pattern>%sample - %msg</Pattern>
7+
</layout>
8+
</appender>
9+
10+
<conversionRule conversionWord="sample"
11+
converterClass="ch.qos.logback.classic.pattern.SampleConverter" />
12+
13+
<root level="debug">
14+
<appender-ref ref="LIST" />
15+
</root>
16+
</included>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<configuration>
2+
3+
4+
<appender name="LIST" class="ch.qos.logback.core.testUtil.StringListAppender">
5+
<layout class="ch.qos.logback.classic.PatternLayout">
6+
<Pattern>%sample - %msg</Pattern>
7+
</layout>
8+
</appender>
9+
10+
<include file="src/test/input/joran/conversionRule/conversionRuleIncluded.xml"/>
11+
12+
<root level="debug">
13+
<appender-ref ref="LIST" />
14+
</root>
15+
</configuration>

logback-classic/src/test/java/ch/qos/logback/classic/PatternLayoutTest.java

+24
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,30 @@ public void testConversionRuleSupportInPatternLayout() throws JoranException {
236236
assertEquals(SampleConverter.SAMPLE_STR + " - " + msg, sla.strList.get(0));
237237
}
238238

239+
@Test
240+
public void testConversionRuleAtEnd() throws JoranException {
241+
configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "conversionRule/conversionRuleAtEnd.xml");
242+
root.getAppender("LIST");
243+
String msg = "testConversionRuleAtEnd";
244+
logger.debug(msg);
245+
StringListAppender<ILoggingEvent> sla = (StringListAppender<ILoggingEvent>) root.getAppender("LIST");
246+
assertNotNull(sla);
247+
assertEquals(1, sla.strList.size());
248+
assertEquals(SampleConverter.SAMPLE_STR + " - " + msg, sla.strList.get(0));
249+
}
250+
251+
@Test
252+
public void testConversionRuleInIncluded() throws JoranException {
253+
configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "conversionRule/conversionRuleTop0.xml");
254+
root.getAppender("LIST");
255+
String msg = "testConversionRuleInIncluded";
256+
logger.debug(msg);
257+
StringListAppender<ILoggingEvent> sla = (StringListAppender<ILoggingEvent>) root.getAppender("LIST");
258+
assertNotNull(sla);
259+
assertEquals(1, sla.strList.size());
260+
assertEquals(SampleConverter.SAMPLE_STR + " - " + msg, sla.strList.get(0));
261+
}
262+
239263
@Test
240264
public void smokeReplace() {
241265
pl.setPattern("%replace(a1234b){'\\d{4}', 'XXXX'}");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
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.core.util;
16+
17+
import ch.qos.logback.core.Appender;
18+
import ch.qos.logback.core.AppenderBase;
19+
import ch.qos.logback.core.Context;
20+
import ch.qos.logback.core.ContextBase;
21+
import ch.qos.logback.core.spi.AppenderAttachableImpl;
22+
import org.junit.jupiter.api.Disabled;
23+
import org.junit.jupiter.api.Test;
24+
25+
import java.util.concurrent.ExecutionException;
26+
import java.util.concurrent.ExecutorService;
27+
import java.util.concurrent.Executors;
28+
29+
import java.util.ArrayList;
30+
import java.util.Arrays;
31+
import java.util.List;
32+
import java.util.concurrent.Future;
33+
import java.util.concurrent.locks.ReentrantLock;
34+
35+
import static org.assertj.core.api.Fail.fail;
36+
37+
@Disabled
38+
public class COWArrayListConcurrencyTest {
39+
40+
//private static final int LIST_SIZE = 1_000_000;
41+
private static final int LOOP_LEN = 1_0;
42+
private static final int RECONFIGURE_DELAY = 1;
43+
44+
ReentrantLock reconfigureLock = new ReentrantLock(true);
45+
ReentrantLock writeLock = new ReentrantLock(true);
46+
47+
private static int THREAD_COUNT = 200; //Runtime.getRuntime().availableProcessors()*200;
48+
//private static int THREAD_COUNT = 5000;
49+
50+
private final ExecutorService tasksExecutor = Executors.newVirtualThreadPerTaskExecutor();
51+
LoopingRunnable[] loopingThreads = new LoopingRunnable[THREAD_COUNT];
52+
ReconfiguringThread[] reconfiguringThreads = new ReconfiguringThread[THREAD_COUNT];
53+
Future<?>[] futures = new Future[THREAD_COUNT];
54+
55+
AppenderAttachableImpl<String> aai = new AppenderAttachableImpl<>();
56+
Context context = new ContextBase();
57+
58+
void reconfigureWithDelay(AppenderAttachableImpl<String> aai) {
59+
try {
60+
reconfigureLock.lock();
61+
aai.addAppender(makeNewNOPAppender());
62+
aai.addAppender(makeNewNOPAppender());
63+
delay(RECONFIGURE_DELAY);
64+
aai.detachAndStopAllAppenders();
65+
} finally {
66+
reconfigureLock.unlock();
67+
}
68+
}
69+
70+
private Appender<String> makeNewNOPAppender() {
71+
List<Long> longList = new ArrayList<>();
72+
// for (int j = 0; j < LIST_SIZE; j++) {
73+
// longList.add(0L);
74+
// }
75+
Appender<String> nopAppenderWithDelay = new NOPAppenderWithDelay<>(longList);
76+
nopAppenderWithDelay.setContext(context);
77+
nopAppenderWithDelay.start();
78+
return nopAppenderWithDelay;
79+
}
80+
81+
private void delay(int delay) {
82+
try {
83+
Thread.sleep(delay);
84+
} catch (InterruptedException e) {
85+
throw new RuntimeException(e);
86+
}
87+
}
88+
89+
@Test
90+
void smoke() throws InterruptedException, ExecutionException {
91+
92+
for (int i = 0; i < THREAD_COUNT; i++) {
93+
System.out.println("i="+i);
94+
ReconfiguringThread rt = new ReconfiguringThread(aai);
95+
futures[i] = tasksExecutor.submit(rt);
96+
reconfiguringThreads[i] = rt;
97+
}
98+
99+
for (int i = 0; i < THREAD_COUNT; i++) {
100+
LoopingRunnable loopingThread = new LoopingRunnable(i, aai);
101+
tasksExecutor.submit(loopingThread);
102+
loopingThreads[i] = loopingThread;
103+
}
104+
105+
for (int i = 0; i < THREAD_COUNT; i++) {
106+
futures[i].get();
107+
}
108+
109+
//reconfiguringThread.join();
110+
Arrays.stream(loopingThreads).forEach(lt -> lt.active = false);
111+
112+
}
113+
114+
public class NOPAppenderWithDelay<E> extends AppenderBase<E> {
115+
116+
List<Long> longList;
117+
118+
NOPAppenderWithDelay(List<Long> longList) {
119+
this.longList = new ArrayList<>(longList);
120+
}
121+
122+
int i = 0;
123+
124+
@Override
125+
protected void append(E eventObject) {
126+
i++;
127+
try {
128+
writeLock.lock();
129+
if ((i & 0xF) == 0) {
130+
delay(1);
131+
} else {
132+
//longList.stream().map(x-> x+1);
133+
}
134+
} finally {
135+
writeLock.unlock();
136+
}
137+
138+
}
139+
140+
}
141+
142+
class ReconfiguringThread extends Thread {
143+
144+
AppenderAttachableImpl<String> aai;
145+
146+
ReconfiguringThread(AppenderAttachableImpl aai) {
147+
this.aai = aai;
148+
}
149+
150+
public void run() {
151+
Thread.yield();
152+
for (int i = 0; i < LOOP_LEN; i++) {
153+
reconfigureWithDelay(aai);
154+
}
155+
}
156+
157+
158+
}
159+
160+
161+
class LoopingRunnable implements Runnable {
162+
163+
int num;
164+
AppenderAttachableImpl<String> aai;
165+
public boolean active = true;
166+
167+
LoopingRunnable(int num, AppenderAttachableImpl aai) {
168+
this.num = num;
169+
this.aai = aai;
170+
}
171+
172+
public void run() {
173+
System.out.println("LoopingRunnable.run.num="+num);
174+
int i = 0;
175+
while (active) {
176+
if ((i & 0xFFFFF) == 0) {
177+
long id = Thread.currentThread().threadId();
178+
System.out.println("thread=" + id + " reconfigure=" + i);
179+
}
180+
aai.appendLoopOnAppenders(Integer.toString(i));
181+
i++;
182+
//Thread.yield();
183+
}
184+
}
185+
}
186+
187+
188+
}

0 commit comments

Comments
 (0)