blob: 6afa8d627e4edf9ebc6a7910d6dbd4393adedfb9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache license, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.core.async;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.ThreadContextTestAccess;
import org.apache.logging.log4j.core.test.CoreLoggerContexts;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
import org.apache.logging.log4j.core.util.Constants;
import org.apache.logging.log4j.spi.DefaultThreadContextMap;
import org.apache.logging.log4j.spi.LoggerContext;
import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.Unbox;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
public abstract class AbstractAsyncThreadContextTestBase {
private final static int LINE_COUNT = 130;
@BeforeClass
public static void beforeClass() {
System.setProperty("log4j2.is.webapp", "false");
System.setProperty("AsyncLogger.RingBufferSize", "128"); // minimum ringbuffer size
System.setProperty("AsyncLoggerConfig.RingBufferSize", "128"); // minimum ringbuffer size
}
@AfterClass
public static void afterClass() {
System.clearProperty("AsyncLogger.RingBufferSize");
System.clearProperty("AsyncLoggerConfig.RingBufferSize");
System.clearProperty(Constants.LOG4J_CONTEXT_SELECTOR);
System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
System.clearProperty("log4j2.garbagefree.threadContextMap");
System.clearProperty("log4j2.is.webapp");
System.clearProperty("log4j2.threadContextMap");
}
enum Mode {
ALL_ASYNC, MIXED, BOTH_ALL_ASYNC_AND_MIXED;
void initSelector() {
if (this == ALL_ASYNC || this == BOTH_ALL_ASYNC_AND_MIXED) {
System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, AsyncLoggerContextSelector.class.getName());
} else {
System.clearProperty(Constants.LOG4J_CONTEXT_SELECTOR);
}
}
void initConfigFile() {
// NOTICE: PLEASE DON'T REFACTOR: keep "file" local variable for confirmation in debugger.
final String file = this == ALL_ASYNC //
? "AsyncLoggerThreadContextTest.xml" //
: "AsyncLoggerConfigThreadContextTest.xml";
System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, file);
}
}
enum ContextImpl {
WEBAPP, GARBAGE_FREE, COPY_ON_WRITE;
void init() {
System.clearProperty("log4j2.threadContextMap");
final String PACKAGE = "org.apache.logging.log4j.spi.";
System.setProperty("log4j2.threadContextMap", PACKAGE + implClassSimpleName());
PropertiesUtil.getProperties().reload();
ThreadContextTestAccess.init();
}
public String implClassSimpleName() {
switch (this) {
case WEBAPP:
return DefaultThreadContextMap.class.getSimpleName();
case GARBAGE_FREE:
return "GarbageFreeSortedArrayThreadContextMap";
case COPY_ON_WRITE:
return "CopyOnWriteSortedArrayThreadContextMap";
}
throw new IllegalStateException("Unknown state " + this);
}
}
private final ContextImpl contextImpl;
private final Mode asyncMode;
public AbstractAsyncThreadContextTestBase(final ContextImpl contextImpl, final Mode asyncMode) {
this.contextImpl = contextImpl;
this.asyncMode = asyncMode;
asyncMode.initSelector();
asyncMode.initConfigFile();
contextImpl.init();
}
@Test
public void testAsyncLogWritesToLog() throws Exception {
final File[] files = new File[] {
new File("target", "AsyncLoggerTest.log"), //
new File("target", "SynchronousContextTest.log"), //
new File("target", "AsyncLoggerAndAsyncAppenderTest.log"), //
new File("target", "AsyncAppenderContextTest.log"), //
};
for (final File f : files) {
f.delete();
}
ThreadContext.push("stackvalue");
ThreadContext.put("KEY", "mapvalue");
final Logger log = LogManager.getLogger("com.foo.Bar");
final LoggerContext loggerContext = LogManager.getContext(false);
final String loggerContextName = loggerContext.getClass().getSimpleName();
RingBufferAdmin ring;
if (loggerContext instanceof AsyncLoggerContext) {
ring = ((AsyncLoggerContext) loggerContext).createRingBufferAdmin();
} else {
ring = ((AsyncLoggerConfig) ((org.apache.logging.log4j.core.Logger) log).get()).createRingBufferAdmin("");
}
for (int i = 0; i < LINE_COUNT; i++) {
while (i >= 128 && ring.getRemainingCapacity() == 0) { // buffer may be full
Thread.sleep(1);
}
if ((i & 1) == 1) {
ThreadContext.put("count", String.valueOf(i));
} else {
ThreadContext.remove("count");
}
log.info("{} {} {} i={}", contextImpl, contextMap(), loggerContextName, Unbox.box(i));
}
ThreadContext.pop();
CoreLoggerContexts.stopLoggerContext(false, files[0]); // stop async thread
checkResult(files[0], loggerContextName);
if (asyncMode == Mode.MIXED || asyncMode == Mode.BOTH_ALL_ASYNC_AND_MIXED) {
for (int i = 1; i < files.length; i++) {
checkResult(files[i], loggerContextName);
}
}
LogManager.shutdown();
}
private static String contextMap() {
final ReadOnlyThreadContextMap impl = ThreadContext.getThreadContextMap();
return impl == null ? ContextImpl.WEBAPP.implClassSimpleName() : impl.getClass().getSimpleName();
}
private void checkResult(final File file, final String loggerContextName) throws IOException {
final String contextDesc = contextImpl + " " + contextImpl.implClassSimpleName() + " " + loggerContextName;
try (final BufferedReader reader = new BufferedReader(new FileReader(file))) {
String expect;
for (int i = 0; i < LINE_COUNT; i++) {
final String line = reader.readLine();
if ((i & 1) == 1) {
expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue, configProp=configValue, configProp2=configValue2, count=" + i + "} "
+ contextDesc + " i=" + i;
} else {
expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue, configProp=configValue, configProp2=configValue2} " + contextDesc + " i=" + i;
}
assertEquals(file.getName() + ": line " + i, expect, line);
}
final String noMoreLines = reader.readLine();
assertNull("done", noMoreLines);
} finally {
file.delete();
}
}
}