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