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

Log4j初始化详解

阅读更多
java中volatile关键字的含义:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html
Java transient关键字使用小记:http://www.cnblogs.com/lanxuezaipiao/p/3369962.html
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
上一篇简单学习了Log4j的使用,今天来看一下,日志初始化,
我们就从下面这一句来看:
private static Logger log = Logger.getLogger(testLog4j.class);

查看Logger
public class Logger extends Category
{
    protected Logger(String name)
    {
        super(name);
    }
    //获取Logger
    public static Logger getLogger(String name)
    {
        return LogManager.getLogger(name);
    }
    public static Logger getLogger(Class clazz)
    {
        return LogManager.getLogger(clazz.getName());
    }
    static 
    {
        FQCN = (org.apache.log4j.Logger.class).getName();
    }
}

来看LogManager的getLogger方法
//LogManager
public class LogManager
{
 public static Logger getLogger(String name)
    {
        return getLoggerRepository().getLogger(name);
    }
 //获取本机LoggerRepository
 public static LoggerRepository getLoggerRepository()
    {
        if(repositorySelector == null)
        {
            repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
            guard = null;
            Exception ex = new IllegalStateException("Class invariant violation");
            String msg = "log4j called after unloading, see http://logging.apache.org/log4j/1.2/faq.html#unload.";
            if(isLikelySafeScenario(ex))
                LogLog.debug(msg, ex);
            else
                LogLog.error(msg, ex);
        }
        return repositorySelector.getLoggerRepository();
    }
    public static final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
    static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";
    public static final String DEFAULT_CONFIGURATION_KEY = "log4j.configuration";
    public static final String CONFIGURATOR_CLASS_KEY = "log4j.configuratorClass";
    public static final String DEFAULT_INIT_OVERRIDE_KEY = "log4j.defaultInitOverride";
    private static Object guard = null;
    private static RepositorySelector repositorySelector;
    //加载log4j配置文件,先加载log4j.xml,如果log4j.xml不存在,
    //则加载log4j.properties文件
    static 
    {
        Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG));
        repositorySelector = new DefaultRepositorySelector(h);
        String override = OptionConverter.getSystemProperty("log4j.defaultInitOverride", null);
        if(override == null || "false".equalsIgnoreCase(override))
        {
            String configurationOptionStr = OptionConverter.getSystemProperty("log4j.configuration", null);
            String configuratorClassName = OptionConverter.getSystemProperty("log4j.configuratorClass", null);
            URL url = null;
            if(configurationOptionStr == null)
            {
                url = Loader.getResource("log4j.xml");
                if(url == null)
                    url = Loader.getResource("log4j.properties");
            } else
            {
                try
                {
                    url = new URL(configurationOptionStr);
                }
                catch(MalformedURLException ex)
                {
                    url = Loader.getResource(configurationOptionStr);
                }
            }
            if(url != null)
            {
                LogLog.debug("Using URL [" + url + "] for automatic log4j configuration.");
                try
                {
                    OptionConverter.selectAndConfigure(url, configuratorClassName, getLoggerRepository());
                }
	   }
	}
    }
}

//DefaultRepositorySelector
public class DefaultRepositorySelector
    implements RepositorySelector
{
    public DefaultRepositorySelector(LoggerRepository repository)
    {
        this.repository = repository;
    }
    public LoggerRepository getLoggerRepository()
    {
        return repository;
    }
    final LoggerRepository repository;
}

//NOPLoggerRepository
public final class NOPLoggerRepository
    implements LoggerRepository
{
    //从这里看,Logger实际上为NOPLogger
      public Logger getLogger(String name)
    {
        return new NOPLogger(this, name);
    }
}

//NOPLogger
public final class NOPLogger extends Logger
{

    public NOPLogger(NOPLoggerRepository repo, String name)
    {
        super(name);
        repository = repo;
        level = Level.OFF;
        parent = this;
    }
}

而Logger继承Category
public class Logger extends Category
{

