package org.eluder.logback.ext.lmax.appender;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import ch.qos.logback.core.spi.AppenderAttachable;
import org.openjdk.jmh.annotations.*;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@State(Scope.Benchmark)
public abstract class AppenderBenchmark<T extends Appender<ILoggingEvent> & AppenderAttachable<ILoggingEvent>> {
private static final int EVENTS = 32000;
private static final LoggerContext CONTEXT = (LoggerContext) LoggerFactory.getILoggerFactory();
private static final AtomicInteger idx = new AtomicInteger(0);
private static final CountDownLatch[] latches = new CountDownLatch[99999];
@Param({ "1" })
public int consumers;
private EmulatingAppender controller;
private T appender;
@State(Scope.Thread)
public static class ThreadContext {
LoggingEvent event;
int index;
@Setup(Level.Trial)
public void setupContext() {
index = idx.getAndIncrement();
event = new LoggingEvent(
"org.eluder.logback.ext.lmax.appender.AppenderBenchmark",
CONTEXT.getLogger(Logger.ROOT_LOGGER_NAME), ch.qos.logback.classic.Level.INFO, "" + index, null, null
);
}
@Setup(Level.Invocation)
public void setupLatch() {
latches[index] = new CountDownLatch(EVENTS);
}
public void await() throws InterruptedException {
latches[index].await();
}
}
@Setup(Level.Trial)
public void setupAppender() {
controller = new EmulatingAppender(CONTEXT);
appender = createAppender(consumers);
appender.setContext(CONTEXT);
appender.addAppender(controller);
controller.start();
appender.start();
}
@TearDown(Level.Trial)
public void tearDownAppender() {
appender.stop();
controller.stop();
}
protected abstract T createAppender(int consumers);
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
@OperationsPerInvocation(EVENTS)
public void throughput(ThreadContext context) throws Exception {
append(context);
}
@Benchmark
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@OperationsPerInvocation(EVENTS)
public void latency(ThreadContext context) throws Exception {
append(context);
}
private void append(ThreadContext context) throws Exception {
for (int i = 0; i < EVENTS; i++) {
appender.doAppend(context.event);
}
context.await();
}
public static class EmulatingAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
public EmulatingAppender(LoggerContext context) {
setContext(context);
setName("emulator");
}
@Override
protected void append(ILoggingEvent eventObject) {
int index = Integer.parseInt(eventObject.getMessage());
latches[index].countDown();
}
}
}