1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.slf4j.implTest;
16
17 import ch.qos.logback.classic.ClassicConstants;
18 import ch.qos.logback.classic.ClassicTestConstants;
19 import ch.qos.logback.classic.spi.ILoggingEvent;
20 import ch.qos.logback.core.read.ListAppender;
21 import org.junit.jupiter.api.AfterEach;
22 import org.junit.jupiter.api.BeforeEach;
23 import org.junit.jupiter.api.Test;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26 import org.slf4j.LoggerFactoryFriend;
27 import org.slf4j.helpers.SubstituteLogger;
28
29 import java.util.List;
30 import java.util.Random;
31 import java.util.concurrent.BrokenBarrierException;
32 import java.util.concurrent.CyclicBarrier;
33 import java.util.concurrent.atomic.AtomicLong;
34
35 import static org.junit.jupiter.api.Assertions.assertEquals;
36 import static org.junit.jupiter.api.Assertions.assertNotNull;
37
38 public class MultithreadedInitializationTest {
39
40 final static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2;
41 private static AtomicLong EVENT_COUNT = new AtomicLong(0);
42 final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1);
43
44 int diff = new Random().nextInt(10000);
45 String loggerName = "org.slf4j.impl.MultithreadedInitializationTest";
46
47 @BeforeEach
48 public void setUp() throws Exception {
49 System.setProperty(ClassicConstants.CONFIG_FILE_PROPERTY,
50 ClassicTestConstants.INPUT_PREFIX + "listAppender.xml");
51 LoggerFactoryFriend.reset();
52 }
53
54 @AfterEach
55 public void tearDown() throws Exception {
56 System.clearProperty(ClassicConstants.CONFIG_FILE_PROPERTY);
57 }
58
59 @Test
60 public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException {
61 LoggerAccessingThread[] accessors = harness();
62
63 for (LoggerAccessingThread accessor : accessors) {
64 EVENT_COUNT.getAndIncrement();
65 accessor.logger.info("post harness");
66 }
67
68 Logger logger = LoggerFactory.getLogger(loggerName + ".slowInitialization-" + diff);
69 logger.info("hello");
70 EVENT_COUNT.getAndIncrement();
71
72 List<ILoggingEvent> events = getRecordedEvents();
73 assertEquals(EVENT_COUNT.get(), events.size());
74 }
75
76 private List<ILoggingEvent> getRecordedEvents() {
77 ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory
78 .getLogger(Logger.ROOT_LOGGER_NAME);
79
80 ListAppender<ILoggingEvent> la = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
81 assertNotNull(la);
82 return la.list;
83 }
84
85 private static LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException {
86 LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT];
87 final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1);
88 for (int i = 0; i < THREAD_COUNT; i++) {
89 threads[i] = new LoggerAccessingThread(barrier, i);
90 threads[i].start();
91 }
92
93 barrier.await();
94 for (int i = 0; i < THREAD_COUNT; i++) {
95 threads[i].join();
96 }
97 return threads;
98 }
99
100 static class LoggerAccessingThread extends Thread {
101 final CyclicBarrier barrier;
102 Logger logger;
103 int count;
104
105 LoggerAccessingThread(CyclicBarrier barrier, int count) {
106 this.barrier = barrier;
107 this.count = count;
108 }
109
110 public void run() {
111 try {
112 barrier.await();
113 } catch (Exception e) {
114 e.printStackTrace();
115 }
116 logger = LoggerFactory.getLogger(this.getClass().getName() + "-" + count);
117 logger.info("in run method");
118 if (logger instanceof SubstituteLogger) {
119 SubstituteLogger substLogger = (SubstituteLogger) logger;
120 if (!substLogger.createdPostInitialization) {
121 EVENT_COUNT.getAndIncrement();
122 }
123 } else {
124 EVENT_COUNT.getAndIncrement();
125 }
126 }
127 };
128
129 }