    protected Logger(String name)
    {
        super(name);
    }
}

//Category
public class Category
    implements AppenderAttachable
{

    protected Category(String name)
    {
        additive = true;
        this.name = name;
    }
    protected String name;
    //volatile
    protected volatile Level level;
    protected volatile Category parent;
    private static final String FQCN;
    protected ResourceBundle resourceBundle;
    protected LoggerRepository repository;
    AppenderAttachableImpl aai;
    protected boolean additive;

    static 
    {
        FQCN = (org.apache.log4j.Category.class).getName();
    }
}

//Level
public class Level extends Priority
    implements Serializable
{
      protected Level(int level, String levelStr, int syslogEquivalent)
    {
        super(level, levelStr, syslogEquivalent);
    }
    public static final int TRACE_INT = 5000;
    public static final Level OFF = new Level(2147483647, "OFF", 0);
    public static final Level FATAL = new Level(50000, "FATAL", 0);
    public static final Level ERROR = new Level(40000, "ERROR", 3);
    public static final Level WARN = new Level(30000, "WARN", 4);
    public static final Level INFO = new Level(20000, "INFO", 6);
    public static final Level DEBUG = new Level(10000, "DEBUG", 7);
    public static final Level TRACE = new Level(5000, "TRACE", 7);
    public static final Level ALL = new Level(-2147483648, "ALL", 7);
    static final long serialVersionUID = 3491141966387921974L;
}

//Priority
public class Priority
{

    protected Priority()
    {
        level = 10000;
        levelStr = "DEBUG";
        syslogEquivalent = 7;
    }

    protected Priority(int level, String levelStr, int syslogEquivalent)
    {
        this.level = level;
        this.levelStr = levelStr;
        this.syslogEquivalent = syslogEquivalent;
    }
    //比较日志级别
      public boolean isGreaterOrEqual(Priority r)
    {
        return level >= r.level;
    }
    transient int level;
    transient String levelStr;
    transient int syslogEquivalent;
    public static final int OFF_INT = 2147483647;
    public static final int FATAL_INT = 50000;
    public static final int ERROR_INT = 40000;
    public static final int WARN_INT = 30000;
    public static final int INFO_INT = 20000;
    public static final int DEBUG_INT = 10000;
    public static final int ALL_INT = -2147483648;
    public static final Priority FATAL = new Level(50000, "FATAL", 0);
    public static final Priority ERROR = new Level(40000, "ERROR", 3);
    public static final Priority WARN = new Level(30000, "WARN", 4);
    public static final Priority INFO = new Level(20000, "INFO", 6);
    public static final Priority DEBUG = new Level(10000, "DEBUG", 7);
}

我们在回到LogManager加载log4j属性文件,关键在这一句
OptionConverter.selectAndConfigure(url, configuratorClassName, getLoggerRepository());

这个LoggerRepository实际为NOPLoggerRepository
public class OptionConverter
{
 public static void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy)
    {
        Configurator configurator = null;
        String filename = url.getFile();
        if(clazz == null && filename != null && filename.endsWith(".xml"))
            clazz = "org.apache.log4j.xml.DOMConfigurator";
	//XML配置解析
        if(clazz != null)
        {
            LogLog.debug("Preferred configurator class: " + clazz);
            configurator = (Configurator)instantiateByClassName(clazz, org.apache.log4j.spi.Configurator.class, null);
           
        } else
        {
	    //java属性文件解析log4j.properties
            configurator = new PropertyConfigurator();
        }
	//配置NOPLoggerRepository
        configurator.doConfigure(url, hierarchy);
    }
    static String DELIM_START = "${";
    static char DELIM_STOP = '}';
    static int DELIM_START_LEN = 2;
    static int DELIM_STOP_LEN = 1;

  }
}

