• Java日志系统(学习总结)


    JDK Logging

    从jdk1.4起,JDK开始自带一套日志系统。JDK Logger最大的优点就是不需要任何类库的支持,只要有Java的运行环境就可以使用。相对于其他的日志框架,JDK自带的日志可谓是鸡肋,无论易用性,功能还是扩展性都要稍逊一筹,所以在商业系统中很少直接使用。Java标准库内置了日志包java.util.logging,我们可以直接用。

    JDK的Logging定义了7个日志级别,从严重到普通:

    • SEVERE
    • WARNING
    • INFO
    • CONFIG
    • FINE
    • FINER
    • FINEST

    因为默认级别是INFO,因此,INFO级别以下的日志,不会被打印出来。使用日志级别的好处在于,调整级别,就可以屏蔽掉很多调试相关的日志输出。

    使用Java标准库内置的Logging有以下局限:

    Logging系统在JVM启动时读取配置文件并完成初始化,一旦开始运行main()方法,就无法修改配置;

    配置不太方便,需要在JVM启动时传递参数-Djava.util.logging.config.file=<config-file-name>

    因此,Java标准库内置的Logging使用并不是非常广泛。

    Commons Logging日志库

    Commons Logging是使用最广泛的日志模块;

    和Java标准库提供的日志不同,Commons Logging是一个第三方日志库,它是由Apache创建的日志模块。

    Commons Logging的特色是,它可以挂接不同的日志系统,并通过配置文件指定挂接的日志系统。默认情况下,Commons Loggin自动搜索并使用Log4j(Log4j是另一个流行的日志系统),如果没有找到Log4j,再使用JDK Logging。

    使用Commons Logging只需要和两个类打交道,并且只有两步:

    第一步,通过LogFactory获取Log类的实例; 第二步,使用Log实例的方法打日志。

    Commons Logging定义了6个日志级别:

    • FATAL
    • ERROR
    • WARNING
    • INFO
    • DEBUG
    • TRACE

    默认级别是INFO

    使用Commons Logging时,如果在静态方法中引用Log,通常直接定义一个静态类型变量:

    // 在静态方法中引用Log:
    public class Main {
        static final Log log = LogFactory.getLog(Main.class);
    
        static void foo() {
            log.info("foo");
        }
    }
    

    在实例方法中引用Log,通常定义一个实例变量:

    // 在实例方法中引用Log:
    public class Person {
        protected final Log log = LogFactory.getLog(getClass());
    
        void foo() {
            log.info("foo");
        }
    }
    

    注意到实例变量log的获取方式是LogFactory.getLog(getClass()),虽然也可以用LogFactory.getLog(Person.class),但是前一种方式有个非常大的好处,就是子类可以直接使用该log实例。例如:

    // 在子类中使用父类实例化的log:
    public class Student extends Person {
        void bar() {
            log.info("bar");
        }
    }
    

    此外,Commons Logging的日志方法,例如info(),除了标准的info(String)外,还提供了一个非常有用的重载方法:info(String, Throwable),这使得记录异常更加简单:

    try {
        ...
    } catch (Exception e) {
        log.error("got exception!", e);
    }
    

    Log4j日志框架

    Commons Logging,可以作为“日志接口”来使用。而真正的“日志实现”可以使用Log4j。

    Log4j是一种非常流行的日志框架,最新版本是2.x。

    Log4j是一个组件化设计的日志系统,它的架构大致如下:

    image-20200819091506541

    当我们使用Log4j输出一条日志时,Log4j自动通过不同的Appender把同一条日志输出到不同的目的地。例如:

    • console:输出到屏幕;
    • file:输出到文件;
    • socket:通过网络输出到远程计算机;
    • jdbc:输出到数据库

    在输出日志的过程中,通过Filter来过滤哪些log需要被输出,哪些log不需要被输出。例如,仅输出ERROR级别的日志。

    最后,通过Layout来格式化日志信息,例如,自动添加日期、时间、方法名称等信息。

    上述结构虽然复杂,但我们在实际使用的时候,并不需要关心Log4j的API,而是通过配置文件来配置它。

    以XML配置为例,使用Log4j的时候,我们把一个log4j2.xml的文件放到classpath下就可以让Log4j读取配置文件并按照我们的配置来输出日志。

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
    	<Properties>
            <!-- 定义日志格式 -->
    		<Property name="log.pattern">%d{MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}%n%msg%n%n</Property>
            <!-- 定义文件名变量 -->
    		<Property name="file.err.filename">log/err.log</Property>
    		<Property name="file.err.pattern">log/err.%i.log.gz</Property>
    	</Properties>
        <!-- 定义Appender,即目的地 -->
    	<Appenders>
            <!-- 定义输出到屏幕 -->
    		<Console name="console" target="SYSTEM_OUT">
                <!-- 日志格式引用上面定义的log.pattern -->
    			<PatternLayout pattern="${log.pattern}" />
    		</Console>
            <!-- 定义输出到文件,文件名引用上面定义的file.err.filename -->
    		<RollingFile name="err" bufferedIO="true" fileName="${file.err.filename}" filePattern="${file.err.pattern}">
    			<PatternLayout pattern="${log.pattern}" />
    			<Policies>
                    <!-- 根据文件大小自动切割日志 -->
    				<SizeBasedTriggeringPolicy size="1 MB" />
    			</Policies>
                <!-- 保留最近10份 -->
    			<DefaultRolloverStrategy max="10" />
    		</RollingFile>
    	</Appenders>
    	<Loggers>
    		<Root level="info">
                <!-- 对info级别的日志,输出到console -->
    			<AppenderRef ref="console" level="info" />
                <!-- 对error级别的日志,输出到err,即上面定义的RollingFile -->
    			<AppenderRef ref="err" level="error" />
    		</Root>
    	</Loggers>
    </Configuration>
    

    虽然配置Log4j比较繁琐,但一旦配置完成,使用起来就非常方便。对上面的配置文件,凡是INFO级别的日志,会自动输出到屏幕,而ERROR级别的日志,不但会输出到屏幕,还会同时输出到文件。并且,一旦日志文件达到指定大小(1MB),Log4j就会自动切割新的日志文件,并最多保留10份。

    有了配置文件还不够,因为Log4j也是一个第三方库,我们需要从这里下载Log4j,解压后,把以下3个jar包放到classpath中:

    • log4j-api-2.x.jar
    • log4j-core-2.x.jar
    • log4j-jcl-2.x.jar

    因为Commons Logging会自动发现并使用Log4j,所以,把上一节下载的commons-logging-1.2.jar也放到classpath中。

    要打印日志,只需要按Commons Logging的写法写,不需要改动任何代码,就可以得到Log4j的日志输出。

    在开发阶段,始终使用Commons Logging接口来写入日志,并且开发阶段无需引入Log4j。如果需要把日志写入文件, 只需要把正确的配置文件和Log4j相关的jar包放入classpath,就可以自动把日志切换成使用Log4j写入,无需修改任何代码。

    SLF4J和Logback

    Commons Logging和Log4j这一对好基友,它们一个负责充当日志API,一个负责实现日志底层,搭配使用非常便于开发。

    其实SLF4J类似于Commons Logging,也是一个日志接口,而Logback类似于Log4j,是一个日志的实现。

    为什么有了Commons Logging和Log4j,又会蹦出来SLF4J和Logback?这是因为Java有着非常悠久的开源历史,不但OpenJDK本身是开源的,而且我们用到的第三方库,几乎全部都是开源的。开源生态丰富的一个特定就是,同一个功能,可以找到若干种互相竞争的开源库。

    因为对Commons Logging的接口不满意,有人就搞了SLF4J。因为对Log4j的性能不满意,有人就搞了Logback。

    对比一下Commons Logging和SLF4J的接口:

    image-20200819093427782

    使用SLF4J和Logback和前面讲到的使用Commons Logging加Log4j是类似的,先分别下载SLF4JLogback,然后把以下jar包放到classpath下:

    • slf4j-api-1.7.x.jar
    • logback-classic-1.2.x.jar
    • logback-core-1.2.x.jar

    然后使用SLF4J的Logger和LoggerFactory即可。和Log4j类似,我们仍然需要一个Logback的配置文件,把logback.xml放到classpath下,配置如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
    
    	<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    		<encoder>
    			<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    		</encoder>
    	</appender>
    
    	<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    		<encoder>
    			<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    			<charset>utf-8</charset>
    		</encoder>
    		<file>log/output.log</file>
    		<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
    			<fileNamePattern>log/output.log.%i</fileNamePattern>
    		</rollingPolicy>
    		<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
    			<MaxFileSize>1MB</MaxFileSize>
    		</triggeringPolicy>
    	</appender>
    
    	<root level="INFO">
    		<appender-ref ref="CONSOLE" />
    		<appender-ref ref="FILE" />
    	</root>
    </configuration>
    

    从目前的趋势来看,越来越多的开源项目从Commons Logging加Log4j转向了SLF4J加Logback。

    参考资料

    https://www.liaoxuefeng.com/

  • 相关阅读:
    Android简易抽屉效果
    apk 下载并自动安装
    python2.7_1.3_获取远程设备的IP地址
    python2.7_1.2_打印设备名和IPv4地址
    python2.7_1.14_编写一个简单的回显客户端/服务器应用
    python2.7_1.13_编写一个SNTP客户端
    C语言程序转换为Python语言
    5分钟弄懂Docker!
    让正则表达式变简单(PythonVerbalExpressions)
    python sqlalchemy-migrate 使用方法
  • 原文地址:https://www.cnblogs.com/jianhaoscnu/p/13527535.html
Copyright © 2020-2023  润新知