org.refcodes.logger.ext.slf4j.RuntimeLoggerFactory Maven / Gradle / Ivy
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// =============================================================================
// This code is copyright (c) by Siegfried Steiner, Munich, Germany, distributed
// on an "AS IS" BASIS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, and licen-
// sed under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// =============================================================================
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// together with the GPL linking exception applied; as being applied by the GNU
// Classpath ("http://www.gnu.org/software/classpath/license.html")
// =============================================================================
// Apache License, v2.0 ("http://www.apache.org/licenses/TEXT-2.0")
// =============================================================================
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////
package org.refcodes.logger.ext.slf4j;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.refcodes.logger.RuntimeLogger;
import org.refcodes.logger.RuntimeLoggerFactorySingleton;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.slf4j.helpers.NOPLogger;
/**
* An {@link ILoggerFactory} factory for creating {@link RuntimeLogger} objects.
*/
public class RuntimeLoggerFactory implements ILoggerFactory {
// /////////////////////////////////////////////////////////////////////////
// VARIABLES:
// /////////////////////////////////////////////////////////////////////////
private final ConcurrentMap _nameToLoggerMap;
private static final ThreadLocal _invocationCount = new ThreadLocal() {
@Override
protected Integer initialValue() {
return 0;
}
};
// /////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS:
// /////////////////////////////////////////////////////////////////////////
/**
* Instantiates a new runtime logger factory.
*/
public RuntimeLoggerFactory() {
_nameToLoggerMap = new ConcurrentHashMap<>();
SLF4JBridgeHandler.install();
}
// /////////////////////////////////////////////////////////////////////////
// METHODS:
// /////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
@Override
public Logger getLogger( String name ) {
/**
* An API involved in *creating* the logger wants to create a logger for
* itself as well while creating the desired logger. This causes an
* endless loop of logger creation invocations with the result of an
* StackOverflowError. To prevent this we count the number of
* invocations a thread has undertaken to determine whether we ended up
* in such a loop.
*/
if ( _invocationCount.get() != 0 ) {
return NOPLogger.NOP_LOGGER;
}
_invocationCount.set( _invocationCount.get() + 1 );
final Logger slf4jLogger = _nameToLoggerMap.get( name );
if ( slf4jLogger != null ) {
_invocationCount.remove();
return slf4jLogger;
}
else {
if ( name != null ) {
name = name.replaceAll( "/", "." );
}
if ( name.length() > 0 && name.charAt( 0 ) == '.' ) {
name = name.substring( 1 );
}
if ( name == null || name.isEmpty() ) {
name = RuntimeLogger.ROOT_LOGGER_ELEMENT_PATH;
}
final RuntimeLogger theRuntimeLogger;
if ( name.equalsIgnoreCase( Logger.ROOT_LOGGER_NAME ) ) {
theRuntimeLogger = RuntimeLoggerFactorySingleton.createRuntimeLogger();
}
else {
theRuntimeLogger = RuntimeLoggerFactorySingleton.getInstance().create( name );
}
final Logger newInstance = new RuntimeLoggerAdapter( theRuntimeLogger );
final Logger oldInstance = _nameToLoggerMap.putIfAbsent( name, newInstance );
_invocationCount.remove();
return oldInstance == null ? newInstance : oldInstance;
}
}
}