来看log4j.properties属性文件解析
//PropertyConfigurator
public class PropertyConfigurator
    implements Configurator
{
    protected Hashtable registry;
    private LoggerRepository repository;
    protected LoggerFactory loggerFactory;
    static final String CATEGORY_PREFIX = "log4j.category.";
    static final String LOGGER_PREFIX = "log4j.logger.";
    static final String FACTORY_PREFIX = "log4j.factory";
    static final String ADDITIVITY_PREFIX = "log4j.additivity.";
    static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory";
    static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger";
    static final String APPENDER_PREFIX = "log4j.appender.";
    static final String RENDERER_PREFIX = "log4j.renderer.";
    static final String THRESHOLD_PREFIX = "log4j.threshold";
    private static final String THROWABLE_RENDERER_PREFIX = "log4j.throwableRenderer";
    private static final String LOGGER_REF = "logger-ref";
    private static final String ROOT_REF = "root-ref";
    private static final String APPENDER_REF_TAG = "appender-ref";
    public static final String LOGGER_FACTORY_KEY = "log4j.loggerFactory";
    private static final String RESET_KEY = "log4j.reset";
    private static final String INTERNAL_ROOT_NAME = "root";

    public PropertyConfigurator()
    {
        registry = new Hashtable(11);
        loggerFactory = new DefaultCategoryFactory();
    }
    //加载URL文件到Properties
    public void doConfigure(URL configURL, LoggerRepository hierarchy)
    {
        Properties props;
        InputStream istream;
        props = new Properties();
        istream = null;
        URLConnection uConn = null;
        URLConnection uConn = configURL.openConnection();
        uConn.setUseCaches(false);
        istream = uConn.getInputStream();
        props.load(istream);
	//加载URL文件到Properties
        doConfigure(props, hierarchy);
    }
    //根据properties文件配置NOPLoggerRepository
    public void doConfigure(Properties properties, LoggerRepository hierarchy)
    {
        repository = hierarchy;
        String value = properties.getProperty("log4j.debug");
        if(value == null)
        {
            value = properties.getProperty("log4j.configDebug");
            if(value != null)
                LogLog.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead.");
        }
        if(value != null)
            LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true));
        String reset = properties.getProperty("log4j.reset");
        if(reset != null && OptionConverter.toBoolean(reset, false))
            hierarchy.resetConfiguration();
        String thresholdStr = OptionConverter.findAndSubst("log4j.threshold", properties);
        if(thresholdStr != null)
        {
            hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr, Level.ALL));
            LogLog.debug("Hierarchy threshold set to [" + hierarchy.getThreshold() + "].");
        }
	//配置RootCategory,rootLogger,appenders
        configureRootCategory(properties, hierarchy);
        configureLoggerFactory(properties);
        parseCatsAndRenderers(properties, hierarchy);
        LogLog.debug("Finished configuring.");
        registry.clear();
    }
}

//配置RootCategory,rootLogger,appenders
void configureRootCategory(Properties props, LoggerRepository hierarchy)
    {
        String effectiveFrefix = "log4j.rootLogger";
        String value = OptionConverter.findAndSubst("log4j.rootLogger", props);
	if(value == null)
        {
            LogLog.debug("Could not find root logger information. Is this OK?");
        } else
        {
            Logger root = hierarchy.getRootLogger();
            synchronized(root)
            {
                parseCategory(props, root, effectiveFrefix, "root", value);
            }
        }
    }

来看 OptionConverter.findAndSubst
//返回key对应的属性
public static String findAndSubst(String key, Properties props)
    {
        String value;
        value = props.getProperty(key);
}

//NOPLoggerRepository,获取rootLogger
 public Logger getRootLogger()
    {
        return new NOPLogger(this, "root");
    }

