001package org.slf4j.impl; 002 003import static org.junit.Assert.assertEquals; 004import static org.junit.Assert.assertNotNull; 005 006import java.util.List; 007import java.util.Random; 008import java.util.concurrent.BrokenBarrierException; 009import java.util.concurrent.CyclicBarrier; 010import java.util.concurrent.atomic.AtomicLong; 011 012import org.junit.After; 013import org.junit.Before; 014import org.junit.Test; 015import org.slf4j.Logger; 016import org.slf4j.LoggerFactory; 017import org.slf4j.LoggerFactoryFriend; 018import org.slf4j.helpers.SubstituteLogger; 019 020import ch.qos.logback.classic.ClassicConstants; 021import ch.qos.logback.classic.ClassicTestConstants; 022import ch.qos.logback.classic.spi.ILoggingEvent; 023import ch.qos.logback.core.read.ListAppender; 024 025public class MultithreadedInitializationTest { 026 027 final static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2; 028 private static AtomicLong EVENT_COUNT = new AtomicLong(0); 029 final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); 030 031 int diff = new Random().nextInt(10000); 032 String loggerName = "org.slf4j.impl.MultithreadedInitializationTest"; 033 034 @Before 035 public void setUp() throws Exception { 036 System.setProperty(ClassicConstants.CONFIG_FILE_PROPERTY, ClassicTestConstants.INPUT_PREFIX + "listAppender.xml"); 037 LoggerFactoryFriend.reset(); 038 } 039 040 @After 041 public void tearDown() throws Exception { 042 System.clearProperty(ClassicConstants.CONFIG_FILE_PROPERTY); 043 } 044 045 @Test 046 public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException { 047 LoggerAccessingThread[] accessors = harness(); 048 049 for (LoggerAccessingThread accessor : accessors) { 050 EVENT_COUNT.getAndIncrement(); 051 accessor.logger.info("post harness"); 052 } 053 054 Logger logger = LoggerFactory.getLogger(loggerName + ".slowInitialization-" + diff); 055 logger.info("hello"); 056 EVENT_COUNT.getAndIncrement(); 057 058 List<ILoggingEvent> events = getRecordedEvents(); 059 assertEquals(EVENT_COUNT.get(), events.size()); 060 } 061 062 private List<ILoggingEvent> getRecordedEvents() { 063 ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); 064 065 ListAppender<ILoggingEvent> la = (ListAppender<ILoggingEvent>) root.getAppender("LIST"); 066 assertNotNull(la); 067 return la.list; 068 } 069 070 private static LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException { 071 LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT]; 072 final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); 073 for (int i = 0; i < THREAD_COUNT; i++) { 074 threads[i] = new LoggerAccessingThread(barrier, i); 075 threads[i].start(); 076 } 077 078 barrier.await(); 079 for (int i = 0; i < THREAD_COUNT; i++) { 080 threads[i].join(); 081 } 082 return threads; 083 } 084 085 static class LoggerAccessingThread extends Thread { 086 final CyclicBarrier barrier; 087 Logger logger; 088 int count; 089 090 LoggerAccessingThread(CyclicBarrier barrier, int count) { 091 this.barrier = barrier; 092 this.count = count; 093 } 094 095 public void run() { 096 try { 097 barrier.await(); 098 } catch (Exception e) { 099 e.printStackTrace(); 100 } 101 logger = LoggerFactory.getLogger(this.getClass().getName() + "-" + count); 102 logger.info("in run method"); 103 if (logger instanceof SubstituteLogger) { 104 SubstituteLogger substLogger = (SubstituteLogger) logger; 105 if (!substLogger.createdPostInitialization) { 106 EVENT_COUNT.getAndIncrement(); 107 } 108 } else { 109 EVENT_COUNT.getAndIncrement(); 110 } 111 } 112 }; 113 114}