java工具-log4j框架-基本介绍和文件配置及框架加载调用

一、log4j基本介绍


Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
所以简单的来说,Log4j可以理解为一个通过配置文件进行配置的日志操作工具。

log4j框架 需要  log4j.jar 包  和  log4j配置文件。log4j 1.x 版 和log4j 2.x  代码调用和配置文件 都不一样了要注意。本文讲的 代码调用和 文件配置,都是针对1.x 版本来说的。【不是很确定,但应该是1.x 版本】

二、log4j配置文件


1、log4j的配置文件可以有两种类型:

(1)log4j.properties
(2)log4j.xml

log4j文件名和文件路径都可以随意设置,只要在代码中指定好配置文件就行,这样就能加载log4j框架了。【如果配置文件取名为log4j.xml或者log4j.properties,且文件放在根目录(就是可执行二进制class文件的根目录),那么log4j会自动加载配置文件,无需写代码】

2、Log4j配置文件的基本格式如下:

#配置根Logger
log4j.rootLogger = [level] , appenderName1 , appenderName2 , …
#配置日志信息输出目的地Appender
log4j.appender.appenderName  =  fully.qualified.name.of.appender.class 
log4j.appender.appenderName.option1  =  value1 
… 
log4j.appender.appenderName.optionN  =  valueN 
#配置日志信息的格式(布局)
log4j.appender.appenderName.layout  =  fully.qualified.name.of.layout.class 
log4j.appender.appenderName.layout.option1  =  value1 
… 
log4j.appender.appenderName.layout.optionN  =  valueN

3、log4j.properties各部分的格式具体含义:

log4j.rootLogger=INFO,Console,File
#控制台日志
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%p][%t][%d{yyyy-MM-dd HH\:mm\:ss}][%C] - %m%n
#普通文件日志
log4j.appender.File=org.apache.log4j.RollingFileAppender
log4j.appender.File.File=logs/ssm.log
log4j.appender.File.MaxFileSize=10MB
#输出日志,如果换成DEBUG表示输出DEBUG以上级别日志
log4j.appender.File.Threshold=ALL
log4j.appender.File.layout=org.apache.log4j.PatternLayout
log4j.appender.File.layout.ConversionPattern=[%p][%t][%d{yyyy-MM-dd HH\:mm\:ss}][%C] - %m%n

首先对于基本格式中的配置根Logger这部分来说
log4j.rootLogger = [level] , appenderName1 , appenderName2 , …
我们的log4j.properties文件相应内容如下:
log4j.rootLogger=INFO,Console,File
其中[level]是日志输出级别分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。
appenderName:就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。例如:log4j.rootLogger=INFO,Console,File 配置了2个输出地方,这个名字可以任意(如上面的Console和File),但必须与我们在后面进行的设置名字对应。例如:log4j.appender.Console中的Consolelog4j.appender.File中的File就是对应之前写的名称。

在看接下来配置日志信息输出目的地Appender配置日志信息的格式(布局)的部分。
Appender 为日志输出目的地,Log4j提供的appender有以下几种:

org.apache.log4j.ConsoleAppender(控制台),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件),
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

Layout为日志输出格式,Log4j提供的layout有以下几种:

org.apache.log4j.HTMLLayout(以HTML表格形式布局),
org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

那么,我们log4j.properties的内容是否不难理解了。

#控制台日志
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%p][%t][%d{yyyy-MM-dd HH\:mm\:ss}][%C] - %m%n

appenderName为Console的日志输出目的地为控制台,采用了可以灵活地指定布局模式的格式。
至于其他的格式可以参考文章 配置Log4j

三、log4j框架加载调用


1、本地客户端项目加载log4j

(1)默认配置自动加载

java代码运行时,会在class文件的根目录(包名不是根目录,是class文件的一部分)寻找加载log4j.xml或者log4j.properties。一旦加载完成,就开启log4j功能了。

(2)代码加载(不管是main方法还是junit方法)

本地项目: 初始化log4j的日志配置,指定到src目录下(建议用2)

 //1. 本地项目-属性文件配置
 PropertyConfigurator.configure("src/config/log4j.properties");
 //2. 本地项目-xml文件配置
  DOMConfigurator.configure("src/config/log4j.xml");
 //3. 本地项目-默认配置
  BasicConfigurator.configure();

特别注意:
(1)、DOMConfiguratorPropertyConfigurator是用来加载不同类型的配置文件,别搞错了。

(2)、configure方法:里面的参数  如果是 文件夹 开头,则代表相对目录,这个相对目录是相对工程文件目录来说的,如果是  / 开头,代表根目录。获取路径可以参考java常识-获取路径的方法及注意点

