简单了解日志

日志简介

日志框架的来源

什么是日志

日志就是在系统的运行过程中,来记录一些数据信息。没有日志系统一样能够正常运行,但是没有日志的项目也不太完整,加入日志能够帮助我们去解决一些问题

例如:

  • 生产环境中当接口出现异常时,打印错误信息,这样子就方面我们去排查(问题定位)
  • 在开发的过程中可能也会打印看下某个变量的值方便我们调试(调试)
  • 记录某个功能的点击行为,进行数据分析(数据分析)

为什么要使用日志框架

在没有日志框架之前怎么打印日志信息?

  • 在需要打印日志的地方输入System.out.println("");,写完之后如果我们不想打印了,然后我们一行行的注释掉,当需要打印的时候然后一行行的把注释给取消掉,这对于控制日志的打印非常的不方便
  • System.out.println("");打印日志信息是阻塞式的,通过System调用out,out表示一个静态常量的打印流,也就是在整个系统运行中只会存在一份,在println()方法中有使用synchronized,synchronized中锁的就是当前对象,这样子当很多线程同时访问时,得一个个等待,会降低系统的性能,可能还会以为一个小小的打印让整个系统宕机
public void println(String x) {
     synchronized (this) {
         print(x);
         newLine();
     }
 }

日志框架的好处

  • 日志框架中有一个日志级别,能够很好的控制的打印输出
  • 异步非阻塞式的
  • 可以根据我们的需要做一些更多功能的配置,例如:日志归档等
  • 可以将日志的信息输出到控制台,也可以输出到文件当中等,根据自己的需求选择

常用的日志框架与日志框架的选择

市面上常用的日志框架

JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j…

为什么会有日志抽象接口层

张三开发了一个日志框架,叫做Log4j,后面张三想做一些更高级功能的操作,又开发了一个日志框架logback,在我们的系统当中,如果之前使用的是Log4j,现在我们又想切换到logback,这样子做的话我们还需要去更改使用的api,因为这是两个不同的日志框架,没有一套统一的标准,那么api就会不一样。

这个时候日志门面(日志抽象层就出现了),我定义一个日志抽象层,所有的日志实现都统一遵循这个标准。这样子就不会有上面说的问题了

在实际使用的过程中,我们会选择一个日志门面(调用抽象层的接口),然后再选择一个具体的实现框架一起结合使用(具体的操作由加入的日志实现框架去做),这样我们想更改日志框架,原有的api就不需要更改了。改具体的实现就行了

日志门面对应关系

日志门面(抽象)日志实现
slf4jlog4j、logback

补充:

  • 在springboot中默认推荐使用的是SpringBoot选用 SLF4j和logback
  • Spring框架底层是JCL

日志使用

开发的时候,日志记录方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象层里面的方法;

SLF4j的使用

官网:https://www.slf4j.org

依赖使用介绍

想要很好的使用好slf4j这个日志框架,那么就需要先对它里面的依赖关系理解清楚。
在这里插入图片描述

解析:

  • 编号1,表示系统中只加入了SLF4J的抽象层,没有加入具体的实现日志框架
  • 编号2,表示系统中加入了SLF4J的抽象层以及logback实现层日志框架
  • 编号3,表示系统中加入了SLF4J的抽象层以及log4j实现层日志框架,但是这里有点特殊的是,在SLF4J的抽象层出来之前,log4j就已经出来了,原因有的log4j日志框架中的api可能与新定义的规范接口抽象层的api不一样,但是为了方面用户使用,统一定义好一个规范,于是就有了一个适配层,适配层实现自SLF4J的抽象层,而具体的实现层调用的又是log4j
  • 编号4、编号5与编号2层是一样的意思
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

每一个日志的实现框架都有自己的配置文件。使用slf4j以后,配置文件还是做成日志实现框架自己本身的配置文件;(我们调用的肯定是SLF4J抽象层的api,底层调用的还是具体的实现,所以对于配置日志输出,直接找实现层对应的配置文件)

遗留问题

a(slf4j+logback): Spring(commons-logging)、Hibernate(jboss-logging)、MyBatis、xxxx

什么意思呢?

项目中我们要使用的日志搭配为slf4j+logback,项目中呢可能继承了一些其它的框架,例如:Spring(commons-logging)、Hibernate(jboss-logging)、MyBatis、等等。如:spring中默认使用的是commons-logging日志(自带),这个时候项目中就有两个日志实现框架了,在使用的过程中我们不可能为logback的编写一个配置xml,然后又为commons-logging编写一份配置吧。

如何解决呢?
统一日志记录,即使是别的框架和我一起统一使用slf4j进行输出

在这里插入图片描述

如何让系统中所有的日志都统一到slf4j

1、将系统中其他日志框架先排除出去;

2、用中间包来替换原有的日志框架;

3、我们导入slf4j其他的实现

SpringBoot中日志的使用

