Java日志快速入门

Java Log 快速入门

一、日志框架介绍

1、Java 日志框架的分类

在 Java 框架系统中,为了可以在不同的日志系统中进行切换,于是将 Java 日志API的调用实现进行分离

专门进行 API 定义的叫做 日志门面

Java 日志实现 则是针对专门的日志门面实现的

2、具体框架

在Java里面,流行的共有两种日志门面

  • JCL(Jakarta Common Logging),该日志下实现较老,现在不流行使用
  • SLF4J(Simple Logging Facade For Java),目前流行的日志门面

门面日志只能给出有哪些隔离级别,但不能设置,具体的级别由日志实现决定,这点非常重要


同样,在Java生态中也存在的很多的Java日志实现

  • Log4j,公有两个大版本,Log4j1Log4j21.x版本已停止维护,现在一般是直接使用2.x版本,且性能更高(支持异步日志)
  • JUL,这是JavaSE默认的日志实现,默认的配置文件位于JAVA_HOME目录下的conf文件夹下的logging.properties文件
  • LogbackLog4j1作者的另一个日志框架,性能也很高,SpringBoot的默认日志框架

二、不同日志框架快速使用

日志门面就是一个API框架,他会自动发现classpath下实现该API的日志框架并使用,如果发现多个,则会输出警告并选择一个日志实现

利用日志门面API,可以获取对应的 Logger对象并使用,它真实的工作过程还是使用的日志实现,日志门面只是个封装作用

(1)、JCL

JCL里面有两个重要的对象,

日志的隔离级别

trace > debug > info > warn > error > fatal,这个隔离级别是接口的,门面日志不能设置隔离级别

  • LogFactory,日志工厂,利用日志工厂可以获取一个日志对象,其他框架为了实现该日志门面,需要实现该抽象类
  • Log,日志对象,在JCL里面就是个通用的接口,通过该接口对象完成日志的输出

调用 **LogFactory.getLog()**获取一个日志对象(注意接口的包路径)

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Main
{
    public static void main(String[] args)
    {
        Log log = LogFactory.getLog(Main.class);
        log.error("Hello World!");
    }
}

在新版本的JCL里面,内置了多个LogFactoryLogger的实现,比如log4j2、slf4j、JUL,所以只需要导入对应的依赖就可以直接使用了

如果存在多个实现,则会优先log4j2,再slf4j,最后如果没有提供任何实现时,则使用JUL(或通过commons-logging.properties配置文件指定)

关于slf4j,这其实是另一个日志门面,也就是说它也只是一套API,它需要他自己的门面日志实现

如果使用了JCL没有默认实现的日志系统,则需要自己提供对应的适配器(使日志框架适配日志门面)

大概过程是实现LogFactory抽象类和Logger接口,并使用commons-logging.properties(resources目录下)配置文件指定


由于传统的JCL性能不太好,所以Spirng重写了一套JCL实现,叫做spring-jcl,它的工作原理和过程与传统的JCL几乎相同,就连包名都相同

使用时,只需要导入使用的日志实现就可以了

关于如何扩展spring-jcl,还不知道(可以是通过spi发现,传统jcl可能是通过实现LogFactory类发现)

导入依赖

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.3.5</version>
</dependency>
(2)、SLF4J

导入依赖

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

SLF4J是目前最流行的日志门面,使用时只需要通过LoggerFactory.getLogger()来获取Logger对象,如下示例所示:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main
{
    public static void main(String[] args)
    {
        Logger logger = LoggerFactory.getLogger(Main.class);
        logger.error("Hello World");
    }
}

一般而言,会把Logger对象设置为private static final类型


为了使SLF4J与多个不同的日志系统结合工作,所以存在适配器桥接器两个工具

适配器

由于SLF4J只是一个日志门面,需要依赖一个具体的日志实现,且这个日志实现必须实现SLF4J的接口,但由于已经存在很多已经存在的日志框架

