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 }