SpringBoot内置的有Logback的依赖

直接在属性文件中进行配置

# logback的配置
logging.file=d:/log.log
logging.level.org.springframework.web=DEBUG

单独提供一个logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <property name="log.context.name" value="gupao"/>
    <property name="log.charset" value="UTF-8"/>
    <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS}[%p][%c][%M][%L] %msg%n "/>

    <contextName>${log.context.name}</contextName>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder charset="${log.charset}">
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>./log/${log.context.name}%d{yyyyMMdd}.log</fileNamePattern>
            <maxHistory>5</maxHistory>
        </rollingPolicy>

        <encoder charset="${log.charset}">
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>


    <logger name="org.apache" level="ERROR" />
    <logger name="org.apache.kafka" level="INFO" />
    <logger name="org.springframework" level="ERROR" />
    <logger name="org.springframework.data.elasticsearch.client.WIRE" level="trace"/>
    <logger name="org.elasticsearch.client" level="ERROR"/>


    <root>
        <level value="debug"/>
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILE"/>
    </root>

</configuration>

日志级别分类

共有8个级别,按照从低到⾼为:ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF。

  • All:最低等级的,⽤于打开所有⽇志记录.
  • Trace:是追踪,就是程序推进⼀下.
  • Debug:指出细粒度信息事件对调试应⽤程序是⾮常有帮助的.
    • 应用场景
      • 在代码调试的过程中打印自己的参数变量信息等
  • Info:消息在粗粒度级别上突出强调应⽤程序的运⾏过程.
    • 应用场景:
      • 打印业务代码中的关键数据,方便调试
  • Warn:输出警告及warn以下级别的⽇志.
  • Error:输出错误信息⽇志.
  • Fatal:输出每个严重的错误事件将会导致应⽤程序的退出的⽇志.
  • OFF:最⾼等级的,⽤于关闭所有⽇志记录.

程序会打印⾼于或等于所设置级别的⽇志,设置的⽇志等级越⾼,打印出来的⽇志就越少。

疑问补充

阻塞式和非阻塞式的区别

如果服务端接受到io请求后,使用传统的BIO进行处理,则是阻塞的,如果使用异步IO处理,则是非阻塞的。

异步和同步的区别

同步

同步的执行流程:
在这里插入图片描述
简单说明:

用户(线程)发起一个请求调用某个程序,这个程序需要执行3s时间,在程序没有执行完成之前,这个线程就一直处于等待状态,等程序执行完之后给用户响应,也只有等调用的程序响应了,这个用户(线程)才能够去做别的事情。

异步
在这里插入图片描述

简单说明:

用户(线程)发起一个请求调用某个程序,这个程序需要执行3s时间,不管程序有没有执行完成,用户(线程)不同等待程序响应,这个用户(线程)依然可以去做别的事情,等程序执行完成,会通知用户(线程),异步节约了时间,提高了效率。

总结

同步和异步都有其优缺点,都一起适合的场景,根据业务而定,是否使用同步和异步看需要的请求的数据是否是程序继续执行必须依赖的数据

结合案例理解

需求:两个Ajax请求,后一个Ajax需要依赖于前一个Ajax的请求结果。
在这里插入图片描述

  • 同步请求
    在Ajax2发出请求前,需要先等Ajax1的请求结果有响应,然后拿到Ajax1的响应结果作为Ajax1的请求参数,发出Ajax2的请求
  • 异步请求
    Ajax2的请求不等Ajax1响应直接发出请求,那根据我们现有的业务需求,使用异步请求是实现有问题的

异步和同步与阻塞式和非阻塞式的区别

程序中的应用

  • 同步和异步在之前使用Ajax的时候有理解过
  • 而阻塞与非阻塞自己在之前的网络IO中有体会过

两者的区别与理解

  • 这是两个不同的概念,没有可比性,异步可以阻塞,也可以不阻塞;搞明白两个概念就好了; 举个例子,就好比小明去菜市场买菜,先买鱼,再买青菜;那同步就是他买了鱼,必须等鱼老板处理好,把鱼交到小明手上,然后小明才能去买青菜;那异步就是小明先去买了鱼,但是此时鱼老板要处理很久,所以他不在这里一直等着,而是去买了青菜,再回来取鱼;那阻塞和非阻塞只是线程的一种状态,阻塞,就是小明在买鱼的时候,鱼老板没有给他,那这个时候他就进入阻塞队列等,非阻塞就不进入阻塞队列
  • 如果需要调用方主动获取结果的,不管是提交请求后阻塞在原地,或者提交请求后每隔一段时间轮询结果是否完成,属于同步。如果是通过第三方通知结果的,例如消息队列,通知、回调等主动推送结果,非自己主动获取结果的,则属于异步。而阻塞和非阻塞,这个比较好理解,就是业务是否是属于阻塞或者非阻塞执行。

涉及知识点

  • 并发编程
  • 网络IO
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值