为了使其也能被SLF4J日志门面发现,需要一个适配器,使SLF4J可以作为他们的日志门面,官方示例图如下所示:
在这里插入图片描述正如上图所示,要想使用Log4j、JUL需要添加适配器,依赖如下所示

  • Log4j1(slf4j-log4j12)

    <dependency> 
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>2.0.17</version>
    </dependency>
    
  • 由于存在版本漏洞问题,为了修复,上面依赖再构建依赖时会重定向到reload4j,依赖如下所示

    <dependency> 
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-reload4j</artifactId>
        <version>2.0.17</version>
    </dependency>
    

    上面两个依赖的效果相同

  • Log4j2(log4j-slf4j-impl)

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.24.3</version>
    </dependency>
    

    注意log4j1log4j2所需要的依赖不同

  • JUL(slf4j-jdk14)

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

上面这些依赖都是需要进行适配的日志框架所需要添加的依赖

而对于那些日志框架本身就实现了SLF4J的日志框架,则不需要添加对应的适配器,比如logback、simple、no-operation


桥接器

对于那些没有使用SLF4J日志门面获取使用了其他的日志门面(JCL)的项目,要想在再不需要代码的情况下使用SLF4J日志门面,就需要桥接器,官网图在这里插入图片描述如图所示,它可以对JCL、Log4j、JUL进行桥接,对应的需要添加以下依赖:

  • Log4j1(log4j-over-slf4j)

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>log4j-over-slf4j</artifactId>
        <version>2.0.17</version>
    </dependency>
    
  • Log4j2(log4j-to-slf4j)

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-to-slf4j</artifactId>
        <version>2.21.1</version>
    </dependency>
    
  • JUL(jul-to-slf4j)

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jul-to-slf4j</artifactId>
        <version>2.0.13</version>
    </dependency>
    
  • JCL(jcl-over-slf4j)

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>2.0.17</version>
    </dependency>
    

对于SLF4J而言,有两个大版本,且共工作方式完全不同,使用时使用注意版本日志实现或者适配器的关系

对于1.x而言,对应的日志实现需要提供org.slf4j.impl.StaticLoggerBinder.class类文件,如果存在多个,则会显示警告(打印所有实现)并使用第一个日志实现

对于2.x而言,使用的时JDKSPI机制,需要提供META-INF/services/org.slf4j.spi.SLF4JServiceProvider文件,该文件的内容只想一个日志实现,如果存在多个同样会显示警告并打印所有实现,同时只使用第一个实现

上面的都是日志门面的使用,下面的都是日志实现框架的使用


(1)、LOG4J

LOG4J有两个版本,1.x版本已停止维护,现在基本都是使用的2.x版本,且性能非常的高

日志的隔离级别

trace > debug > info > warn > error > fatal,默认日志隔离级别为error

1.x版本的简单使用

  1. 导入依赖

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    
  2. 使用

    import org.apache.log4j.Logger;
    
    public class Main
    {
        public static void main(String[] args)
        {
            Logger logger = Logger.getLogger(Main.class);
            logger.error("Hello World");
        }
    }
    

    使用Logger.getLogger()获取日志对象

  3. 添加配置文件

    1.x版本的Logger使用要求类路径下必须存在log4j.xml配置文件,否则将无法工作,例如上面的代码控制台会出现报错(配置文件这个就不写了)

2.x版本的使用发生了很大的变化

  1. 导入依赖

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

    上面导入的依赖表示2.x版本的LOG4J由两部分组成,一个是具体的实现log4j-core,另一个时日志门面log4j-api

    没错,在2.x版本里也有个LOG4J实现的日志门面log4j-api,只不过使用的不多,且它最出名的是日志实现log4j-core,log4j-core依赖包含log4j-api,所以只导入log4j-core同样是可以的

  2. 使用

    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    public class Main
    {
        public static void main(String[] args)
        {
            Logger logger = LogManager.getLogger(Main.class);
            logger.error("Hello World");
        }
    }
    

    使用LogManager.getLogger()获取日志对象,默认的日志级别为error

  3. 添加配置文件

    2.x版本里,不需要配置文件也可以正常工作,当然一般都会添加配置文件来完成个性化定义,配置文件位于根类类路径下,也就是resources目录下

    文件名为log4j2.xml2.x版本也支持其他格式的配置文件(json、properties等)

    这些配置也可以使用编程方式配置,重要的对象由LoggerContent、LoggerManager、LoggerContentFactory、LoggerConfiguration等

