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}