日志门面和日志框架介绍

原文链接:日志门面和日志框架介绍 – 编程屋

目录

1 前言

2 日志框架和日志门面

2.1 日志框架:

2.2 日志门面: 

3 springBoot中日志使用

 3.1 springBoot中的日志设计

 3.2 springBoot中的日志使用

 4 日志桥接


1 前言

        相信大家在平时的开发中都会经常会通过打日志的方式来排查和解决问题。用到的最多的形式也无外乎log.info("某某日志为:",{})。那么大家有没有设想一下市面上有那么多的日志框架,但为什么公司用的几乎是同一种呢?这是我们公司中以slf4j作为日志门面对项目中的所有应用做了统一管理。

        相信大多数同学都看过《阿里巴巴开发手册》中,有这样一条强制规范:应用中不可直接使用日志系统(Log4j、Logback)中的API,而应依赖使用日志框架中SLF4J中的API,使用门面模式的日志框架,有利于维护各个类的日志处理方式统一。

        这是因为在我们不同的应用上可能会应用了不同的日志框架,每一套日志框架都对应一套属于自己的API,这样应用和框架的耦合性大大提高,不好管理。所以就提出了日志门面(也是门面模式)对各个应用的日志框架做了统一的桥梁。我们只需对这个桥梁进行修改即可。

2 日志框架和日志门面

2.1 日志框架:

JUL、log4j、log4j2、logback。

JUL: JUL全称java util  Logging是Java原生的日志框架,使用时不需要引用三方类库,相对其他日志框架使用方便。其有7个日志级别:SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST。   

Log4J:    log4j是apache的一个开源项目,通过在项目中使用log4j,我们可以控制日志信息输出到控制台,文件、GUI组件,甚至是数据库中。参考博客:Log4j学习_set sail_2021的博客-CSDN博客

        log4j主要由Loggers(日志记录器)Appenders(输出端)Layout(日志格式化器组成)。其中Loggers控制日志的输出级别和日志是否输出;Appenders指定日志的输出方式(输出到控制台,文件);Layout控制日志的输出格式。

        Log4J 在 org.apache.log4j.Level 类中定义了OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL七种日志级别:

