org.apache.logging.log4j.spi.ThreadContextMapFactory Maven / Gradle / Ivy
/*
* 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.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;
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) {
try {
final Class> clazz = cl.loadClass(ThreadContextMapName);
if (ThreadContextMap.class.isAssignableFrom(clazz)) {
result = (ThreadContextMap) clazz.newInstance();
}
} 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 = clazz.newInstance();
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);
}
}