• Java中的Log


    参考:
    Java日志框架那些事儿
    https://www.cnblogs.com/chenhongliang/p/5312517.html
    关于slf4j log4j log4j2的jar包配合使用的那些事

    概述

    Java常用日志框架类别

    在Java开发中,常用的日志记录框架有JDKLog、Log4J、LogBack、Commons Logging(JCL)、SLF4J。这些日志记录框架各有各的特点,各有各的应用场景。了解这些框架的特点及应用场景,有利于我们做技术选型的时候做出正确的判断。

    • JDKLog 又称JUL(Java Util Logging),自Java1.4以来的官方日志实现。

    • Log4j Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的,现在则是Apache软件基金会的一个项目。 Log4j是几种Java日志框架之一。

    • Log4j 2 Apache Log4j 2是apache开发的一款Log4j的升级产品。

    • Logback 一套日志组件的实现(Slf4j阵营)。
    • Commons Logging (JCL,Jakarta Commons Logging) Apache基金会所属的项目,是一套Java日志接口,之前叫Jakarta Commons Logging,后更名为Commons Logging。

    • Slf4j (Simple Logging Facade for Java,缩写Slf4j)类似于Commons Logging,也是接口,是一套简易Java日志门面,本身并无日志的实现。

    Java常用日志框架历史

    • 1996年早期,欧洲安全电子市场项目组决定编写它自己的程序跟踪API(Tracing API)。经过不断的完善,这个API终于成为一个十分受欢迎的Java日志软件包,即Log4j。后来Log4j成为Apache基金会项目中的一员。

    • 期间Log4j近乎成了Java社区的日志标准。据说Apache基金会还曾经建议Sun引入Log4j到java的标准库中,但Sun拒绝了。

    • 2002年Java1.4发布,Sun推出了自己的日志库JUL(Java Util Logging),其实现基本模仿了Log4j的实现。在JUL出来以前,Log4j就已经成为一项成熟的技术,使得Log4j在选择上占据了一定的优势。

    • 接着,Apache推出了Jakarta Commons Logging,JCL只是定义了一套日志接口(其内部也提供一个Simple Log的简单实现),支持运行时动态加载日志组件的实现,也就是说,在你应用代码里,只需调用Commons Logging的接口,底层实现可以是Log4j,也可以是Java Util Logging。

    • 后来(2006年),Ceki Gülcü不适应Apache的工作方式,离开了Apache。然后先后创建了Slf4j(日志门面接口,类似于Commons Logging)和Logback(Slf4j的实现)两个项目,并回瑞典创建了QOS公司,QOS官网上是这样描述Logback的:The Generic,Reliable Fast&Flexible Logging Framework(一个通用,可靠,快速且灵活的日志框架)。

    • 现今,Java日志领域被划分为两大阵营:Commons Logging阵营和Slf4j阵营。
      Commons Logging在Apache大树的笼罩下,有很大的用户基数。但有证据表明,形式正在发生变化。2013年底有人分析了GitHub上30000个项目,统计出了最流行的100个Libraries,可以看出Slf4j的发展趋势更好。

    • Apache眼看有被Logback反超的势头,于2012-07重写了Log4j 1.x,成立了新的项目Log4j 2, Log4j 2具有Logback的所有特性。

    java常用日志框架关系

    Log4j 2与Log4j 1发生了很大的变化,Log4j 2不兼容Log4j 1。

    Commons Logging和Slf4j是日志门面(门面模式是软件工程中常用的一种软件设计模式,也被称为正面模式、外观模式。它为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用)。Log4j和Logback则是具体的日志实现方案。可以简单的理解为接口与接口的实现,调用者只需要关注接口而无需关注具体的实现,做到解耦。

    比较常用的组合使用方式是Slf4j与Logback组合使用,Commons Logging与Log4j组合使用。

    Logback必须配合Slf4j使用。由于Logback和Slf4j是同一个作者,其兼容性不言而喻。

    Commons Logging与Slf4j实现机制对比

    Commons Logging实现机制
        Commons Logging是通过动态查找机制,在程序运行时,使用自己的ClassLoader寻找和载入本地具体的实现。详细策略可以查看commons-logging-*.jar包中的org.apache.commons.logging.impl.LogFactoryImpl.java文件。由于Osgi不同的插件使用独立的ClassLoader,Osgi的这种机制保证了插件互相独立, 其机制限制了Commons Logging在Osgi中的正常使用。

    Slf4j实现机制
        Slf4j在编译期间,静态绑定本地的Log库,因此可以在Osgi中正常使用。它是通过查找类路径下org.slf4j.impl.StaticLoggerBinder,然后在StaticLoggerBinder中进行绑定。

    项目中选择日志框架选择

    如果是在一个新的项目中建议使用Slf4j与Logback组合,这样有如下的几个优点。

    • Slf4j实现机制决定Slf4j限制较少,使用范围更广。由于Slf4j在编译期间,静态绑定本地的LOG库使得通用性要比Commons Logging要好。

    • Logback拥有更好的性能。Logback声称:某些关键操作,比如判定是否记录一条日志语句的操作,其性能得到了显著的提高。这个操作在Logback中需要3纳秒,而在Log4J中则需要30纳秒。LogBack创建记录器(logger)的速度也更快:13毫秒,而在Log4J中需要23毫秒。更重要的是,它获取已存在的记录器只需94纳秒,而Log4J需要2234纳秒,时间减少到了1/23。跟JUL相比的性能提高也是显著的。

    • Commons Logging开销更高

    # 在使Commons Logging时为了减少构建日志信息的开销,通常的做法是
    if(log.isDebugEnabled()){
      log.debug("User name: " +
        user.getName() + " buy goods id :" + good.getId());
    }
    
    # 在Slf4j阵营,你只需这么做:
    log.debug("User name:{} ,buy goods id :{}", user.getName(),good.getId());
    
    # 也就是说,Slf4j把构建日志的开销放在了它确认需要显示这条日志之后,减少内存和Cup的开销,使用占位符号,代码也更为简洁
    
    • Logback文档免费。Logback的所有文档是全面免费提供的,不象Log4J那样只提供部分免费文档而需要用户去购买付费文档。

    JDKLog

    JDKLog又称为Jul (Java Util Logging),自Java1.4以来的官方日志实现。是JDK官方提供的一个记录日志的方式,直接在JDK中就可以使用。

    package i_log;
    import java.util.logging.Logger;
    import org.junit.jupiter.api.Test;
    
    public class TestJdkLogging {
        static Logger logger = Logger.getLogger("MyLog");
    
        @Test
        public void test01() {
            logger.severe("[severe]除数不能为0.");      //严重
            logger.warning("[warning]除数不能为0.");    //警告
            logger.info("[info]除数不能为0.");          //信息
            logger.config("[config]除数不能为0.");    //配置
            logger.fine("[fine]除数不能为0.");          //良好
            logger.finer("[finer]除数不能为0.");      //较好
            logger.finest("[finest]除数不能为0.");    //最好
            // ** 注意:默认输出级别:info和info以上
        }
    }
    /*
    十月 09, 2021 7:03:26 下午 i_log.TestJdkLogging test01
    严重: [severe]除数不能为0.
    十月 09, 2021 7:03:26 下午 i_log.TestJdkLogging test01
    警告: [warning]除数不能为0.
    十月 09, 2021 7:03:26 下午 i_log.TestJdkLogging test01
    信息: [info]除数不能为0.
    */

    JDKLog 是使用非常简单,直接在 JDK 中就可以使用。但 JDKLog 功能比较太过于简单,不支持占位符显示,拓展性比较差,所以现在用的人也很少。

    Log4J

    Log4J 是 Apache 的一个日志开源框架,有多个分级(DEBUG/INFO/WARN/ERROR)记录级别,可以很好地将不同日志级别的日志分开记录,极大地方便了日志的查看。

    Log4J 有 1.X 版本和 2.X 版本,现在官方推荐使用 2.X 版本,2.X 版本在架构上进行了一些升级,配置文件也发生了一些变化。但好在官方的配置说明文档非常清楚,通过查阅文档能解决大部分的问题。

    Log4J   1.x 版本

    导入jar包:

    在src包下(classpath下)添加 Log4j.properties 文件

    #set log level: show debug, info, error
    log4j.rootLogger=DEBUG, A1, A2
    
     
    
    # A1 is set to be a ConsoleAppender which outputs to System.out. 
    log4j.appender.A1=org.apache.log4j.ConsoleAppender
    log4j.appender.A2=org.apache.log4j.FileAppender
    
     
    
    # uses PatternLayout.
    log4j.appender.A1.layout=org.apache.log4j.PatternLayout
    #自定义样式  
    #Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下: %m 输出代码中指定的消息
    #  %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
    #  %r 输出自应用启动到输出该log信息耗费的毫秒数
    #  %c 输出所属的类目,通常就是所在类的全名
    #  %t 输出产生该日志事件的线程名
    #  %n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”
    #  %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
    #  %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
    log4j.appender.A1.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%t] [%-5p] - %l :%m%n
    
    log4j.appender.A2.layout=org.apache.log4j.TTCCLayout
    
    #out
    log4j.appender.A2.File=E:/test/log4j.log
    View Code

    代码:

    package i_log;
    
    import org.apache.log4j.Logger;
    import org.junit.jupiter.api.Test;
    
    public class TestLog4j {
        private static Logger logger = Logger.getLogger(TestLog4j.class);
    
        @Test
        public void test01() {
            System.out.println("This is log4j test.");
            // 记录debug级别的信息
            logger.debug("This is debug message.");
            // 记录info级别的信息
            logger.info("This is info message.");
            // 记录warn级别的信息
            logger.warn("This is warn message");
            // 记录error级别的信息
            logger.error("This is error message.");
        }
    
    }
    /*
    This is log4j test.
    [2021-10-09 19:48:09.373] [main] [DEBUG] - i_log.TestLog4j.test01(TestLog4j.java:13) :This is debug message.
    [2021-10-09 19:48:09.378] [main] [INFO ] - i_log.TestLog4j.test01(TestLog4j.java:15) :This is info message.
    [2021-10-09 19:48:09.378] [main] [WARN ] - i_log.TestLog4j.test01(TestLog4j.java:17) :This is warn message
    [2021-10-09 19:48:09.378] [main] [ERROR] - i_log.TestLog4j.test01(TestLog4j.java:19) :This is error message.
    
    */
    View Code

    Log4J   2.x 版本

    新建maven工程,导入依赖

      	<dependency>
    	    <groupId>org.apache.logging.log4j</groupId>
    	    <artifactId>log4j-core</artifactId>
    	    <version>2.14.1</version>
    	</dependency>
    	<dependency>
    	    <groupId>org.apache.logging.log4j</groupId>
    	    <artifactId>log4j-api</artifactId>
    	    <version>2.14.1</version>
    	</dependency>
    

    在classpath下(resource包或src包)添加 log4j2.xml,内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="WARN">
        <Appenders>
            <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            </Console>
        </Appenders>
        <Loggers>
            <Root level="trace">
                <AppenderRef ref="Console"/>
            </Root>
        </Loggers>
    </Configuration>

    其中节点的 level 属性表示输出的最低级别,level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF。详细配置说明参考:log4j2配置文件log4j2.xml详解(转载)

    	%d{HH:mm:ss.SSS} 表示输出到毫秒的时间
     	%t 输出当前线程名称
      	%-5level 输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补0
      	%logger 输出logger名称,因为Root Logger没有名称,所以没有输出
     	%msg 日志文本
      	%n 换行
      其他常用的占位符有:
      	%F 输出所在的类文件名,如Log4j2Test.java
      	%L 输出行号
      	%M 输出所在方法名
      	%l 输出语句所在的行数, 包括类名、方法名、文件名、行数
    

    代码例子:

    package cn.love.test;
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    public class TestLog4j2 {
        public static void main(String args[]) {
            Logger logger = LogManager.getLogger(TestLog4j2.class);
            logger.trace("This is trace message.{} {}", 10, "hello");
            logger.debug("Debug Level");
            logger.info("Info Level");
            logger.warn("Warn Level");
            logger.error("Error Level");
        }
    }
    /*
    20:36:29.181 [main] TRACE cn.love.test.TestLog4j2 - This is trace message.10 hello
    20:36:29.185 [main] DEBUG cn.love.test.TestLog4j2 - Debug Level
    20:36:29.185 [main] INFO  cn.love.test.TestLog4j2 - Info Level
    20:36:29.185 [main] WARN  cn.love.test.TestLog4j2 - Warn Level
    20:36:29.185 [main] ERROR cn.love.test.TestLog4j2 - Error Level
    */

    如果没有配置 log4j2.xml 配置文件,那么LOG4J将自动启用类似于下面的的配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="WARN">
        <Appenders>
            <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            </Console>
        </Appenders>
        <Loggers>
            <Root level="error">
                <AppenderRef ref="Console"/>
            </Root>
        </Loggers>
    </Configuration>

    LogBack

    LogBack 其实可以说是 Log4J 的进化版,因为它们两个都是同一个人(Ceki Gülcü)设计的开源日志组件。

    使用 LogBack 需要首先引入依赖:

      	<dependency>
    	  <groupId>ch.qos.logback</groupId>
    	  <artifactId>logback-classic</artifactId>
    	  <version>1.2.5</version>
    	</dependency>
    

    在classpath下添加 logback.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <layout class="ch.qos.logback.classic.PatternLayout">
                <Pattern>%d{yyyy-MM-dd HH:mm:ss} [%t] [%-5level] %logger{36} - %msg%n</Pattern>
            </layout>
        </appender>
        <appender name="FILE" class="ch.qos.logback.core.FileAppender"> 
            <file>E:/test/logback.log</file> 
            <append>true</append> 
            <encoder> 
                <pattern>%d{yyyy-MM-dd HH:mm:ss} [%t] [%-5level] %logger{36} - %msg%n</pattern> 
            </encoder>
        </appender>
        
        
        <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
        <property name="LOG_HOME" value="E:/test" />
        <!--文件日志, 按照每天生成日志文件 -->
        <appender name="FILE2" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--日志文件输出的文件名-->
                <FileNamePattern>${LOG_HOME}/logback.%d{yyyy-MM-dd}.log</FileNamePattern>
                <!--日志文件保留天数-->
                <MaxHistory>30</MaxHistory>
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            </encoder>
            <!--日志文件最大的大小-->
            <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
                <MaxFileSize>20MB</MaxFileSize>
            </triggeringPolicy>
        </appender>
     
        <root level="debug">
            <appender-ref ref="STDOUT" />
            <appender-ref ref="FILE" />
            <appender-ref ref="FILE2"/>
        </root>
        <!-- 指定包下的日志输出级别,默认继承自Root -->
        <logger name="cn.love.test2" level="TRACE"/>
    </configuration>
    View Code

    详细参考:logback配置文件---logback.xml详解

    代码例子:

    package cn.love.test2;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class TestLogback {
        private static final Logger logger = LoggerFactory.getLogger(TestLogback.class);
        
        public static void main(String args[]) {
            logger.trace("This is trace message.{} {}", 10, "hello");
            logger.debug("Debug Level");
            logger.info("Info Level");
            logger.warn("Warn Level");
            logger.error("Error Level");
        }
    }

    SLF4J

    SLF4J+JDKLog

    SLF4J + JDKLog 需要在 Maven 中导入以下依赖包:

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.21</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-jdk14</artifactId>
      <version>1.7.21</version>
    </dependency>
    

    编写测试类:

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
     
    /****
     ** SLF4J + JDKLog
     **/
    public class Slf4jJDKLog {
        final static Logger logger = LoggerFactory.getLogger(Slf4jJDKLog.class);
        public static void main(String[] args) {
            logger.trace("Trace Level.");
            logger.info("Info Level.");
            logger.warn("Warn Level.");
            logger.error("Error Level.");
        }
    }
    

    输出结果:

    七月 15, 2016 3:30:02 下午 com.chanshuyi.slf4j.Slf4jJDKLog main
    信息: Info Level.
    七月 15, 2016 3:30:02 下午 com.chanshuyi.slf4j.Slf4jJDKLog main
    警告: Warn Level.
    七月 15, 2016 3:30:02 下午 com.chanshuyi.slf4j.Slf4jJDKLog main
    严重: Error Level.
    

    SLF4J+LOG4J

    需要依赖的 Jar 包:slf4j-api.jar、slf4j-log4j12.jar、log4j.jar,导入Maven依赖:

          <!-- slf4j 对Log4j1.2版本的桥接器 -->
          <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.26</version>
        </dependency>
    会自动导入依赖的 slf4j-api-1.7.26.jar   log4j-1.2.17.jar

    在src包下(classpath下)添加 Log4j.properties 文件

    我们还是用上面的代码,无需做改变

    SLF4J+LogBack

    导入依赖:

      <dependencies>
    <!--       <dependency> -->
    <!--       <groupId>org.slf4j</groupId> -->
    <!--       <artifactId>slf4j-api</artifactId> -->
    <!--       <version>1.7.31</version> -->
    <!--     </dependency> -->
        <!-- logback-classic 依赖了logback-core和slf4j-api,所以可以不用写了 -->
        <dependency>
          <groupId>ch.qos.logback</groupId>
          <artifactId>logback-classic</artifactId>
          <version>1.2.5</version>
        </dependency>
    <!--     <dependency> -->
    <!--       <groupId>ch.qos.logback</groupId> -->
    <!--       <artifactId>logback-core</artifactId> -->
    <!--       <version>1.2.5</version> -->
    <!--     </dependency> -->
      </dependencies>

    配置 logback.xml 文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <layout class="ch.qos.logback.classic.PatternLayout">
                <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
            </layout>
        </appender>
        <logger name="com.chanshuyi" level="TRACE"/>
     
        <root level="warn">
            <appender-ref ref="STDOUT" />
        </root>
    </configuration>
    

    我们还是用上面的代码,无需做改变

    常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。争渡,争渡,惊起一滩鸥鹭。

    昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。
  • 相关阅读:
    实现分享功能(分享到qq空间,新浪微博)
    AXIOS构建请求处理全局loading状态&&AXIOS避免重复请求loading多次出现
    Vue.use() 方法
    判断浏览器版本
    判断当前环境是ios还是安卓
    如何理解react中的super() super(props)
    JavaScript 函数调用时带括号和不带括号的区别
    npm 安装时 --save --dev 和 --save 区别
    npm 全局安装和局部安装的区别
    module.exports 与 exports
  • 原文地址:https://www.cnblogs.com/htj10/p/15243036.html
Copyright © 2020-2023  润新知