//PropertyConfigurator
void parseCategory(Properties props, Logger logger, String optionKey, String loggerName, String value)
    {
        StringTokenizer st = new StringTokenizer(value, ",");
        if(!value.startsWith(",") && !value.equals(""))
        {
            if(!st.hasMoreTokens())
                return;
            //获取rootLogger,日志级别
            String levelStr = st.nextToken();
            if("inherited".equalsIgnoreCase(levelStr) || "null".equalsIgnoreCase(levelStr))
            {
                if(loggerName.equals("root"))
                    LogLog.warn("The root logger cannot be set to null.");
                else
                    logger.setLevel(null);
            } else
            {
                //设置rootLogger,日志级别
                logger.setLevel(OptionConverter.toLevel(levelStr, Level.DEBUG));
            }
            LogLog.debug("Category " + loggerName + " set to " + logger.getLevel());
        }
	//移除Appenders
        logger.removeAllAppenders();
        do
        {
            if(!st.hasMoreTokens())
                break;
            String appenderName = st.nextToken().trim();
            if(appenderName != null && !appenderName.equals(","))
            {
                LogLog.debug("Parsing appender named \"" + appenderName + "\".");
		//根据appenderName解析Appender
                Appender appender = parseAppender(props, appenderName);
                if(appender != null)
		    //添加appender
                    logger.addAppender(appender);
            }
        } while(true);
    }

//根据appenderName解析Appender
Appender parseAppender(Properties props, String appenderName)
    {
        Appender appender = registryGet(appenderName);
        if(appender != null)
        {
            LogLog.debug("Appender \"" + appenderName + "\" was already parsed.");
            return appender;
        }
	//log4j.appender的前缀
        String prefix = "log4j.appender." + appenderName;
        //log4j.appender.appenderName.layout
        String layoutPrefix = prefix + ".layout";
	//加载Appender,Class,
	//log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
        appender = (Appender)OptionConverter.instantiateByKey(props, prefix, org.apache.log4j.Appender.class, null);
        appender.setName(appenderName);
        if(appender instanceof OptionHandler)
        {
            if(appender.requiresLayout())
            {
	        //加载Layout,class,
		//log4j.appender.D.layout = org.apache.log4j.PatternLayout
                Layout layout = (Layout)OptionConverter.instantiateByKey(props, layoutPrefix, org.apache.log4j.Layout.class, null);
                if(layout != null)
                {
                    appender.setLayout(layout);
                    LogLog.debug("Parsing layout options for \"" + appenderName + "\".");
		    //设置layout的属性
                    PropertySetter.setProperties(layout, props, layoutPrefix + ".");
                    LogLog.debug("End of parsing for \"" + appenderName + "\".");
                }
            }
            String errorHandlerPrefix = prefix + ".errorhandler";
            String errorHandlerClass = OptionConverter.findAndSubst(errorHandlerPrefix, props);
            if(errorHandlerClass != null)
            {
                ErrorHandler eh = (ErrorHandler)OptionConverter.instantiateByKey(props, errorHandlerPrefix, org.apache.log4j.spi.ErrorHandler.class, null);
                if(eh != null)
                {
                    appender.setErrorHandler(eh);
                    LogLog.debug("Parsing errorhandler options for \"" + appenderName + "\".");
                    parseErrorHandler(eh, errorHandlerPrefix, props, repository);
                    Properties edited = new Properties();
                    String keys[] = {
                        errorHandlerPrefix + "." + "root-ref", errorHandlerPrefix + "." + "logger-ref", errorHandlerPrefix + "." + "appender-ref"
                    };
                    Iterator iter = props.entrySet().iterator();
                    do
                    {
                        if(!iter.hasNext())
                            break;
                        java.util.Map.Entry entry = (java.util.Map.Entry)iter.next();
                        int i;
                        for(i = 0; i < keys.length && !keys[i].equals(entry.getKey()); i++);
                        if(i == keys.length)
                            edited.put(entry.getKey(), entry.getValue());
                    } while(true);
                    PropertySetter.setProperties(eh, edited, errorHandlerPrefix + ".");
                    LogLog.debug("End of errorhandler parsing for \"" + appenderName + "\".");
                }
            }
	    //设置Appender属性
            PropertySetter.setProperties(appender, props, prefix + ".");
            LogLog.debug("Parsed \"" + appenderName + "\" options.");
        }
        parseAppenderFilters(props, appenderName, appender);
        //将Appender放入registry
        registryPut(appender);
        return appender;
    }

