org.apache.logging.log4j.spi.ThreadContextMapFactory Maven / Gradle / Ivy
Show all versions of activemq-all Show documentation
/*
* 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.spi;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.Constants;
import org.apache.logging.log4j.util.LoaderUtil;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.ProviderUtil;
/**
* Creates the ThreadContextMap instance used by the ThreadContext.
*
* If {@link Constants#ENABLE_THREADLOCALS Log4j can use ThreadLocals}, a garbage-free StringMap-based context map can
* be installed by setting system property {@code log4j2.garbagefree.threadContextMap} to {@code true}.
*
* Furthermore, any custom {@code ThreadContextMap} can be installed by setting system property
* {@code log4j2.threadContextMap} to the fully qualified class name of the class implementing the
* {@code ThreadContextMap} interface. (Also implement the {@code ReadOnlyThreadContextMap} interface if your custom
* {@code ThreadContextMap} implementation should be accessible to applications via the
* {@link ThreadContext#getThreadContextMap()} method.)
*
* Instead of system properties, the above can also be specified in a properties file named
* {@code log4j2.component.properties} in the classpath.
*
*
* @see ThreadContextMap
* @see ReadOnlyThreadContextMap
* @see org.apache.logging.log4j.ThreadContext
* @since 2.7
*/
public final class ThreadContextMapFactory {
private static final Logger LOGGER = StatusLogger.getLogger();
private static final String THREAD_CONTEXT_KEY = "log4j2.threadContextMap";
private static final String GC_FREE_THREAD_CONTEXT_KEY = "log4j2.garbagefree.threadContextMap";
private static boolean GcFreeThreadContextKey;
private static String ThreadContextMapName;
private static final String GARBAGE_FREE_CONTEXT_MAP =
"org.apache.logging.log4j.spi" + ".GarbageFreeSortedArrayThreadContextMap";
private static final String COPY_ON_WRITE_CONTEXT_MAP =
"org.apache.logging.log4j.spi" + ".CopyOnWriteSortedArrayThreadContextMap";
static {
initPrivate();
}
/**
* Initializes static variables based on system properties. Normally called when this class is initialized by the VM
* and when Log4j is reconfigured.
*/
public static void init() {
CopyOnWriteSortedArrayThreadContextMap.init();
GarbageFreeSortedArrayThreadContextMap.init();
DefaultThreadContextMap.init();
initPrivate();
}
/**
* Initializes static variables based on system properties. Normally called when this class is initialized by the VM
* and when Log4j is reconfigured.
*/
private static void initPrivate() {
final PropertiesUtil properties = PropertiesUtil.getProperties();
ThreadContextMapName = properties.getStringProperty(THREAD_CONTEXT_KEY);
GcFreeThreadContextKey = properties.getBooleanProperty(GC_FREE_THREAD_CONTEXT_KEY);
}
private ThreadContextMapFactory() {}
public static ThreadContextMap createThreadContextMap() {
final ClassLoader cl = ProviderUtil.findClassLoader();
ThreadContextMap result = null;
if (ThreadContextMapName != null) {
/*
* Two implementation are package-private classes, so we instantiate them directly.
* Other implementation must be publicly accessible (through `LoaderUtil`).
*/
switch (ThreadContextMapName) {
case GARBAGE_FREE_CONTEXT_MAP:
result = new GarbageFreeSortedArrayThreadContextMap();
break;
case COPY_ON_WRITE_CONTEXT_MAP:
result = new CopyOnWriteSortedArrayThreadContextMap();
break;
default:
try {
result = LoaderUtil.newCheckedInstanceOf(ThreadContextMapName, ThreadContextMap.class);
} catch (final ClassNotFoundException cnfe) {
LOGGER.error("Unable to locate configured ThreadContextMap {}", ThreadContextMapName);
} catch (final Exception ex) {
LOGGER.error("Unable to create configured ThreadContextMap {}", ThreadContextMapName, ex);
}
}
}
if (result == null && ProviderUtil.hasProviders() && LogManager.getFactory() != null) { // LOG4J2-1658
final String factoryClassName = LogManager.getFactory().getClass().getName();
for (final Provider provider : ProviderUtil.getProviders()) {
if (factoryClassName.equals(provider.getClassName())) {
final Class extends ThreadContextMap> clazz = provider.loadThreadContextMap();
if (clazz != null) {
try {
result = LoaderUtil.newInstanceOf(clazz);
break;
} catch (final Exception e) {
LOGGER.error(
"Unable to locate or load configured ThreadContextMap {}",
provider.getThreadContextMap(),
e);
result = createDefaultThreadContextMap();
}
}
}
}
}
if (result == null) {
result = createDefaultThreadContextMap();
}
return result;
}
private static ThreadContextMap createDefaultThreadContextMap() {
if (Constants.ENABLE_THREADLOCALS) {
if (GcFreeThreadContextKey) {
return new GarbageFreeSortedArrayThreadContextMap();
}
return new CopyOnWriteSortedArrayThreadContextMap();
}
return new DefaultThreadContextMap(true);
}
}