日志框架的使用

文章讲述了日志框架在开发中的重要性,以及开发者张三如何从System.out.println()过渡到自定义日志框架,最终发展出log4j、logback和slf4j等解决方案。slf4j作为一个规范,允许灵活选择不同的实现,如logback。文章还介绍了日志框架之间的关系,以及如何通过配置将不同框架整合到slf4j,并提供了logback的使用示例,包括导入依赖和配置文件设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

日志框架的使用

1、讲一个故事

​ 张三在一个公司做开发、开发的时候 为了在一些关键信息的上需要打印关键信息(这个信息主要使用用于判断系统在运行的时候的一些状态) 于是张三这个家伙编写了无数个System.out.println()这个语句

​ 等到项目上线前夕、项目经理觉得 打印的数据太多影响效率 于是让张三将所有的打印信息全部删除或者 注释-------于是张三埋头苦干了两天 终于将所有的 System.out.println语句全部删除完成

​ 等到刚删除完成不久 项目经理觉得 这些信息还是挺有用的 、可以有效的 知道这个系统运行的状况 于是就给张三说 这些信息经过反复的考虑还是挺有用的 你还是把它加上吧

​ 张三是一个勤劳的程序员 听到项目经理有需求、张三就在想一个问题、能不能写个框架来解决这个问题、既能打印我们的系统运行信息、又能将这些不需要打印的信息给屏蔽掉、于是张三就开始来写这个代码了-----开发了大约10天左右-------这个框架就开发出来了

​ xxxx.jar(log4j)实现--------------------主要就是打印当前的这个系统的运行信息的 还能屏蔽不需要打印的这些信息

​ 于是这个张三就苦思冥想这个框架存在的问题在哪里呢? 于是张三就想到了这个鬼 不能完成异步打印 会阻塞主程序 打印的信息 在一个文件里头 会导致这个文件过大 不利用查看 需要将这些日志进行归档…

​ xxxx-good.jar

​ 终于张三这个鬼开发的这个程序能满足当前项目的这个需求了

​ 在这个时候 张三需要调换项目组-------开发一个新的项目--------张三就发现了一个问题-----这个系统同样的需要上一个系统中开发的xxxx-good.jar这个程序进行系统的运行状态的记录

​ 于是张三就在想 能不能像 sun公司一样装逼 整个规范呢? 这个规范就是咋们上面开发的记录运行系统的这个系统规范 xxxxx(接口)(slf4j)规范

​ 张三又想规范有了 总的有个实现、实现怎么办呢?

​ 于是张三就针对这个规范开发了一个新的框架、来满足打印这个系统的运行信息

​ xxxx-best.jar(logback)实现

2、市场上的日志框架有哪些

log4j log4j2 logback JCL JUL JBoos-Logging slf4j

log4j logback slf4j 一个人开发的

slf4j :simple logging facade for java

JBoss-Logging 这个是定制开发的

JCL :Jakatra commons logging 这个应该是 Spring框架内部使用的日志框架

JUL :java util logging

上面这些框架中 有些 是接口(规范) 有些是实现

3、市场上日志框架的关系

日志规范

JCL JBoss-Logging slf4j

日志实现

log4j log4j2 logback JUL

我们在做开发的时候 一般情况下 都是选择一个规范 一个实现

slf4j -------------------- logback

3.1、slf4j整合其他的第三方日志框架

在这里插入图片描述

理解图

在这里插入图片描述

3.2、将其他的框架整合成符合slf4j规范的日志框架
3.2.1、将其他日志框架转换成logback实现的日志框架

在这里插入图片描述

JCL和SLF4J都是规范(简称接口),logback是slf4j的默认实现框架。但是JCL是Apache的规范框架。因为日志开发者log4j(作者),觉得Apache那种面向接口开发的日志框架真香,在真香定律的加持下。这个作者写了slf4j。如果项目中有jcl日志的话需要整么解决呢?

这时候就可以写一个中间包.jar。去继承jcl包的接口,在中间包里面重写里面的方法(这里就得说哈,子父类有相同的非静态函数的方法时,有限执行子类里面的方法)。然后在这些方法中调用slf4j中的方法。最后让logback来实现。
3.2.2、将其他日志框架转换成log4j实现的日志框架

在这里插入图片描述

因为这个作者写框架的时候,是写的log4j,然后slf4j,最后logback。所以log4j没有实现slf4j。logback才是slf4j的默认实现。因此需要一个中间代理层,去实现slf4j里面的方法。然后在中间代理层与log4j相对应的方法中调用log4j中的日志方法。

3.2.3、参考图

在这里插入图片描述

4、Logback的使用

4.1、导包
 <!--这个包是为了 把JCL的日志转换成复合SLF4j标准的日志进行输出
            SLF4j的实现    logback
        -->
       <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.7</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>${logback.version}</version>
        </dependency>

        <!--这个是SLF4j的这个接口的规范-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>

        <!--Spring对logback的支持包-->
        <dependency>
            <groupId>org.logback-extensions</groupId>
            <artifactId>logback-ext-spring</artifactId>
            <version>0.1.4</version>
        </dependency>
        <!-- logback end -->