log4j2: Apache Log4j2是对log4j的升级版本,它参考了logback的设计并且修复了logback中的一些问题(参考博客:https://blog.csdn.net/qq_50652600/article/details/122507140)例如:

异常处理:在logback中,Appener的异常不会被应用感知到,但是在log4j2中,提供了一些异常处理机制

性能提升:log4j2相较于log4j和logback都有明显的性能提升

自动重载配置,参考了logback的设计,提供自动刷新参数设置,最实用的就是我们在生产上可以动态的修改日志级别而不需要重启应用。

无垃圾机制:log4j2在大部分情况下,都可以使用其设计的一套无垃圾的机制(对象重用,内存缓冲),避免频繁的日志收集导致的jvm gc。

 logback:logback是我们springBoot默认的日志处理框架,同时它和log4j都是出自同一作者之手。

        logback由三个模块组成:

        logback-core:Logback核心包,开发人员可以以此为基础搭建自身模块

        logback-classic: Logback对于Slf4j的实现

        logback-access:与Servlet容器的集成,实现Http访问日志的功能

2.2 日志门面: 

slf4j:slf4j(全称是Simple Loging Facade For Java)是一个为Java程序提供日志输出的统一接口,并不是一个具体的日志实现方案。就好像我们经常使用JDBC连接关系型数据库一样。所以单独是slf4j是不能工作的,它必须与我们的日志框架搭配起来使用。而且slf4j是门面模式(外观模式)的典型应用。

Commons-Logging:Commons-Logging和slf4j都是日志的接口,供用户使用,但是都不提供实现(让一些日志框架提供具体的实现)。commons-logging是apache提供的一个通用的日志接口,功能和slf4j类似,都是提供日志门面的。

注意:启用slf4j库意味着添加一个强制的依赖,级slf4j-api.jar。如果在类路径上找不到绑定/提供程序,那么slf4j将默认为无操作实现

那么很多人都想问为什么有了日志框架之后我们直接用不就好了,为什么还要弄一个日志门面呢?

这其中做重要的一点就是解耦合,slf4j和Commons-Logging都是提供日志门面的,用户可以选择第三方的日志组件来作为具体实现。提供日志的接口和获取具体日志对象的方法。这样就避免了我们的应用和日志方案的直接耦合,如果需要有改动日志方案时,我们可以直接修改日志实现。因为日志门面一般都兼容大多数的日志框架。

3 springBoot中日志使用

 3.1 springBoot中的日志设计

        springBoot日志是系统中常用的日志系统,springboot默认就是使用SLF4J作为日志门面,logback作为日志实现来记录日志。

我们可以用idea创建一个springBoot工程(导入web依赖),然后分析其依赖关系。(下图只截取了依赖关系的一小部分)

 由以上关系图可知,spring-boot-starter启动器依赖着spring-boot-starter-loggering日志启动器,并且又依赖了像log4j-api和slf4j-api作为日志的门面。里面包含了许多桥接器(log4j-to-slf4j和jul-to-sllf4j)都是slf4j作为其日志的门面。所以springBoot框架,默认的日志门面就是slf4j。那么slf4j只是一个日志门面,日志实现是什么?就是我们的logback-classic其又依赖了logback-core。

总结:

1. springboot底层默认使用logback作为日志实现

2. 使用slf4j作为日志门面

3. 将JUL也转换成slf4j

4.也可以使用log4j2作为日志门面,但是最终也是通过slf4j调用logback。

 3.2 springBoot中的日志使用

刚刚说到,springboot中默认是使用slf4j作为日志门面,logback作为日志实现来进行日志输出的。如果有其他的日志实现,那么它也会通过底层的桥接器来来转换成系统默认的配置。

我们可以测试下我们上面所说的是否成立,如果我在测试类中分别用slf4j和loglog4j2作为日志门面来输出日志,如果日志输出格式一样,那么就可以证明,桥接器是转换成功了的。

测试类:

@SpringBootTest
class SpringbootLogApplicationTests {

    public static final Logger LOGGER  = LoggerFactory.getLogger(SpringbootLogApplicationTests.class);

    @Test
    void contextLoads() {
        LOGGER.error("error");
        LOGGER.warn("warn");
        LOGGER.info("info");
        LOGGER.debug("debug");
        LOGGER.trace("trace");

        //使用log4j2使用桥接器切换为slf4j日志门面和logback的日志实现
        org.apache.logging.log4j.Logger logger = LogManager.getLogger(String.valueOf(SpringbootLogApplicationTests.class));
        logger.info("log4j2");
    }

}

测试结果:

以上4条消息格式是一样的,那么久说明springboot中底层桥接器的转换是没有问题的。

指定配置文件位置 

在springboot中,如果给类路径上放上自己的配置文件,那么springboor就不会使用默认配置了。

 使用springboot解析日志配置

由上个框图可知,配置文件即可以叫logback-spring.xml,也可以叫logback.xml,那么这二者之间有什么区别呢?

如果使用logback.xml能够直接被日志框架所识别,如果叫做logback-spring.xml能够spring框架识别并解析,例如:

在resources配置logback-spring.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <!--配置集中管理属性 我们可以直接更改属性value的值 格式: ${name}-->
    <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] ----- %m%n"/>


    <appender name="console" class = "ch.qos.logback.core.ConsoleAppender">
        <!--控制输出流对象 默认System.out改为System.err-->
        <target>System.err</target>
        <!--引用上面的属性 用${name}-->
        <encoder class = "ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <springProfile name = "dev">
            <pattern>${pattern}</pattern>
            </springProfile>

            <springProfile name = "pro">
                <pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] xxxxx %m%n</pattern>
            </springProfile>
        </encoder>
    </appender>

    <!-- 自定义logger对象 additivity = "false" 自定义logger对象是否继承rootLogger-->
    <logger name = "com.liubujun" level = "info" additivity = "false">
        <appender-ref ref = "console"/>
    </logger>
</configuration>

在application.properties配置文件中配置:

#指定自定义logger对象日志级别
logging.level.com.liubujun = trace
#指定控制台输出消息格式
logging.pattern.console=[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c [%thread] ====== %msg %n

#指定项目使用的具体环境
spring.profiles.active=pro

测试结果:

我们可以通过在 properties文件中配置spring.profiles.active=pro或者=pre(指定项目使用的具体环境)就来控制日志消息用什么来进行输出。

 4 日志桥接

桥接器的命名规范是:实现类-over/to-门面(log4j-over-slf4j.jar)

桥接器实现原理(log4j-over-slf4j.jar): 桥接器重写了log4j,类名功能都一样,但是实现了slf4j接口。引入桥接器,排除实现,完美替代了log4j类。

桥接解决的是日志中的遗留问题,当系统中存在之前的日志API,可以通过桥接转换到slf4j的实现。

官方图片:

我们都知道springBoot中日志门面使用的是slf4j,日志实现使用是logback。这些都是springBoot的默认配置。但是随着时代的发展,越来越多优秀的优秀的日志实现我们肯定是要被使用的,那么如何去使用它呢?我们以log4j2替代logback为例:

桥接步骤:

      

以上只是部分内容,为了维护方便,本文已迁移到新地址:日志门面和日志框架介绍 – 编程屋

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值