• Log4j扩展使用--日志记录器Logger



    OK,现在我们认真的研究下Logger的配置,进行相关配置扩展。

    Log4j有三个主要的组件:Loggers(记录器),Appenders(输出源)和Layouts(布局)。其中,Logger负责记录日志,Appender负责输出到什么地方,Layout负责以什么格式输出,输出哪些附加信息等。综合使用这三个组件可以轻松的记录信息的类型和级别,并可以在运行时控制日志输出的样式和位置。

    • Log4J三个核心概念
    公共类     Logger       负责处理日志记录的大部分操作。 
    公共接口   Appender     负责控制日志记录的输出。 
    公共抽象类   Layout     负责格式化Appender的输出


    Logger日志记录器是日志处理的核心组件。现在我们来认真的整理下这个组件。Logger就是Java代码中的logger,例如:
    public static Logger log = Logger.getLogger(Log4jTest.class);
    Logger是有名字的,它的名字便是Logger.getLogger()方法的参数。如果参数为所在的类,Log4j会去类名作为logger的名称,比如org.linkinpark.commons.logtest.Log4jTest。

    Loggers组件在此系统中被分为五个级别:TRACE→DEBUG→INFO→WARNING→ERROR→FATAL→OFF。等级高的level自动屏蔽等级低的level,这点一定要记住。

    这里Log4j有一个规则:假设Loggers级别为P,如果在Loggers中发生了一个级别Q比P高,则可以启动,否则屏蔽掉。假设你定义的级别是info,那么error和warn的日志可以显示而比他低的debug信息就不显示了。

    注意以下几点:

    1,Logger为单态模式,相同名字的logger只会有一个实例。如果在构建一个同名的Logger,log4j会返回之前的Logger实例。

    2,一般情况下都以类名作为Logger的名称。Logger的名字类似于Java中的Package,大小写敏感,用点分开且具有继承关系。log4j.properties中通过名称来配置Logger的属性。

    3,在对Logger实例进行命名时,没有限制,可以取任意自己感兴趣的名字。一般情况下建议以类的所在位置来命名Logger实例,这是目前来讲比较有效的Logger命名方式。这样可以使得每个类建立自己的日志信息,便于管理。

    4,Log4j中有一个根记录器rootLogger,它是所有Logger的父类。

    • logger的配置
    在log.properties配置log4j.properties中,log4j.logger后面配置的是Logger,log4j.appender后面配置一个Appender。
    log4j.logger.org.linkinpark.commons.logtest.Log4jTest=INFO,console
    如果某个Logger没有配置,则使用它的父亲配置,知道找到为止。一般情况下,只需要配置根记录器rootLogger即可,所有的logger都会沿用rootLogger的配置。

    • rootLogger配置
    根记录器rootLogger直接用log4j.rootLogger配置即可。rootLogger是所有记录器的父亲,任何记录器都可以继承rootLogger的配置,代码如下:
    #log4j.rootLogger=DEBUG,console,file
    #log4j.logger.org.linkinpark.commons.logtest.Log4jTest=INFO
    log4j.rootLogger=INFO,console
      
    #输出到控制台   
    log4j.appender.console=org.apache.log4j.ConsoleAppender  
    #设置输出样式   
    log4j.appender.console.layout=org.apache.log4j.PatternLayout 
    #日志输出信息格式为
    log4j.appender.console.layout.ConversionPattern=[%-d{yyyy-MM-dd HH:mm:ss}]-[%t-%5p]-[%C-%M(%L)]: %m%n 
    注意:如果要对某个Logger进行特殊的输出,只需要再配置一下该Logger就OK,覆盖父亲的配置即可。覆盖时,可以只配置级别,输出地,也可以2者都配置。

    OK,现在我们举一个例子好了。

    比如我现在有如下需求,一般的日志打印我都按照某一种特定的配置就够了,但是有一个类比较特殊,我需要进行特殊的配置那么要如何做呢?

    1,写好2个Java源码,输出日志

    2,主要是写好这个log4j.properties文件。先定义rootLogger,然后子类重新配置覆盖rootLogger就够了。但是丫的有一个问题就是说如果子类重新定义了appender,仍然会继承rootLogger的配置,也就是说2份日志输出了,我晕。

    所以以后建议控制子类重写覆盖rootLogger配置的时候,只重写日志级别好了,其他的别动。OK,现在贴出代码:

    package org.linkinpark.commons.logtest;
    
    import org.apache.log4j.Logger;
    
    /**
     * @创建作者: LinkinPark
     * @创建时间: 2016年2月23日
     * @功能描述: 这个类用log4j的rootLogger默认输出
     */
    public class Log4jTest
    {
    
    	public static Logger log = Logger.getLogger(Log4jTest.class);
    
    	/**
    	 * @创建时间: 2016年2月22日
    	 * @相关参数:
    	 * @功能描述: 定义一个输出日志的方法
    	 * <p>
    	 * trace→debug→info→warn→error→fatal→off
    	 * 级别依次升高,级别高的level会屏蔽级别低的level。
    	 * </p>
    	 */
    	public static void logTest()
    	{
    		System.out.println("=======这里是rootLogger类的日志输出======");
    		if (log.isDebugEnabled())
    		{
    			log.debug("debug级别的日志输出");
    		}
    		log.trace("trace级别的日志输出");
    		log.info("info级别的日志输出");
    		log.warn("warn级别的日志输出");
    		log.error("error级别的日志输出");
    		log.fatal("fatal级别的日志输出");
    		try
    		{
    			System.out.println(9 / 0);
    		}
    		catch (RuntimeException e)
    		{
    			log.error(e.getMessage());
    		}
    	}
    
    	public static void main(String[] args)
    	{
    		logTest();
    	}
    
    }
    
    package org.linkinpark.commons.logtest;
    
    import org.apache.log4j.Logger;
    
    /**
     * @创建作者: LinkinPark
     * @创建时间: 2016年2月23日
     * @功能描述: 这个类重新配置,来重写rootLogger的日志级别
     */
    public class Log4jTest1
    {
    
    	public static Logger log = Logger.getLogger(Log4jTest1.class);
    
    	/**
    	 * @创建时间: 2016年2月22日
    	 * @相关参数:
    	 * @功能描述: 定义一个输出日志的方法
    	 * <p>
    	 * trace→debug→info→warn→error→fatal→off
    	 * 级别依次升高,级别高的level会屏蔽级别低的level。
    	 * </p>
    	 */
    	public static void logTest()
    	{
    		System.out.println("=======这里是特定类的日志输出======");
    		log.info("info级别的日志输出");
    		log.warn("warn级别的日志输出");
    		log.error("error级别的日志输出");
    		log.fatal("fatal级别的日志输出");
    		try
    		{
    			throw new NullPointerException("人工抛出一个异常");
    		}
    		catch (RuntimeException e)
    		{
    			log.error(e.getMessage());
    		}
    	}
    
    	public static void main(String[] args)
    	{
    		logTest();
    		Log4jTest.logTest();
    	}
    
    }
    
    #	可设置级别:TRACE→DEBUG→INFO→WARNING→ERROR→FATAL→OFF
    #	高级别level会屏蔽低级别level。
    #	debug:显示debug、info、error   
    #	info:显示info、error   
    
    #log4j.rootLogger=DEBUG,console,file
    log4j.logger.org.linkinpark.commons.logtest.Log4jTest1=ERROR
    log4j.rootLogger=INFO,console
    
    # 一下是rootLogger的配置,子类默认继承,但是子类重写下面配置=rootLogger+自己配置,我晕
    #输出到控制台   
    log4j.appender.console=org.apache.log4j.ConsoleAppender  
    #设置输出样式   
    log4j.appender.console.layout=org.apache.log4j.PatternLayout 
    #日志输出信息格式为
    log4j.appender.console.layout.ConversionPattern=[%-d{yyyy-MM-dd HH:mm:ss}]-[%t-%5p]-[%C-%M(%L)]: %m%n 
    
    #输出到文件(这里默认为追加方式)   
    #log4j.appender.file=org.apache.log4j.FileAppender 
    #log4j.appender.file.File=F:/LinkinPark/logs/Log4J.log 
    #样式为TTCCLayout   
    #log4j.appender.file.layout=org.apache.log4j.TTCCLayout  
    
    #自定义样式   
    #%c	输出所属的类目,通常就是所在类的全名 
    #%C	输出Logger所在类的名称,通常就是所在类的全名 
    #%d	输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss , SSS},%d{ABSOLUTE},%d{DATE}
    #%F	输出所在类的类名称,只有类名。
    #%l	输出语句所在的行数,包括类名+方法名+文件名+行数
    #%L	输出语句所在的行数,只输出数字
    #%m	输出代码中指定的讯息,如log(message)中的message
    #%M	输出方法名
    #%p	输出日志级别,即DEBUG,INFO,WARN,ERROR,FATAL
    #%r	输出自应用启动到输出该log信息耗费的毫秒数
    #%t	输出产生该日志事件的线程名
    #%n	输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n”
    #%%	用来输出百分号“%”
    #log4j.appender.Linkin.layout.ConversionPattern=%n[%l%d{yy/MM/dd HH:mm:ss:SSS}][%C-%M] %m  
    #log4j.appender.Linkin.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss}[%C]-[%p] %m%n   
    #log4j.appender.Linkin.layout.ConversionPattern = %d{ABSOLUTE} %5p %t %c{2}:%L - %m%n
    

    OK,现在我们来看下控制台输出,没问题。

    =======这里是特定类的日志输出======
    [2016-02-23 00:23:54]-[main-ERROR]-[org.linkinpark.commons.logtest.Log4jTest1-logTest(24)]: error级别的日志输出
     [2016-02-23 00:23:54]-[main-FATAL]-[org.linkinpark.commons.logtest.Log4jTest1-logTest(25)]: fatal级别的日志输出
     [2016-02-23 00:23:54]-[main-ERROR]-[org.linkinpark.commons.logtest.Log4jTest1-logTest(32)]: 人工抛出一个异常
     =======这里是rootLogger类的日志输出======
    [2016-02-23 00:23:54]-[main- INFO]-[org.linkinpark.commons.logtest.Log4jTest-logTest(27)]: info级别的日志输出
     [2016-02-23 00:23:54]-[main- WARN]-[org.linkinpark.commons.logtest.Log4jTest-logTest(28)]: warn级别的日志输出
     [2016-02-23 00:23:54]-[main-ERROR]-[org.linkinpark.commons.logtest.Log4jTest-logTest(29)]: error级别的日志输出
     [2016-02-23 00:23:54]-[main-FATAL]-[org.linkinpark.commons.logtest.Log4jTest-logTest(30)]: fatal级别的日志输出
     [2016-02-23 00:23:54]-[main-ERROR]-[org.linkinpark.commons.logtest.Log4jTest-logTest(37)]: / by zero
     


    • 类别category配置
    logger还有一个类别(category)的概念,荣国设置类别来设置类别下所有的logger。category类似于Java的package,效果和Logger的名字等价。这里也举一个例子好了:

    OK,我们复制前面的log4jTest到一个新的包logtest1下,2份Java代码不变,然后设置配置文件控制不同的日志级别,来看看效果。

      

    #	可设置级别:TRACE→DEBUG→INFO→WARNING→ERROR→FATAL→OFF
    #	高级别level会屏蔽低级别level。
    #	debug:显示debug、info、error   
    #	info:显示info、error   
    
    #log4j.rootLogger=DEBUG,console,file
    #子类重新定义日志级别,logger的名字是日志类的权限类名
    #log4j.logger.org.linkinpark.commons.logtest.Log4jTest1=ERROR
    #子类重新定义日志级别,category的名字是日志类的包名,可以将category理解为Java的package。
    log4j.category.org.linkinpark.commons.logtest1=ERROR
    log4j.rootLogger=DEBUG,console
    
    # 以下是rootLogger的配置,子类默认继承,但是子类重写下面配置=rootLogger+自己配置,我晕
    #输出到控制台   
    log4j.appender.console=org.apache.log4j.ConsoleAppender  
    #设置输出样式   
    log4j.appender.console.layout=org.apache.log4j.PatternLayout 
    #日志输出信息格式为
    log4j.appender.console.layout.ConversionPattern=[%-d{yyyy-MM-dd HH:mm:ss}]-[%t-%5p]-[%C-%M(%L)]: %m%n 
    
    #输出到文件(这里默认为追加方式)   
    #log4j.appender.file=org.apache.log4j.FileAppender 
    #log4j.appender.file.File=F:/LinkinPark/logs/Log4J.log 
    #样式为TTCCLayout   
    #log4j.appender.file.layout=org.apache.log4j.TTCCLayout  
    
    #自定义样式   
    #%c	输出所属的类目,通常就是所在类的全名 
    #%C	输出Logger所在类的名称,通常就是所在类的全名 
    #%d	输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss , SSS},%d{ABSOLUTE},%d{DATE}
    #%F	输出所在类的类名称,只有类名。
    #%l	输出语句所在的行数,包括类名+方法名+文件名+行数
    #%L	输出语句所在的行数,只输出数字
    #%m	输出代码中指定的讯息,如log(message)中的message
    #%M	输出方法名
    #%p	输出日志级别,即DEBUG,INFO,WARN,ERROR,FATAL
    #%r	输出自应用启动到输出该log信息耗费的毫秒数
    #%t	输出产生该日志事件的线程名
    #%n	输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n”
    #%%	用来输出百分号“%”
    #log4j.appender.Linkin.layout.ConversionPattern=%n[%l%d{yy/MM/dd HH:mm:ss:SSS}][%C-%M] %m  
    #log4j.appender.Linkin.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss}[%C]-[%p] %m%n   
    #log4j.appender.Linkin.layout.ConversionPattern = %d{ABSOLUTE} %5p %t %c{2}:%L - %m%n
    
    OK,我们现在看下控制台输出:没问题,成功输出我们自己定义的特定的包下面的日志,并且按照我们自己配置的日志级别。

    =======这里是特定包下面类的日志输出======
    [2016-02-23 00:39:56]-[main-ERROR]-[org.linkinpark.commons.logtest1.Log4jTest1-logTest(30)]: error级别的日志输出
     [2016-02-23 00:39:56]-[main-FATAL]-[org.linkinpark.commons.logtest1.Log4jTest1-logTest(31)]: fatal级别的日志输出
     [2016-02-23 00:39:56]-[main-ERROR]-[org.linkinpark.commons.logtest1.Log4jTest1-logTest(38)]: 人工抛出一个异常
     =======这里是rootLogger类的日志输出======
    [2016-02-23 00:39:56]-[main-DEBUG]-[org.linkinpark.commons.logtest.Log4jTest-logTest(29)]: debug级别的日志输出
     [2016-02-23 00:39:56]-[main- INFO]-[org.linkinpark.commons.logtest.Log4jTest-logTest(32)]: info级别的日志输出
     [2016-02-23 00:39:56]-[main- WARN]-[org.linkinpark.commons.logtest.Log4jTest-logTest(33)]: warn级别的日志输出
     [2016-02-23 00:39:56]-[main-ERROR]-[org.linkinpark.commons.logtest.Log4jTest-logTest(34)]: error级别的日志输出
     [2016-02-23 00:39:56]-[main-FATAL]-[org.linkinpark.commons.logtest.Log4jTest-logTest(35)]: fatal级别的日志输出
     [2016-02-23 00:39:56]-[main-ERROR]-[org.linkinpark.commons.logtest.Log4jTest-logTest(42)]: / by zero
     

    OK,下一篇我会整理到日志的输出组件Appender。

  • 相关阅读:
    表单元素(控件)不可见属性“visibility”和“display”分析
    如何实现网页的右键菜单功能
    Google Chrome 11 浏览器 下Flash Debug 插件无效的解决办法
    embed区别object
    在Fedora 12 下安装Intel X4500 显卡驱动
    HDOJ 2000
    费马小定理
    HDOJ 2055
    HDOJ 1018(阶乘位数)
    大数阶乘所得数位数的定理
  • 原文地址:https://www.cnblogs.com/LinkinPark/p/5232851.html
Copyright © 2020-2023  润新知