4.2、编写配置文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true"><!-- debug="true"设置调试模式 -->
    <!--
        <configuration scan="true" scanPeriod="60 seconds" dubug="false">
        scan这个属性如果设置为true的话  配置文件如果是发生改变那么就会自动进行 重新加载
        scanPeriod这个属性检测当前的这个文件修改的时间间隔 如果你没有给定时间单位的话那么默认单位是毫秒。只有scan设置为true的时候这个才生效
        debug这个属性设置为true的时候 就要日志自己的内部信息、可以时时查看logback的运行状态
    -->
    <!--
       appender:表示的是定义了一种日志的输出
       这里就类似于  变量
       变量要先定义  后使用
       这里 就相当于定义了日志的输出   这个日志到底输出在哪里  由这个class类类决定
       ConsoleAppender:的意思就是日志要输出到控制台
       name:这个名字是可以随便定义的  你高兴就好 但是一般情况下  见名之意
    -->
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--表示的是输出日志的格式
                 %d{yyyy-MM-dd-HH:mm:ss.SSS}:时间引用
                 %level:日志的级别    trace  <  debug < info < warn < error
                 [%thread]:线程名字
                 %class:当前打印日志的类名
                 %line:打印日志的代码的行号(一般不要)
                 %msg:日志本身的信息
                 %n:换行
            -->
            <!--
                pattern:这个表示的是定义的是日志的输出格式
            -->
            <pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS}======>%level======>[%thread]-%class:%line-------->>%msg%n</pattern>
        </encoder>
    </appender>

    <!--
        这个就表示的是要把 日志输出到文件(FileAppender)
        FileAppender:这个表示的是将日志输出到文件
        name:可以随便写
    -->
    <appender name="file" class="ch.qos.logback.core.FileAppender">
        <!--
            catalina.home:这个实际上是引用  这个地址实际上是引用的是 Tomcat的环境变量
            ${catalina.home} :实际上定位的是 Tomcat的根目录
            ${catalina.home}/logs/file.log:下面这段地址的意思是:日志打印到了Tomcat根目录下的 logs目录下
            名字 叫做 file.log
        -->
        <file>${catalina.home}/logs/file.log</file>
        <!--这个表示的是 下一次的日志是在上一次的基础上 进行追加  不是覆盖-->
        <append>true</append>
        <encoder>
            <pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level	[%thread]-%class:%line>>%msg%n</pattern>
            <!--这个意思是:设置编码-->
            <charset>UTF-8</charset>
        </encoder>
        <!--
            prudent=true:表示的是日志的写入是线程安全的、但是线程安全会降低效率  一般默认设置为false
        -->
        <prudent>false</prudent>
    </appender>
    <!--
       RollingFileAppender:表示的是 日志文件滚动输出 并且最大保留30天
       滚动输出到日志  当达到一定条件的时候 就将日志记录到其他文件中去
    -->
    <appender name="timeFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--
            rollingPolicy滚动的策略
            TimeBasedRollingPolicy:最常用的一个、根据时间进行滚动 当达到一定的时间的时候、就会自动开辟一个新的日志文件
            FixedWindowRollingPolicy:根据固定窗口的算法重命名文件的滚动策略
            TriggeringPolicy:根据当前活动文件的大小来来确定是否滚动
        -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--表达式中最小的滚动单位是天、所以每天生成一个日志、日志的名字就是下面这个名字-->
            <!--
                  log/xxxx/xxxx.log
                  如果直接写的文件的名字 这个路径默认是定位到  tomcat/bin/
                  Tomcat/bin/logfile2020-7-8.log
            -->
            <fileNamePattern>log/logFile%d{yyyy-MM-dd}.log</fileNamePattern>
            <!--表示的是生成的日志 保留30天 30天以后自动销毁-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level	[%thread]-%class:%line>>%msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--
        日志的滚动的输出
        这个Appender的主要作用就是在生成日志的时候 如果单个的日志文件 达到了5M 那么这个时候就会创建新的日志进行继续生成
    -->
    <appender name="fixedFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--
             Tomcat/bin/log/fixedFile.log  :文件是放到这个路径下的
        -->
        <file>log/fixedFile.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <!--生成日志文件的文件名的格式-->
            <fileNamePattern>log/fixedFile%i.log.zip</fileNamePattern>
            <!--至少生成一个日志文件-->
            <minIndex>1</minIndex>
            <!--最大只是生成三个日志文件  如果我们的内容超过了15M  那么就会实现覆盖前面的这个日志文件-->
            <maxIndex>3</maxIndex>
        </rollingPolicy>

        <!--表示的是添加了触发策略-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <!--单个文件的最大的值  是5M-->
            <maxFileSize>5MB</maxFileSize>
        </triggeringPolicy>
        <!--生成日志的格式和编码-->
        <encoder>
            <pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level	[%thread]-%class:%line>>%msg%n
            </pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--
        这个表示的是定义了一种日志输出格式  并和过滤器进行整合
    -->
    <appender name="filter" class="ch.qos.logback.core.FileAppender">
        <file>log/filter.log</file>
        <append>true</append>
        <!--
            LevelFilter:的意思是添加了一个日志级别的过滤器
            如果日志的级别等于配置的级别。那么则执行onMatch里面的配置
            否则执行 onMismatch中的内容
        -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <!--
                 ACCEPT:当前的日志会立即被执行不经过其他的过滤器了
                 DENY:日志立即被抛弃、也不再经过其他的过滤器了
                 NEUTRAL:下一个过滤器将继续执行、如果是最后一个过滤器的话那么就会被执行
            -->
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--临界值过滤器:如果你输出的日志级别 是低于下面定义的这个级别的话那么 降火被过滤掉-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>

        <encoder>

            <pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level	[%thread]-%class:%line>>%msg%n
            </pattern>
            <charset>UTF-8</charset>
        </encoder>
        <prudent>false</prudent>
    </appender>

    <!--
        logger:定义的是输出的对象
        name:一般写 包名  level:就是咋们的日志的级别
        addtivity:true、日志将会继续的向他爹进行传递

        表示的是给整个项目的某一个包 单独定义日志的输出
        比如:
            我要给 com.qf.springboot.controller 这个包 定义输出级别是 info  低于info的都不输出
            并且我还要定义这些日志输出到哪些地方
            file :就表示的是输出到文件
            stdout:这个就表示的是还要输出到控制台
         局部的
    -->
 <!--   <logger name="com.qf.meeting.controller" level="error" addtivity="false">
        <appender-ref ref="file" />
    </logger>-->


    <!--全局设置了一个日志级别  如果只是在这里引用的话 其余的是不生效的 -->
    <!--简单的说  就是全局所有的日志都要打印到控制台-->
    <!--
        给整个项目设置一个全局的日志的打印
        在整个项目中  日志级别都是 info 意思是如果低于这个级别那么这个日志就将不打印
        全局的

        trace  <   debug   <  info   <  warn  <   error
    -->
    <root level="debug">
        <appender-ref ref="file"></appender-ref>
        <appender-ref ref="stdout" />
        <appender-ref ref="timeFile" />
        <appender-ref ref="fixedFile" />
        <appender-ref ref="filter" />
    </root>
