/**
* This file is part of Graylog.
*
* Graylog is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Graylog is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Graylog. If not, see <http://www.gnu.org/licenses/>.
*/
package org.graylog2;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.message.SimpleMessage;
import org.graylog2.log4j.MemoryAppender;
import org.junit.Test;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static org.assertj.core.api.Assertions.assertThat;
public class MemoryAppenderTest {
@Test
public void testGetLogMessages() {
final int bufferSize = 10;
final MemoryAppender appender = MemoryAppender.createAppender(null, null, "memory", String.valueOf(bufferSize), "false");
assertThat(appender).isNotNull();
for (int i = 1; i <= bufferSize; i++) {
final LogEvent logEvent = Log4jLogEvent.newBuilder()
.setLevel(Level.INFO)
.setLoggerName("test")
.setLoggerFqcn("com.example.test")
.setMessage(new SimpleMessage("Message " + i))
.build();
appender.append(logEvent);
}
assertThat(appender.getLogMessages(bufferSize * 2)).hasSize(bufferSize);
assertThat(appender.getLogMessages(bufferSize)).hasSize(bufferSize);
assertThat(appender.getLogMessages(bufferSize / 2)).hasSize(bufferSize / 2);
assertThat(appender.getLogMessages(0)).isEmpty();
final List<LogEvent> messages = appender.getLogMessages(5);
for (int i = 0; i < messages.size(); i++) {
assertThat(messages.get(i).getMessage().getFormattedMessage()).isEqualTo("Message " + (bufferSize - i));
}
}
@Test
public void appenderCanConsumeMoreMessagesThanBufferSize() {
final int bufferSize = 10;
final MemoryAppender appender = MemoryAppender.createAppender(null, null, "memory", String.valueOf(bufferSize), "false");
assertThat(appender).isNotNull();
for (int i = 1; i <= bufferSize + 1; i++) {
final LogEvent logEvent = Log4jLogEvent.newBuilder()
.setLevel(Level.INFO)
.setLoggerName("test")
.setLoggerFqcn("com.example.test")
.setMessage(new SimpleMessage("Message " + i))
.build();
appender.append(logEvent);
}
final List<LogEvent> messages = appender.getLogMessages(bufferSize);
for (int i = 0; i < messages.size(); i++) {
assertThat(messages.get(i).getMessage().getFormattedMessage()).isEqualTo("Message " + (bufferSize - i + 1));
}
}
@Test
public void appenderIsThreadSafe() throws Exception {
final int bufferSize = 1;
final MemoryAppender appender = MemoryAppender.createAppender(null, null, "memory", String.valueOf(bufferSize), "false");
assertThat(appender).isNotNull();
final LogEvent logEvent = Log4jLogEvent.newBuilder()
.setLevel(Level.INFO)
.setLoggerName("test")
.setLoggerFqcn("com.example.test")
.setMessage(new SimpleMessage("Message"))
.build();
final int threadCount = 48;
final Thread[] threads = new Thread[threadCount];
final TestAwareThreadGroup threadGroup = new TestAwareThreadGroup("memory-appender-test");
final CountDownLatch latch = new CountDownLatch(1);
for (int i = 0; i < threadCount; i++) {
final Runnable runner = () -> {
try {
latch.await();
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TimeUnit.SECONDS.toMillis(4L)) {
appender.append(logEvent);
}
} catch (InterruptedException ie) {
// Do nothing
}
};
final Thread thread = new Thread(threadGroup, runner, "TestThread-" + i);
threads[i] = thread;
thread.start();
}
latch.countDown();
for (int i = 0; i < threadCount; i++) {
threads[i].join(TimeUnit.SECONDS.toMillis(5L));
}
assertThat(threadGroup.getExceptionsInThreads().get()).isEqualTo(0);
}
private final static class TestAwareThreadGroup extends ThreadGroup {
private final AtomicInteger exceptionsInThreads = new AtomicInteger(0);
public TestAwareThreadGroup(String name) {
super(name);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
exceptionsInThreads.incrementAndGet();
super.uncaughtException(t, e);
}
public AtomicInteger getExceptionsInThreads() {
return exceptionsInThreads;
}
}
}