//OptionConverter.instantiateByKey
public static Object instantiateByKey(Properties props, String key, Class superClass, Object defaultValue)
    {
        String className = findAndSubst(key, props);
        if(className == null)
        {
            LogLog.error("Could not find value for key " + key);
            return defaultValue;
        } else
        {
            return instantiateByClassName(className.trim(), superClass, defaultValue);
        }
    }

//PropertyConfigurator
// protected Hashtable registry;HashTable<String,Appender>
//将Appender放入registry
void registryPut(Appender appender)
    {
        registry.put(appender.getName(), appender);
    }

下面我们来看看logger.addAppender,都做了些什么
public class Category
    implements AppenderAttachable
{
 //添加Appender
    public synchronized void addAppender(Appender newAppender)
    {
        if(aai == null)
            aai = new AppenderAttachableImpl();
        aai.addAppender(newAppender);
	//通知repository,添加Appender事件
        repository.fireAddAppenderEvent(this, newAppender);
    }
    //移除AllAppenders
public synchronized void removeAllAppenders()
    {
        if(aai != null)
        {
            Vector appenders = new Vector();
            for(Enumeration iter = aai.getAllAppenders(); iter != null && iter.hasMoreElements(); appenders.add(iter.nextElement()));
            aai.removeAllAppenders();
            for(Enumeration iter = appenders.elements(); iter.hasMoreElements(); fireRemoveAppenderEvent((Appender)iter.nextElement()));
            aai = null;
        }
    }
   
}

//AppenderAttachableImpl
public class AppenderAttachableImpl
    implements AppenderAttachable
{
//添加Appender
 public void addAppender(Appender newAppender)
    {
        if(newAppender == null)
            return;
        if(appenderList == null)
            appenderList = new Vector(1);
        if(!appenderList.contains(newAppender))
            appenderList.addElement(newAppender);
    }
    //Vector<Appender>
     protected Vector appenderList;
}

总结:
从以上我们可以看出:log4j,通过LogManager的static语句块,加载配置log4j.properties,由OptionConverter去加载log4j.properties,并委托给PropertyConfigurator,去配置RootLogger,根据RootLogger获取Appender,然后根据属性文件初始化Appender,并添加到RootLogger的appender集合中。


0
2
分享到:
评论