</configuration>
4.3、使用日志框架
 private Logger logger= LoggerFactory.getLogger(UserController.class);
logger.trace("我好的");
logger.debug("我好的");
logger.info("我好的");
logger.warn("我好的");
logger.error("我好的");

spirng-boot日志相关配置

编写 logback-spring.xml配置文件
<configuration>
    <!-- 引用 Spring Boot 的 logback 基础配置 -->
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <!-- 变量 yudao.info.base-package,基础业务包 -->
<!--    <springProperty scope="context" name="yudao.info.base-package" source="yudao.info.base-package"/>-->
    <!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
    <property name="PATTERN_DEFAULT"
              value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread ) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>

    <!-- 控制台 Appender -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">     
        <encoder>
            <pattern>${PATTERN_DEFAULT}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 文件 Appender -->
    <!-- 参考 Spring Boot 的 file-appender.xml 编写 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>${PATTERN_DEFAULT}</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志文件名 -->
        <file>${LOG_FILE}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 滚动后的日志文件名 -->
            <fileNamePattern>${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
            </fileNamePattern>
            <!-- 启动服务时,是否清理历史日志,一般不建议清理 -->
            <cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>
            <!-- 日志文件,到达多少容量,进行滚动 -->
            <maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize>
            <!-- 日志文件的总大小,0 表示不限制 -->
            <totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap>
            <!-- 日志文件的保留天数 -->
            <maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30}</maxHistory>
        </rollingPolicy>
    </appender>
    <!-- 异步写入日志,提升性能 -->
    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志。默认的,如果队列的 80% 已满,则会丢弃 TRACT、DEBUG、INFO 级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能。默认值为 256 -->
        <queueSize>256</queueSize>
        <appender-ref ref="FILE"/>
    </appender>

    <!-- 本地环境 -->
    <springProfile name="local">
        <root level="INFO">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="FILE"/>
        </root>
    </springProfile>
    <!-- 其它环境 -->
    <springProfile name="dev,test,stage,prod,default">
        <root level="INFO">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="FILE"/>
<!--            <appender-ref ref="ASYNC"/>-->
        </root>
    </springProfile>

</configuration>
LOG_FILE

是在yml中配置的


# yml 日志配置级别优先 logback-spring.xml配置文件
logging:
  file:
    name: logs/${spring.application.name}.log # 日志文件名,全路径
  level:
    com.github.pagehelper: DEBUG
#    org.mybatis: DEBUG
#    org.mybatis.spring.SqlSessionUtils: DEBUG
#    java.sql: DEBUG
#    org.apache.ibatis: DEBUG
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

单线程bug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值