zoukankan      html  css  js  c++  java
  • 后端——框架——日志框架——logback——《官网》阅读笔记——第二章节(核心模块,核心对象,核心流程)

    第二章节介绍了许多核心内容。在末尾提及了如何更高效的使用日志框架,提高性能。

    第二章节主要分为以下四个部分

    1. 日志框架的核心模块,logback-core,logback-access,logback-classic
    2. 日志框架的核心对象,Logger,Appender,Layout,LoggerContext
    3. 日志框架的核心流程。
    4. 性能问题。

    1、核心模块

    日志的核心模块有三个,logback-core,logback-access,logback-classic,之后忽略其前缀,例如logback-core简称为core。

    • core是classic模块和access模块的基石。Classic和access都依赖于core模块。
    • classic模块实现了slf4j API。它可以与其他实现slf4j API规范的日志进行切换。它返回的Logger对象全名为org.slf4j.Logger,其他日志框架返回的Logger也是该类型。
    • access模块集成Servlet容器,记录Http-access相关的日志,它会单独写个文档介绍。

    官网文档中的logback是指logback-classic模块。

    2、核心对象

      日志框架的核心对象有Logger,Appender,Layout,LoggerContext。在第二章中虽然都提及,但对Appender,Layout只做了简单介绍,却重点介绍了Logger对象。在第四章节中介绍Appender对象,第五章节,第六章节重点介绍Layout对象。

    2.1   LoggerContext

    LoggerContext是日志框架的上下文对象。

    它是日志框架的抽象,类似于applicationContext是IOC容器的抽象,ServletContext是项目的抽象。它与日志框架的生命周期相同,日志框架准备就绪的过程本质就是初始化context对象的过程。

    它提供了独立的上下文环境,例如我们打开浏览器,每一个tab页都有自己独立的运行环境,在其中创建了一些对象,运行一些脚本等等,所有的这些伴随着环境的消失,所有对象随之也被销毁。

    它是全局对象。

    当想深入了解日志框架的运行机制时,会用到该对象。它的获取方式是

    LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();

    打印它运行状态的方式是

    StatusPrinter.print(context);

    2.2   Logger

      原文中没有对Logger进行定义,但是它是日志框架的核心对象,所有对象都是围绕着它运作的。本章介绍了Logger对象的几个关键属性,name,level,appender。

    2.2.1  name

    name是Logger的名称,在创建Logger时,需要提供一个参数

    • 当参数为class时,该Logger的名称为Class对应的类全名。
    • 当参数为字符串时,字符串必须是包名或者是类名。当是包名时,name完全继承了包的层次结构。当是类名时,Logger的名称为类全名。

    当参数为包名时,涉及到name的层次结构,以下是name层次结构的原文:

      A logger is said to be an ancestor of another logger if its name followed by a dot is a prefix of the descendant logger nameA logger is said to be a parent of a child logger if there are no ancestors between itself and the descendant logger

      这段话定义了祖先关系,父关系。如果熟悉树形结构,很容易理解这些关系。例如名称为com.study的Logger对象与名称为com.study.base的Logger对象之间存在父关系。名称为com的Logger对象与名称为com.study.base的Logger对象之间存在祖先关系。

      子Logger对象会从父Logger对象中继承属性,例如level,appender。

      name属性是Logger对象的唯一标识,相同name对应的是同一个Logger对象。

    2.2.2   level

    Level是Logger对象的级别,它用于控制日志框架输出哪些信息。

    当Logger创建之后,它会存在一个日志级别,这个或许是Logger对象自定义的,也可能是从祖先Logger中继承得到的。当同时存在时,遵循以下原则:

      The effective level for a given logger Lis equal to the first non-null level in its hierarchystarting at L itself and proceeding upwards in the hierarchy towards the root logger

    • 这段话的意思是当Logger对象存在自定义级别时,使用自定义级别。
    •  当Logger对象需要从祖先Logger对象中继承时,继承第一个拥有自定义日志级别的祖先Logger对象,它的查找方向为Logger对象------> Root Logger。

      在使用Logger对象时,它有五个方法,error,warn,info,debug,trace。每次调用都会产生一条logging statement,它相当于触发了一个logging request。这个logging request有三个关键信息,name,level,message。其中name是Logger对象的名称,level是Logger request的level,message是日志信息。

      要使message记录在终端,需要满足Logger request的level 大于 Logger对象的effective level。

      原文中的定义如下:

      A log request of level p issued to a logger having an effective level qis enabled if p>=q

           日志级别的大小关系为ERROR > WARN > INFO > DEBUG > TRACE。

      配置日志级别的方式有两种,XML方式指定logger标签的level属性,或者直接调用Logger对象的setLevel方法。XML方式使用频率较高。

      2.2.3   appender

    Logger与Appender之间的关系是set 依赖关系。在ch.qos.logback.classic.logger对象中可以看到私有属性aai,它的类型为AppenderAttachableImpl。

    配置Appender的方式有两种,

    • XML方式下在Logger标签配置子标签appender-ref。
    • Java代码方式下调用log.addAppender方法。

    它们之间是一对多的关系,即一个Logger可以拥有多个Appender。

      默认情况下,Logger对象触发的logging request会同时推送到自己的Appender和祖先Logger对象的Appender。这个过程与DOM结构中事件冒泡的过程非常相似。当设置logger对象的additive属性为false时,不在向祖先Logger对象推送logging request。

      而Additive属性的默认值为true,这会导致终端输出重复的日志信息。

    2.3  Appender

      原文对Appender的定义如下:Logback allows logging request to print to multiple destinationIn logback speakan output destinations

      Appender是终端的抽象,最常见的终端是Console,File。详细的内容会在第四章中介绍。

    2.4   Layout

      原文对Layout的定义如下:The Layout is responsible for formatting the logging request according to the user’s wishes

      Layout按用户的意愿格式化日志信息。

    3、核心流程

    原著中将处理logging request的核心流程分为6个步骤

    1. Get the filter chain。触发过滤器,如果过滤器返回FilterReply.DENY,抛弃logging request;返回FilterReply.NEUTRAL,继续执行下一个过滤器;返回FilterReply.ACCEPT,忽略之后的过滤器,进入步骤2。
    2. Apply the basic selection rule。这个步骤是在比较logging request的level与Logger对象的level。Request level < logger level,则logging request被丢弃。
    3. Create a LoggingEvent Object。创建LoggingEvent对象,这个步骤类似于前端事件触发流程,它的作用与前端Event对象的作用基本是相同的,封装请求的信息。
    4. Invoking Appender。触发Logger中Appender对象的doAppender方法,方法的参数为LoggingEvent。
    5. Formatting the output。Appender对象依赖Layout对象,此时触发Appender中的Layout对象的doLayout方法,参数为LoggingEvent。它会将LoggingEvent对象转换为字符串。
    6. Sending out the LoggingEvent。将返回的字符串写入到各个终端。

    4、性能

    1. 自定义Logger对象的appender,否则该Logger对象触发的每次logging request都会遍历其祖先Logger,查找可以继承的appender。自定义可以避免查找过程
    2. 不同Appender的性能存在很大差异,原著中指出FileAppender的性能远远优于SocketAppender。
    3. 使用参数化方式替换传统的字符串替换方式。
    String userName = "张三";
    // 字符串方式
    logger.debug("Hello" + userName + "Welcome to our website");
    // 参数化方式
    logger.debug("Hello {}, Welcome to our website",userName);
    • 参数化方式只有在logging request的level大于logger的level时,才会将{}替换为真实的参数,它会提升性能。缺点在于参数过多时,很容易产生错误,例如忽略掉某个变量或者参数的顺序记错,导致变量替换错乱。
    • 字符串方式的缺点在于无论logging request的level是否大于logger的level,都会触发字符串拼接,拼接过程中有可能存在类型的转换,例如上面如果出现日期信息。

      至此本篇内容结束,原著的链接地址为:http://logback.qos.ch/manual/architecture.html

  • 相关阅读:
    会议记录补充5月9日
    会议记录补充5月11日
    每日会议记录5月6日
    SQL Server 日期函数
    Jvascript运算符
    For循环
    JS数据类型
    初识Javascript
    检测浏览器版本(综合整理)
    自己实现一个数组的slice方法
  • 原文地址:https://www.cnblogs.com/rain144576/p/12304524.html
Copyright © 2011-2022 走看看