(3)、当配置文件加载好后,log4j框架就已经在运行了,就已经在输出log日志了。

2、Web项目(如SSM)加载log4j

这是一个非常关键的问题,之前讲道我们采用配置Log4j来完成日志部分的操作,但是SSM框架是如何知道这个配置文件的存在并让它起作用呢?

(1)默认配置自动加载

java代码运行时,会在class文件的根目录(包名不是根目录,是class文件的一部分)寻找加载log4j.xml或者log4j.properties。一旦加载完成,就开启log4j功能了。

(2)在web.xml文件配置:

如果配置文件:改成6log4j.xml  ,则在web 可以进行如下配置:

 <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>classpath:6log4j.xml</param-value>
 </context-param>
 <listener>  
      <listener-class>  
           org.springframework.web.util.Log4jConfigListener  
      </listener-class>  
 </listener> 

当然也可以额外添加一个 配置:【不添加也没有关系】

<context-param>  
        <param-name>log4jRefreshInterval</param-name>  
        <param-value>60000</param-value>  
</context-param>

至于上述 log4j的配置,最好放在 org.springframework.web.context.ContextLoader前面。如果放在它后面,那么在加载org.springframework.web.context.ContextLoader这个listener的时会找不到log4j的配置文件,变会出现:

log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader). 
log4j:WARN Please initialize the log4j system properly.

到了后面:又会继续读取 web.xml 时,又会加载 log4j 的配置了。此时,网站已具有log4j的功能。 

(3)web项目单元测试

本地项目: 初始化log4j的日志配置,指定到src目录下(建议用2)

 //1. 本地项目-属性文件配置
 PropertyConfigurator.configure("src/config/log4j.properties");
 //2. 本地项目-xml文件配置
  DOMConfigurator.configure("src/config/log4j.xml");
 //3. 本地项目-默认配置
  BasicConfigurator.configure();

特别注意:
(1)、DOMConfiguratorPropertyConfigurator是用来加载不同类型的配置文件,别搞错了。

(2)、configure方法:里面的参数  如果是 文件夹 开头,则代表相对目录,这个相对目录是相对工程文件目录来说的, 如果是  / 开头,代表根目录。获取路径可以参考java常识-获取路径的方法及注意点

(3)、当配置文件加载好后,log4j框架就已经在运行了,就已经在输出log日志了。

3、在代码中调用log4j框架

当我们想要打印日志时,可以直接参考下面代码:

Logger logger = Logger.getLogger(JunitTest.class); 
// 记录debug级别的信息  
logger.error("This is debug message.");

4、不同构建器项目的路径获取比较

Java Builder 构建器

package com.test.springmvc.test;

import static org.junit.Assert.*;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.test.springmvc.dao.EmployeeMapper;


public class JBuilderTest {

	@Test
	public void test() {
		
		/*****
特别注意:
(1)、DOMConfigurator 和 PropertyConfigurator是用来加载不同类型的配置文件,别搞错了。

(2)、configure方法:里面的参数&nbsp; &nbsp;如果是&nbsp; / 开头,代表根目录,如果是 文件夹开头,则代表相对目录,这个相对目录是相对工程文件目录来说的。

(3)、当配置文件加载好后,log4j框架就已经在运行了,就已经在输出log日志了。
		 * ***/
		
//		BasicConfigurator.configure();
//		DOMConfigurator.configure("classpath:6log4j.xml");  //前面这个方法不行 ,后面这个方法也不行  "/classpath:6log4j.xml"  
//		DOMConfigurator.configure("conf/6log4j.xml");  
	DOMConfigurator.configure(Thread.currentThread().getContextClassLoader().getResource(".").getPath()+"6log4j.xml");  
	
//OK	DOMConfigurator.configure(Thread.currentThread().getContextClassLoader().getResource(".").getPath()+"test.log/log4j.xml");  
//	    Logger logger = Logger.getLogger(JunitTest.class); 
//	    // 记录debug级别的信息  
//	    logger.error("This is debug message."); 
		System.out.println(Thread.currentThread().getContextClassLoader().getResource(".").getPath());
	
		//1、创建SpringIOC容器
		ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
		//2、从容器中获取mapper
		EmployeeMapper bean = ioc.getBean(EmployeeMapper.class);
		
		System.out.println(bean.getEmps());
	}

}

Maven构建器:

package com.ssm.crud.test;

import java.io.IOException;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ssm.crud.mapper.DepartmentMapper;
import com.ssm.crud.mapper.EmployeeMapper;


public class CodeTest {
	
	DepartmentMapper departmentMapper;