相关推荐

    log4j初始化

    ### log4j初始化详解 #### 引言 `log4j`是一款开源的日志记录工具,广泛应用于Java应用程序中,用于记录程序运行时的各种信息,包括错误、警告、信息等不同级别的日志。其强大的配置功能和灵活性使得开发人员能够...

    log4j使用详解log4j使用详解

    ### Log4j 使用详解 #### 一、Log4j简介 Log4j 是 Apache 的一个开源项目,通过使用 Log4j,开发者能够控制日志信息的输出等级及去向,从而更加灵活地处理日志信息。它具有强大的功能,简单的配置,并且能够支持...

    log4j.properties配置详解

    3. **通过环境变量传递配置文件名**:利用Log4j默认的初始化过程进行解析和配置。 4. **通过应用服务器配置传递配置文件名**:利用一个特殊的servlet来完成配置。 #### 六、为不同的Appender设置日志输出级别 在...

    tomcat下的log4j日志配置

    2. **编写初始化 Servlet**:创建一个自定义的 Servlet 来初始化 Log4j。该 Servlet 的主要任务是在启动时加载特定的 `log4j.properties` 文件。 ```java public class Log4jInitServlet extends HttpServlet { ...

    log4j使用详解 实例

    在Web应用程序中,log4j的配置主要分为两步:配置log4j配置文件和在Servlet中初始化配置。 1. 配置log4j配置文件 log4j的配置文件通常为log4j.properties或log4j.xml,这里我们以.properties文件为例。配置文件的...

    spring-boot-starter-log4j2

    当我们添加这个依赖到项目中,Spring Boot会自动配置Log4j2,无需手动进行繁琐的初始化设置。 三、集成步骤 1. 添加依赖:在Maven或Gradle的配置文件中引入"spring-boot-starter-log4j2"依赖,如下所示(以Maven为...

    log4j中配置日志文件相对路径方法(PDF)

    ### Log4j中配置日志文件相对路径方法详解 #### 概述 在软件开发过程中,日志记录是一项重要的功能,它有助于开发者调试程序、监控应用程序的运行状态以及追踪问题。`Log4j`作为一款优秀的日志管理工具,被广泛应用...

    Log4j日志配置说明,Log4j日志配置说明

    这个 Servlet 的作用是在应用启动时读取配置文件并初始化 Log4j。具体步骤如下: ```java package ttzl.log.web; import javax.servlet.http.HttpServlet; import org.apache.log4j.PropertyConfigurator; public...

    log4j配置详解

    3. **配置文件通过环境变量传递**:利用Log4j默认的初始化过程解析并配置配置文件。 4. **配置文件直接读取**:通过`DOMConfigurator.configure("path/to/config.xml")`等方法直接读取配置文件。 通过以上介绍,...

    log4j使用笔记

    #### 四、log4j 配置详解 1. **配置文件**: - `log4j.properties` 或 `log4j.xml` 文件用于定义 log4j 的配置规则。 - 配置文件通常放置在项目的根目录或者类路径下。 - 如果未指定配置文件的位置,则 log4j 会...

    Log4j配置文件

    3. **通过环境变量传递配置文件**: Log4j会在初始化过程中查找特定的环境变量来加载配置文件。 4. **通过应用服务器配置**: 在部署到应用服务器时,可以通过特定的Servlet来配置Log4j。 #### 六、总结 Log4j的配置...

    log4j-1.2.15-apidocs.rar

    6. **org.apache.log4j.PropertyConfigurator**:用于从属性文件中读取配置并初始化Log4j。 五、实际应用与最佳实践 在实际项目中,合理使用Log4j可以帮助调试、监控和分析程序运行状态。以下是一些最佳实践: 1....

    使用log4j写日志文件

    下面是一个简单的Servlet示例,展示了如何在Servlet的`init()`方法中初始化Log4j: ```java public class InitServlet extends HttpServlet { public void init() { ServletContext sct = getServletContext(); ...

    JBOSS log4j 配置

    3. 建立一个用于初始化的 InitServlet,在 init 方法指定 log4j 读取应用程序下的 log4j.properties 文件。 4. 把 jboss 的 jboss-common.jar($JBOSS-HOME/lib 目录下)复制到应用程序/WEB-INF/lib 目录下。 Log4j ...

    log4j之基本配置

    // 根据.properties文件初始化Log4j PropertyConfigurator.configure("log4j.properties"); // 根据.xml文件初始化Log4j DOMConfigurator.configure("log4j.xml"); Logger logger = Logger.getLogger(Log4...

    Log4j.properties详细说明

    3. 配置放在文件里,通过环境变量传递文件名等信息,利用 log4j 默认的初始化过程解析并配置。 4. 配置放在文件里,通过应用服务器配置。 Log4j.properties 文件是 Log4j 框架的核心配置文件,用于设置记录器的级别...

    log4net的配置详解

    首先,需要初始化log4net: ```csharp log4net.Config.XmlConfigurator.Configure(); ``` 然后,根据需求创建并配置appender和logger。 ### 7. 使用log4net 在代码中使用log4net非常简单,只需要获取一个logger...

    log4j详细配置

    在实际应用中,Log4j 需要通过配置文件来初始化。配置文件可以是 XML 或者 properties 文件格式。以下是以 properties 文件为例的配置示例: ##### 1. 配置根 Logger 根 Logger 通常用于设置全局的日志级别以及...

Global site tag (gtag.js) - Google Analytics