(2)、JUL

JUL(java util logging),是Java自带的日志实现,位于java.util包下,因此不需要导入其他的依赖

日志隔离级别

finest > finer > fine > config > info > warning > severe,默认的日志级别为info

  1. 使用

    import java.util.logging.Logger;
    
    public class Main
    {
        public static void main(String[] args)
        {
            Logger logger = Logger.getLogger(Main.class.getName());
            logger.info("Hello World");
        }
    }
    
  2. 添加配置文件

    由于是Java平台自带的日志实现,所以存在默认的配置文件,位于JAVA_HONE目录下的conf文件夹下(java8位于jre内),配置文件名为logging.properties

    当然这是默认的配置文件,也可以在类路径下添加logging.properties文件来覆盖默认的配置

    当然,一切也是可以使用编程方式配置的

(3)、LOGBACK

LOGBACKLog4j1之后出来的,且和SLF4J一同推出,所以它本身就符合slf4j-api的规范

LOGBACK由两部分组成,logback-classic 和 logback-core两部分,logback-classic包含logback-coreslf4j-api

所以使用LOGBACK就是直接使用SLF4Japi相关的操作

日志隔离级别(同时也是SLF4JLogger接口的隔离级别,门面日志只能给出有哪些隔离级别,但不能设置,具体的级别由日志实现决定)

trace > debug > info > warn > error,默认的日志隔离级别为debug

  1. 使用

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class Main
    {
        public static void main(String[] args)
        {
            Logger logger = LoggerFactory.getLogger(Main.class);
            logger.trace("Hello World");
            logger.debug("Hello World");
            logger.info("Hello World");
            logger.warn("Hello World");
            logger.error("Hello World");
        }
    }
    
  2. 添加配置文件

    LOGBACK不需要配置文件也可以正常工作,也可以通过在类路径下(resources)添加logback.xml文件来自定义配置

    最后,它也是可以通过编程方式配置的

三、简单的工作流程和原理

不论是LOG4J还是LOGBACKJUL,其内部都维持这一个配置对象,这个配置对象可以是通过编程方式配置的,也可以是通过解析配置文件而获得过的

对于LOG4JLOGBACK(高版本中),都使用了服务发现机制,为了解决在存在多个可用日志系统时指定所使用的系统,都可以通过配置文件指定需要使用的日志实现

如果不存在指定的日志实现(或者没有提供),则会使用默认的配置,一般都是寻找某个服务类或者实现特定接口或抽象类的类,并从中选择一个使用,应该是选择第一个找到的实现,所以classpath中依赖的顺序很重要

对于如何管理日志器,一般会存在一个LoggerContext对象,表示一个日志系统上下文,其中包含日志器的配置、Appender、Filter、Formatter、Level等,一般来说一个系统只有一个LoggerContext,但对于特殊的应用环境也可以存在多个,同时也会有一个LoggerContextFactory表示LoggerContext的工厂,等对象

关于配置文件,一般日志框架都会须在classpath路径下指定名字的文件,且这个文件应该为classpath的根路径下,由于其他jar也可能存在同名的文件,所以自己系统的classes文件夹一定要classpath中的第一个(一般来说找到第一个匹配的文件就会立即返回)

四、版本注意事项

1、log4j-slf4j-impl内部slf4j版本注意

由于SLF4J1.x2.x版本的工作方式完全不相同,也不兼容,所以需要特别注意日志实现或者适配器使用的是哪个版本的SLF4J

log4j-slf4j-impl适配器依赖内,包含log4j-core依赖和slf4j-api依赖,这里的slf4j-api依赖是1.x版本的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值