	@Test
	public void testCRUD() throws IOException{
		//PropertyConfigurator.configure  与  DOMConfigurator.configure  是不同的,分别用于加载 properties 和 xml 类型的配置文件
		
        //下面这句话,加载的配置文件路径是   xxx/target/test-classes/6log4j.xml  结果 找不到, 因为真正的路径是  xxx/target/classes/6log4j.xml  
//        DOMConfigurator.configure(Thread.currentThread().getContextClassLoader().getResource("").getPath()+"6log4j.xml");  
        //因为无法正确加载路径,所以采取了 另一种 路径方法
        String config=System.getProperty("user.dir");//获取程序的当前路径 
        System.out.println("config="+config);
	    DOMConfigurator.configure(config+"/target/classes/6log4j.xml");  

       //要想 启用log4j 框架  只需要加载log4j配置文件就行 ,上面的代码已经加载 了
//     Log4j的 调用方法,版本是 1.X 的,  因为 log4j 2.x 的版本 ,配置文件和调用方法 都变不同了。 
//	   Logger logger = Logger.getLogger(MapperTest.class); 
//      // 记录debug级别的信息  
//      logger.error("This is debug message."); 
		
	    //1、创建SpringIOC容器  ,这个地方 却可以 正确加载 路径 xxx/target/classes/springIOC.xml
		
		//1、创建SpringIOC容器
		ApplicationContext ioc = new ClassPathXmlApplicationContext("springIOC.xml");
		//2、从容器中获取mapper
		EmployeeMapper bean = ioc.getBean(EmployeeMapper.class);
		
		System.out.println(bean.selectByPrimaryKey(1));
       
		
	}

}

 

 

参考:https://www.jianshu.com/p/f256866a2ebe

java工具-log4j框架-自动加载原理

log4j,如何“自动加载”?

今天看代码,发现log4j.properties。没有相应的加载代码,但它却生效了,这多神奇!
看进去,org.apache.log4j, LogManager.java,其有一个static方法块:

static {
    // By default we use a DefaultRepositorySelector which always returns 'h'.
    Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
    repositorySelector = new DefaultRepositorySelector(h);

    /** Search for the properties file log4j.properties in the CLASSPATH.  */
    String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
                               null);

    // if there is no default init override, then get the resource
    // specified by the user or the default config file.
    if(override == null || "false".equalsIgnoreCase(override)) {

      String configurationOptionStr = OptionConverter.getSystemProperty(
                              DEFAULT_CONFIGURATION_KEY, 
                              null);

      String configuratorClassName = OptionConverter.getSystemProperty(
                                                   CONFIGURATOR_CLASS_KEY, 
                           null);

      URL url = null;

      // if the user has not specified the log4j.configuration
      // property, we search first for the file "log4j.xml" and then
      // "log4j.properties"
      if(configurationOptionStr == null) {    
    url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
    if(url == null) {
      url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
    }
      } else {
    try {
      url = new URL(configurationOptionStr);
    } catch (MalformedURLException ex) {
      // so, resource is not a URL:
      // attempt to get the resource from the class path
      url = Loader.getResource(configurationOptionStr); 
    }    
      }
      
      // If we have a non-null url, then delegate the rest of the
      // configuration to the OptionConverter.selectAndConfigure
      // method.
      if(url != null) {
    LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");      
    OptionConverter.selectAndConfigure(url, configuratorClassName, 
                       LogManager.getLoggerRepository());
      } else {
    LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
      }
    }  
  }

换句话说,是什么呢?也就是说:

1. 获取系统属性,看是否用户设置了override。默认是不设置的。
2. 如果确实没有设置,那么尝试找一下,有没有log4j.xml,有则加载。
3. 如果还没有,那么尝试找一下,有没有log4j.properites,有则加载。

其中,2、3里提到的“尝试找一下”,可能是去哪个目录里面找呢?翻译了一下,效果不好,还是上原文清晰 :

Search for resource using the thread context class loader under Java2. If that fails, search for resource using the class loader that loaded this class (Loader). Under JDK 1.1, only the the class loader that loaded this class (Loader) is used.
Try one last time with ClassLoader.getSystemResource(resource), that is is using the system class loader in JDK 1.2 and virtual machine’s built-in class loader in JDK 1.1.

所以,你把log4j.xml或log4j.properties放在这些目录下,那么log4j会“自动去加载”到,不用程序里手工写加载代码了。

但我个人,还是倾向于自己写加载。因为这种“悄悄被人做掉”,一是代码很难理解,二是假如A同学放了一个log4j,B同学又写了一个放在其他目录,这种默认加载机制,不一定哪个生效及生效顺序。这种不确定性,还是自己写两行代码,消灭在摇篮里吧。

来自:http://www.cnblogs.com/alipayhutu/archive/2013/04/18/3028249.html