`
Donald_Draper
  • 浏览: 984786 次
社区版块
存档分类
最新评论

slf4j + Log4j 详解

阅读更多
Log4j初始化详解:http://donald-draper.iteye.com/blog/2332385
Log4j日志输出详解 http://donald-draper.iteye.com/blog/2332395
slf4j + Log4j的使用:http://donald-draper.iteye.com/blog/2332407
上一篇讲了slf4j + Log4j的使用,其中获取Logger的一句为
private static Logger log = LoggerFactory.getLogger(testSFL4J.class); 

下面来看这一句的具体含义:
public final class LoggerFactory
{
    static final String CODES_PREFIX = "http://www.slf4j.org/codes.html";
    static final String NO_STATICLOGGERBINDER_URL = "http://www.slf4j.org/codes.html#StaticLoggerBinder";
    static final String MULTIPLE_BINDINGS_URL = "http://www.slf4j.org/codes.html#multiple_bindings";
    static final String NULL_LF_URL = "http://www.slf4j.org/codes.html#null_LF";
    static final String VERSION_MISMATCH = "http://www.slf4j.org/codes.html#version_mismatch";
    static final String SUBSTITUTE_LOGGER_URL = "http://www.slf4j.org/codes.html#substituteLogger";
    static final String LOGGER_NAME_MISMATCH_URL = "http://www.slf4j.org/codes.html#loggerNameMismatch";
    static final String UNSUCCESSFUL_INIT_URL = "http://www.slf4j.org/codes.html#unsuccessfulInit";
    static final String UNSUCCESSFUL_INIT_MSG = "org.slf4j.LoggerFactory could not be successfully initialized. See also http://www.slf4j.org/codes.html#unsuccessfulInit";
    static final int UNINITIALIZED = 0;
    static final int ONGOING_INITIALIZATION = 1;
    static final int FAILED_INITIALIZATION = 2;
    static final int SUCCESSFUL_INITIALIZATION = 3;
    static final int NOP_FALLBACK_INITIALIZATION = 4;
    static int INITIALIZATION_STATE = 0;
    static SubstituteLoggerFactory TEMP_FACTORY = new SubstituteLoggerFactory();
    static NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory();
    static final String DETECT_LOGGER_NAME_MISMATCH_PROPERTY = "slf4j.detectLoggerNameMismatch";
    static boolean DETECT_LOGGER_NAME_MISMATCH = Boolean.getBoolean("slf4j.detectLoggerNameMismatch");
    private static final String API_COMPATIBILITY_LIST[] = {
        "1.6", "1.7"
    };
    private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
   //根据class,获取Logger
public static Logger getLogger(Class clazz)
    {
        Logger logger = getLogger(clazz.getName());
        if(DETECT_LOGGER_NAME_MISMATCH)
        {
            Class autoComputedCallingClass = Util.getCallingClass();
            if(nonMatchingClasses(clazz, autoComputedCallingClass))
            {
                Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", new Object[] {
                    logger.getName(), autoComputedCallingClass.getName()
                }));
                Util.report("See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation");
            }
        }
        return logger;
    }
    //根据class name 获取Logger
     public static Logger getLogger(String name)
    {
        //获取LoggerFactory
        ILoggerFactory iLoggerFactory = getILoggerFactory();
	//从LoggerFactory获取Logger
        return iLoggerFactory.getLogger(name);
    }
    //获取LoggerFactory
     public static ILoggerFactory getILoggerFactory()
    {
        if(INITIALIZATION_STATE == 0)
        {
            INITIALIZATION_STATE = 1;
	    //执行初始化
            performInitialization();
        }
        switch(INITIALIZATION_STATE)
        {
        case 3: // '\003'
	    //返回Log4jLoggerFactory
            return StaticLoggerBinder.getSingleton().getLoggerFactory();

        case 4: // '\004'
	//如果状态为4,则返回NOPLoggerFactory
            return NOP_FALLBACK_FACTORY;

        case 2: // '\002'
            throw new IllegalStateException("org.slf4j.LoggerFactory could not be successfully initialized. See also http://www.slf4j.org/codes.html#unsuccessfulInit");
        //如果初始化状态为1,返回临时LoggerFactory,SubstituteLoggerFactory
        case 1: // '\001'
            return TEMP_FACTORY;
        }
        throw new IllegalStateException("Unreachable code");
    }
    //执行初始化
     private static final void performInitialization()
    {
        //绑定日志工场
        bind();
        if(INITIALIZATION_STATE == 3)
	    //验证配置
            versionSanityCheck();
    }
    //绑定日志工场
     private static final void bind()
    {
        try
        {
	    //获取具体LoggerBinder类,默认为StaticLoggerBinder,在slf4j-log4j12-1.7.9.jar 中
            Set staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
            reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
            StaticLoggerBinder.getSingleton();
            INITIALIZATION_STATE = 3;
            reportActualBinding(staticLoggerBinderPathSet);
	    //从SubstituteLoggerFactory获取具体sfl4j的Logger实现,并用SubstituteLogger代理类去包装
            fixSubstitutedLoggers();
        }
	catch(NoClassDefFoundError ncde)
        {
            String msg = ncde.getMessage();
            if(messageContainsOrgSlf4jImplStaticLoggerBinder(msg))
            {
	        //初始化状态为4,返回NOPLoggerFactory,无配置Logger
                INITIALIZATION_STATE = 4;
                Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
                Util.report("Defaulting to no-operation (NOP) logger implementation");
                Util.report("See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.");
            } else
            {
                failedBinding(ncde);
                throw ncde;
            }
        }
        catch(NoSuchMethodError nsme)
        {
            String msg = nsme.getMessage();
            if(msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1)
            {
	        //org.slf4j.LoggerFactory could not be successfully initialized
                INITIALIZATION_STATE = 2;
                Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
                Util.report("Your binding is version 1.5.5 or earlier.");
                Util.report("Upgrade your binding to version 1.6.x.");
            }
            throw nsme;
        }
	catch(Exception e)
        {
            failedBinding(e);
            throw new IllegalStateException("Unexpected initialization failure", e);
        }

    }
    //获取StaticLoggerBinderPathS
    private static Set findPossibleStaticLoggerBinderPathSet()
    {
        Set staticLoggerBinderPathSet = new LinkedHashSet();
        try
        {
            ClassLoader loggerFactoryClassLoader = org/slf4j/LoggerFactory.getClassLoader();
            Enumeration paths;
            if(loggerFactoryClassLoader == null)
                paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
            else
	        // private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
                paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
            URL path;
            for(; paths.hasMoreElements(); staticLoggerBinderPathSet.add(path))
                path = (URL)paths.nextElement();

        }
        return staticLoggerBinderPathSet;
    }
   // StaticLoggerBinder,是否有多个实现版本
   private static boolean isAmbiguousStaticLoggerBinderPathSet(Set            staticLoggerBinderPathSet)
    {
        return staticLoggerBinderPathSet.size() > 1;
    }
    //report多StaticLoggerBinder,并打印具体实现的package,jar地址
    private static void reportMultipleBindingAmbiguity(Set staticLoggerBinderPathSet)
    {
        if(isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet))
        {
            Util.report("Class path contains multiple SLF4J bindings.");
            URL path;
            for(Iterator iterator = staticLoggerBinderPathSet.iterator(); iterator.hasNext(); Util.report((new StringBuilder()).append("Found binding in [").append(path).append("]").toString()))
                path = (URL)iterator.next();

            Util.report("See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.");
        }
    }
   //report实际绑定,实际绑定的StaticLoggerBinder,是随机的。
    private static void reportActualBinding(Set staticLoggerBinderPathSet)
    {
        if(isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet))
            Util.report((new StringBuilder()).append("Actual binding is of type [").append(StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr()).append("]").toString());
    }
    //从SubstituteLoggerFactory获取具体sfl4j的Logger实现,并用SubstituteLogger代理类去包装
    //如果日志Logger为sfl4j的Logger的实现,则用SubstituteLogger去代理具体的实现Logger
    private static final void fixSubstitutedLoggers()
    {
       //从临时工厂SubstituteLoggerFactory,获取所有Loggers
        List loggers = TEMP_FACTORY.getLoggers();
        if(loggers.isEmpty())
            return;
        Util.report("The following set of substitute loggers may have been accessed");
        Util.report("during the initialization phase. Logging calls during this");
        Util.report("phase were not honored. However, subsequent logging calls to these");
        Util.report("loggers will work as normally expected.");
        Util.report("See also http://www.slf4j.org/codes.html#substituteLogger");
        SubstituteLogger subLogger;
        for(Iterator i$ = loggers.iterator(); i$.hasNext(); Util.report(subLogger.getName()))
        {
            subLogger = (SubstituteLogger)i$.next();
            subLogger.setDelegate(getLogger(subLogger.getName()));
        }

        TEMP_FACTORY.clear();
    }
    //验证配置,校验文件
    private static final void versionSanityCheck()
    {
        try
        {
            String requested = StaticLoggerBinder.REQUESTED_API_VERSION;
            boolean match = false;
            for(int i = 0; i < API_COMPATIBILITY_LIST.length; i++)
                if(requested.startsWith(API_COMPATIBILITY_LIST[i]))
                    match = true;

            if(!match)
            {
                Util.report((new StringBuilder()).append("The requested version ").append(requested).append(" by your slf4j binding is not compatible with ").append(Arrays.asList(API_COMPATIBILITY_LIST).toString()).toString());
                Util.report("See http://www.slf4j.org/codes.html#version_mismatch for further details.");
            }
        }
    }
}

下面来看一下StaticLoggerBinder
public class StaticLoggerBinder
    implements LoggerFactoryBinder
{

    public static final StaticLoggerBinder getSingleton()
    {
        return SINGLETON;
    }

    private StaticLoggerBinder()
    {
        Level level;
        try
        {
            level = Level.TRACE;
        }
    }

    public ILoggerFactory getLoggerFactory()
    {
        return loggerFactory;
    }

    public String getLoggerFactoryClassStr()
    {
        return loggerFactoryClassStr;
    }

    private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
    public static String REQUESTED_API_VERSION = "1.6.99";
    private static final String loggerFactoryClassStr = org/slf4j/impl/Log4jLoggerFactory.getName();
    //从这里可以看出,返回的为Log4jLoggerFactory
    private final ILoggerFactory loggerFactory = new Log4jLoggerFactory();
}

再看Log4jLoggerFactory
//Log4jLoggerFactory
public class Log4jLoggerFactory
    implements ILoggerFactory
{

    public Log4jLoggerFactory()
    {
        loggerMap = new ConcurrentHashMap();
    }

    public Logger getLogger(String name)
    {
        //如果有slf4jLogger具体实现,则返回
        Logger slf4jLogger = (Logger)loggerMap.get(name);
        if(slf4jLogger != null)
            return slf4jLogger;
        org.apache.log4j.Logger log4jLogger;
        if(name.equalsIgnoreCase("ROOT"))
            log4jLogger = LogManager.getRootLogger();
        else
	    //看到这一句是不是很熟悉,LogManager,初始配置,获取log4jLogger
	    //这个具体的我们在log4j初始化,那篇文章中有讲
            log4jLogger = LogManager.getLogger(name);
	//将log4jLogger包装成slf4jLogger
        Logger newInstance = new Log4jLoggerAdapter(log4jLogger);
        Logger oldInstance = (Logger)loggerMap.putIfAbsent(name, newInstance);
        return oldInstance != null ? oldInstance : newInstance;
    }
    ConcurrentMap loggerMap;
}

//Log4jLoggerAdapter
import java.io.Serializable;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.slf4j.Marker;
import org.slf4j.helpers.*;
import org.slf4j.spi.LocationAwareLogger;
public final class Log4jLoggerAdapter extends MarkerIgnoringBase
    implements LocationAwareLogger, Serializable
{
    Log4jLoggerAdapter(Logger logger)
    {
        this.logger = logger;
        name = logger.getName();
    }
    public void info(String msg)
    {
        //这里就是直接调用Log4J的log INFO
        logger.log(FQCN, Level.INFO, msg, null);
    }
    private static final long serialVersionUID = 6182834493563598289L;
    final transient Logger logger;
    static final String FQCN = org/slf4j/impl/Log4jLoggerAdapter.getName();
    final boolean traceCapable = isTraceCapable();
}

//LocationAwareLogger
import org.slf4j.Logger;
import org.slf4j.Marker;
public interface LocationAwareLogger
    extends Logger
{

    public abstract void log(Marker marker, String s, int i, String s1, Object aobj[], Throwable throwable);

    public static final int TRACE_INT = 0;
    public static final int DEBUG_INT = 10;
    public static final int INFO_INT = 20;
    public static final int WARN_INT = 30;
    public static final int ERROR_INT = 40;
}

//SubstituteLogger,Logger具体实现的代理类
public class SubstituteLogger
    implements Logger
{
 public void setDelegate(Logger delegate)
    {
        _delegate = delegate;
    }

    private final String name;
    private volatile Logger _delegate;
}

当StaticLoggerBinder,找不到默认的Log4J,则从临时工厂SubstituteLoggerFactory,去获取
合适的Logger
//SubstituteLoggerFactory
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
public class SubstituteLoggerFactory
    implements ILoggerFactory
{
 final ConcurrentMap loggers = new ConcurrentHashMap();
 //从SubstituteLoggerFactory或sfl4j的具体实现Logger,如果工厂中不存在,
 //则新建一个Logger,并放入SubstituteLoggerFactory中
 public Logger getLogger(String name)
    {
        SubstituteLogger logger = (SubstituteLogger)loggers.get(name);
        if(logger == null)
        {
            logger = new SubstituteLogger(name);
            SubstituteLogger oldLogger = (SubstituteLogger)loggers.putIfAbsent(name, logger);
            if(oldLogger != null)
                logger = oldLogger;
        }
        return logger;
    }
}


下面来看一下:NOPLoggerFactory
//NOPLoggerFactory
public class NOPLoggerFactory
    implements ILoggerFactory
{

    public NOPLoggerFactory()
    {
    }

    public Logger getLogger(String name)
    {
        return NOPLogger.NOP_LOGGER;
    }
}
//NOPLogger
public class NOPLogger extends MarkerIgnoringBase
{
   public static final NOPLogger NOP_LOGGER = new NOPLogger();

}

//MarkerIgnoringBase
import org.slf4j.Logger;
import org.slf4j.Marker;
public abstract class MarkerIgnoringBase extends NamedLoggerBase
    implements Logger
{
    public void info(Marker marker, String msg)
    {
        info(msg);
    }

    public void info(Marker marker, String format, Object arg)
    {
        info(format, arg);
    }

    public void info(Marker marker, String format, Object arg1, Object arg2)
    {
        info(format, arg1, arg2);
    }

    public transient void info(Marker marker, String format, Object arguments[])
    {
        info(format, arguments);
    }

    public void info(Marker marker, String msg, Throwable t)
    {
        info(msg, t);
    }
    public volatile String getName()
    {
        return super.getName();
    }

}


测试当有多个StaticLoggerBinder具体实现,实际bind,添加多个具体实现jar包,控制台会输出:
第一种情况:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/E:/lib/logback-classic-0.9.27.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/E:/lib/slf4j-log4j12-1.7.9.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
####实际绑定为logback-classic-0.9.27.jar的StaticLoggerBinder
SLF4J: Actual binding is of type [ch.qos.logback.classic.selector.DefaultContextSelector]

==================================================================
第二种情况:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/E:/lib/slf4j-log4j12-1.7.9.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/E:/lib/logback-classic-0.9.27.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
####实际绑定为slf4j-log4j12-1.7.9.jar的StaticLoggerBinder
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]

从输出信息可以看出,slf4j 实际bind StaticLoggerBinder,以java build path 中引用的jar的顺序有关,测试结果是第一个发现的jar。


总结:
从上面可以分析,可以看出sfl4j,通过LoggerFactory,来获取实际的Logger实现,默认会找Log4jLoggerFactory,从Log4jLoggerFactory获取log4jLogger,具体为log4jLogger的适配器Log4jLoggerAdapter。当无法找到Log4jLoggerFactory,则从SubstituteLoggerFactory,获取sfl4j的具体实现,并通过SubstituteLogger取代;如果无法找到sfl4j的具体实现,则从NOPLoggerFactory获取Logger。当Logger为Log4jLoggerAdapter时,则调用log4j的日志打印;当Logger为SubstituteLogger,则通过SubstituteLogger,打印日志;如果上面两种,都没有则使用NOPLogger,去打印日志。
分享到:
评论

相关推荐

    slf4j+log4j2配置使用

    SLF4J(Simple Logging Facade for Java)是一个Java的日志接口,而Log4j2是一个具体的日志实现框架。Log4j2是Log4j的升级版,提供了更加灵活和强大的日志处理能力,包括异步日志、延迟加载、日志脱敏等功能。接下来...

    hibernate3.3.1接口实现包 slf4j-log4j12-1.5.2

    SLF4J-Log4j12-1.5.2是SLF4J的一个绑定实现,意味着它将SLF4J的日志调用转发给Log4j1.2框架处理。Log4j12是Log4j的一个较新版本,提供了更高效、更灵活的日志记录,包括自定义布局、过滤器和Appenders,以及支持日志...

    详解Spring Boot 使用slf4j+logback记录日志配置

    Logback 是 SLF4J 推荐的日志实现,它由 log4j 的创始人设计,提供了高速、灵活且可靠的日志记录功能。 使用 SLF4J 和 Logback 进行日志记录配置的主要目的是: 1. 为 Spring 的开发提供了一个更快速更广泛的入门...

    详解log4j-over-slf4j与slf4j-log4j12共存stack overflow异常分析

    例如,我们可以使用log4j-over-slf4j将SLF4J桥接到Log4j上,也可以使用slf4j-log4j12将SLF4J桥接到Log4j 1.2上。 log4j-over-slf4j和slf4j-log4j12是两个不同的桥接器,它们之间的桥接和绑定机制可能会导致堆栈溢出...

    slf4j日志框架的源代码分享

    SLF4J(Simple Logging Facade for Java)是Java中的一种日志门面(Logging Facade),它为各种日志框架提供了一个简单的统一接口,如Log4j、Java Util Logging、Logback等。通过SLF4J,开发者可以在运行时绑定任意...

    log4j所需jar包

    **Apache Log4j详解** Apache Log4j是一个广泛使用的开源日志框架,它为Java应用程序提供了灵活的日志记录功能。这个框架允许开发者控制日志信息的输出格式、输出位置以及日志级别,使得调试和故障排查更为高效。在...

    Slf4j日志相关jar包

    **Slf4j日志框架详解** Slf4j(Simple Logging Facade for Java)是一个用于日志系统的简单 facade,它允许最终用户在部署他们的应用时使用他们希望的日志库。Slf4j提供了一个统一的API,使得开发人员能够在不更换...

    详解slf4j+logback在java工程中的配置

    SLF4J允许开发者在运行时选择任意的日志实现,比如Logback、Log4j等。它提供了一组简单的API,使得开发者可以在不关心具体日志实现的情况下编写代码。SLF4J的主要优势在于其可插拔性,这意味着你可以根据项目需求...

    slf4j使用手册

    ### SLF4J 使用手册详解 #### 一、SLF4J 概述 SLF4J(Simple Logging Facade for Java)是一个用于多种日志框架的简化接口或抽象层,旨在将日志的创建者与具体的日志实现进行解耦。通过这种方式,开发人员可以在...

    SLF4J配置应用

    ### SLF4J配置应用详解 #### 一、引言 在软件开发过程中,日志记录是一项非常重要的工作。良好的日志系统可以帮助开发者快速定位问题、优化程序性能以及监控应用程序的状态。SLF4J(Simple Logging Facade for ...

    log4j各版本jar包

    《log4j各版本详解与应用》 在Java开发领域,日志管理是不可或缺的一部分,而Log4j作为Apache组织开发的一款开源日志框架,因其高效、灵活的特点,被广泛应用于各种Java应用程序中。本文将深入探讨Log4j的各个版本...

    logback + slf4j web项目源码

    2. **SLF4J (Simple Logging Facade for Java)**: SLF4J 提供了一组API,使得开发人员能够插入他们所选择的日志框架,例如Logback、log4j等。它是一个抽象层,允许用户在部署时选择合适的日志实现,通过简单的API...

    slf4j-nop-1.7.3.jar

    2. SLF4J-nop-1.7.3.jar详解: - **版本号**:1.7.3表示这是SLF4J NOP绑定的一个特定版本,1.7是主版本号,3是次版本号。这个版本可能包含了修复的bug、性能改进或新特性。 - **NOP实现**:当使用SLF4J-nop时,...

    日志框架log4j和slf4j入门教程(私塾在线)视频配套学习资料

    ### 日志框架log4j和slf4j入门教程知识点详解 #### 一、Log4j简介 **Log4j** 是Apache组织下的一个开源项目,主要用于Java应用程序的日志记录功能。通过Log4j,开发者可以灵活地控制日志信息的输出格式、输出目的...

    hibernate annotation+slf4j

    SLF4J(Simple Logging Facade for Java)是一个日志抽象层,为不同的日志实现(如log4j、logback)提供一个通用的接口。这样,开发者可以在不修改代码的情况下更换日志实现。 1. 引入依赖:在项目中引入SLF4J的API...

    log4j使用教程(详解)

    **日志框架Log4j详解** 在Java编程中,日志记录是不可或缺的一部分,它用于追踪应用程序的运行状态,帮助开发者在出现问题时定位错误、调试程序。Log4j是一款广泛使用的开源日志框架,由Apache软件基金会开发。本文...

    如何将应用的log4j替换成logback详解

    `logback-classic`是Logback的用户接口,`logback-core`是其核心库,而`log4j-over-slf4j`则允许将Log4j的日志调用桥接到SLF4J。 ```xml &lt;!-- logback日志配置开始 --&gt; &lt;groupId&gt;ch.qos.logback &lt;artifactId&gt;...

    Log4j详解与实战

    - SLF4J(Simple Logging Facade for Java)是一个抽象层,可以用来替换不同的日志实现,包括Log4j。 在实际项目中,理解和掌握Log4j的使用能极大地提升开发效率和问题排查能力。通过深入学习和实践,你可以更好地...

    log4j-1.2.17.jar

    《Java日志框架Log4j详解与应用》 在Java编程中,日志记录是必不可少的一个环节,它有助于我们跟踪程序运行状态,定位错误和调试问题。Log4j作为Java领域广泛使用的日志框架,因其高效、灵活和可扩展性而备受推崇。...

Global site tag (gtag.js) - Google Analytics