• 后端——框架——日志框架——logback——《官网》阅读笔记——第六章节(Layout和日志格式)


    第六章节介绍核心对象Layout,不同于Encoder,Appender等其他核心对象,它的核心不是类的职责和其类体系结构,而是它的格式化表达式,它是Layout的pattern属性。

    类似于正则表达式,其实无论是Java语言,JS语言,它的难度在于表达式本身,而不是与之关联的对象。

    本章的主要内容如下:

    1. 自定义Layout,并在其中添加自定义属性。
    2. Layout的日志格式。
    3. 其他Layout对象,HTMLLayout,XMLLayout,这些对象的使用频率很低。待完善
    4. Logback-access模块的格式化表达式。待完善

    1、自定义Layout

    1.1   类结构

      

      

    1.2  概念

    在编写自定义Layout之前,首先需要理解编写配置文件与Java对象之间的对象。

    在配置文件中配置encoder标签,本质是在配置Appender对象的encoder属性,其中该标签的class属性为Encoder的类型,当类型为PatternLayoutEncoder时,可以省略。

    在配置encoder子标签时,它本质是配置Encoder类的属性,所以根据不同的Encoder类型,它的子标签也是不一样的。

    假设class为PatternLayoutEncoder时

    • 配置pattern标签,相当于给对象的pattern属性赋值。
    • 配置layout标签,相当于给对象的layout属性赋值,其中标签的class属性为Layout的类型。

    自定义Layout就是编写自定义的Layout接口实现类。

    1.3   步骤

    在编写自定义Layout时,首先需要了解Layout的类结构和概念。它的具体步骤如下:

    1. 编写自定义MyLayout,它可以实现Layout接口,也可以继承抽象类LayoutBase。本例中选择继承LayoutBase,它提供了接口的默认实现。MtLayout只需要实现doAppend方法即可。
    2. 在MyLayout添加0..N个自定义属性,这些属性必须有set方法。
    3. 在配置文件中,设置encoder标签的class属性值为LayoutWrapperEncoder,这个是适配器类。
    4. 在配置文件中,设置encoder子标签layout,它的class属性值为MyLayout,如果存在自定义属性,可以将其配置为layout子标签。

      1.4   代码

      自定义Layout类MyLayout

    /**
     * 
     * @File Name: MyLayout.java
     * @Description: 自定义layout类
     * @version 1.0
     * @since JDK 1.8
     */
    public class MyLayout extends LayoutBase<ILoggingEvent> {
    	// 添加自定义属性prefix
    	private String prefix;
    	// 添加自定义属性suffix;
    	private String suffix;
    	//
    	private static final String DEFAULT_SPLIT_STR = "****";
    
    	public String doLayout(ILoggingEvent event) {
    		StringBuffer sbuf = new StringBuffer();
    		// 添加前缀
    		if (!StringUtils.isEmpty(prefix)) {
    			sbuf.append(prefix).append(DEFAULT_SPLIT_STR);
    		}
    		// 时间戳
    		sbuf.append(event.getTimeStamp()).append(DEFAULT_SPLIT_STR);
    		// 级别
    		sbuf.append(event.getLevel().levelStr).append(DEFAULT_SPLIT_STR);
    		// 线程
    		sbuf.append(event.getThreadName()).append(DEFAULT_SPLIT_STR);
    		// logger name
    		sbuf.append(event.getLoggerName()).append(DEFAULT_SPLIT_STR);
    		// line separator
    		sbuf.append(event.getFormattedMessage()).append(DEFAULT_SPLIT_STR);
    		// 添加后缀
    		if (!StringUtils.isEmpty(suffix)) {
    			sbuf.append(suffix).append(DEFAULT_SPLIT_STR);
    		}
    		// 分隔符
    		sbuf.append("
    ");
    		return sbuf.toString();
    	}
    	public void setPrefix(String prefix) {
    		this.prefix = prefix;
    	}
    	public void setSuffix(String suffix) {
    		this.suffix = suffix;
    	}
    }
    

       配置文件,只给出appender部分的内容

    <!-- 配置ConsoleAppender -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    	<!-- 默认值,可以省略,此处只是为了学习 -->
    	<target>System.out</target>
    	<!-- 默认值,可以省略,它的作用是为了给不同级别的日志添加不同的颜色背景 -->
    	<withJansi>false</withJansi>
    	<!-- 配置encoder,大部分学习的都是logback-classic模块的内容 -->
    	<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
    		<!-- 添加自定义Layout,由于配置了Layout,不在需要配置pattern,它是PatternLayoutEncoder的一个属性 -->
    		<layout class="learn.logback.chapter6.MyLayout">
    			<!-- 配置自定义属性 -->
    			<prefix>[single log start]</prefix>
    			<suffix>[single log end]</suffix>
    		</layout>
    	</encoder>
    </appender>
    

      单条日志的效果如下:

    [single log start] ****1582122070664****DEBUG****main****learn.logback.chapter1.HelloWorld****Hello张三Welcome to our website**** [single log end]**** 

    2、日志格式

    当在配置日志格式时,此时它对应的类必须是PatternLayoutEncoder,表现在配置文件上为encoder标签中class属性值为默认值。配置日志格式本质是给PatternLayoutEncoder对象的pattern属性赋值。该属性的主要作用是控制日志信息的格式。

    日志格式由一个个小单元组成,每个小单元由三个部分组成,

    • Format modifier:它的作用是控制日志信息的长度。功能有补充空白字符,截取字符。其中符号”-”表示方向,它表示从末尾补充,或从末尾截取。
    • Conversion Name:它是日志表达式的核心,对应ILoggingEvent中的某一个具体信息,可以是线程,可以是时间,可以是日志内容等等,这部分是小单元的核心。它的格式通常为% + conversionName,conversion Name可以是全称,也可以是缩写
    • Optional parameters:可选参数,它与conversionName密切相关,例如当conversionName为时间时,参数为日期格式,当conversionName为logger名称时,参数为名称的最大长度。

    2.1   Conversion Name

    Conversion name很多,我将它分为五类。

    • 基本:date(时间),logger(名称),level(级别),thread(线程),message(日志信息),%n(换行符),这些是最基本的,也是必备的一些信息。
    • 变量:contextName(上下文名称),marker(标签),Mdc(MDC对象的key-value对),Property(property属性,环境变量等)。
    • 杂项:line(行号),replace(字符串的替换方法),class(类全名),file(类文件名)
    • 方法:method(方法名称),caller(方法调用层次),使用频率低,本文省略。
    • 异常:exception,nopexception,rootException,xException,使用默认值即可,本文省略。

    2.1.1    date

    描述

    date,缩写为d

    参数

    名称:pattern

          说明:日期的格式,

          值:yyyy-MM-dd HH:mm:ss SSS任意组合。

          是否必填:否,默认格式为yyyy-MM-dd HH:mm:ss SSS

     

    名称:timezone

          说明: 时区,

          值:任意合理的时区,例如Asia/shanghai。

          是否必填:否,默认为系统的时区。

    性能

    使用频率很高,不影响性能。

    示例

    %d{yyyy-MM-dd HH:mm:ss SSS},// 指定日期格式

    %date,// 使用默认的格式

    %date{yyyy-MM-dd HH:mm:ss SSS,Asia/shanghai},// 带有时区参数。

    2.1.2   logger & class & file

    描述

    Logger,缩写为c,lo。个人不建议使用缩写,缩写的语义不太明显

    参数

    名称:length

          说明:Logger名称的最大长度,当logger的name长度大于length时,会对name进行截取,它总是name开始处截取。

          值:任何整数。

          是否必填:否,

    性能

    使用频率很高,不影响性能。

    示例

    %logger{30}:logger名称的最大长度为30。

    关联的conversion name

    1. Class表示类名,缩写为C
    2. File表示Java文件,缩写为F

    它们基本不会用到,因为logger的名称一般都是类全名,而Java中类名和Java的文件名是一致的。所以class,file都可以从logger名称中推测出来,有点多余。

      示例如下:

      当pattern的格式为:%d{HH:mm:ss.SSS} [%logger] [%class] [%file] %n

      它对应的效果图为:

    15:43:51.438 [learn.logback.chapter1.HelloWorld] [learn.logback.chapter1.HelloWorld] [HelloWorld.java]
    

      三者的值基本都是相同的。

    2.1.3   Thread

    描述

    Thread,缩写为t,表示当前线程的名称

    参数

    性能

    使用频率很高,不影响性能。

    示例

    %thread

    2.1.4  Level

    描述

    Logger request的日志级别,它不是在logger标签对应的level,缩写为l

    参数

    性能

    使用频率很高,不影响性能。

    示例

    %level

    2.1.5   message

    描述

    Logging request的信息内容,缩写为m

    参数

    性能

    使用频率很高,不影响性能。

    示例

    %message,%msg

      默认的日志格式由上述5个部分组成,最后的%n表示换行符。%d  [%thread] %-5level %logger{36} - %msg%n

    2.1.6   ContextName

    描述

    日志框架上下文的名称,即LoggerContext对象的name属性,在使用时需要配置contextName标签。缩写为cn

    参数

    性能

    使用频率一般,不影响性能。

    示例

    %contextName,%cn

      示例如下:

      当配置<contextName>Learn_Logback</contextName>时

    // 日志格式:
    %d [%contextName] [%marker] %n
    // 日志
    2020-02-20 16:09:38,841 [Learn_Logback] []

    2.1.7   Marker

    描述

    日志请求的标记,在调用请求相关方法时,第一个参数为marker,第二个参数为message。使用MarkerFactory的getMarker创建Marker对象。

    参数

    性能

    使用频率一般,不影响性能。

    示例

    %Marker

      示例如下:

      当代码为:

    Marker test =MarkerFactory.getMarker("Marker test");
    logger.debug(test, "Hello World");
    

      它的效果如下:

    // 日志格式:
    %d [%contextName] [%marker] %n
    // 日志
    2020-02-20 16:16:40,901 [Learn_Logback] [Marker test]

    2.1.8   Mdc

    描述

    org.slf4j.MDC保存着key-value键值对,该标签根据key值,访问value值。使用时,需要在之前设置MDC.put(key,value)方法

    参数

    Key值

    性能

    使用频率一般,不影响性能。

    示例

    %mdc{key}

    示例如下:

    代码为:

    MDC.put("mdc_key", "mdc_value");
    Marker test =MarkerFactory.getMarker("Marker test");
    logger.debug(test, "Hello World");
    

      它的效果如下:

    // 日志格式:
    %d [%contextName] [%marker] [%mdc{mdc_key}] %n 
    // 日志
    2020-02-20 16:26:33,814 [Learn_Logback] [Marker test] [mdc_value]

      2.1.9   Property

    描述

    根据property中的key值获取value值。property它的值有四种,配置文件中的property标签,引入的properties文件,JVM变量,操作系统的环境变量。

    参数

    变量的Key值

    性能

    使用频率一般,不影响性能。

    示例

    %property{key}

    示例如下:

    此例中获取JVM中的os.name变量。

    它的效果如下:

    // 日志格式:
    %d [%mdc{mdc_key}] [%property{os.name}] %n// 日志
    2020-02-20 16:26:33,814  [mdc_value] [Windows 10]

    2.1.10  Line

    描述

    日志显示行号,缩写为L

    参数

    性能

    使用频率一般,不影响性能。

    示例

    %line,%L

    2.2  Formatting

    格式化指定日志中某个部分的长度。它有两种形式:

    格式一:%  +  num  +   conversionName

    1. %固定字符串。
    2. 当num为正整数时,当conversionName的长度小于num时,会在开头填充空格。大于时什么都不做,当num为负数时,在末尾填充空格。
    3. ConversionName:日志的任何组成部分,可以使用括号将一组conversionName括起来。

    示例:

    %20logger:当logger的长度小于20时,会在开头填充空格。

    %20(%logger %level %thread),将logger,level,thread当成一组,一个整体,当整体部分小于20时,会在开头填充空格。

    格式二:%  +  dot  + num  +  conversionName

    1. %固定字符串,dot表示点号(.)。
    2. 当num为正整数时,当conversionName的长度大于num时,会从开头截取字符串,小于时什么都不做。当num为负数时,会从末尾开始截取字符串。

    示例:

    %.1level:如果为INFO时,表示为O,被截取掉的字符串为INF。

    %.-1level:如果为INFO时,表示为I,被截取掉的字符串为NFO。

    2.3  Coloring

             Coloring的主要功能是为不同级别的日志配置不同的背景色。要实现此功能有很多种方式,例如在Eclipse中安装logViewer插件,Idea可以使用JansiColor的插件。本文省略。

    2.4  Evaluator

             TODO

    2.5   自定义conversionName

             TODO

    3、HtmlLayout

             TODO

    4、XMLLayout

             TODO

    5、Access模块

      TODO

  • 相关阅读:
    Python3.6全栈开发实例[022]
    Python3.6全栈开发实例[021]
    Python3.6全栈开发实例[020]
    Python3.6全栈开发实例[019]
    Python3.6全栈开发实例[018]
    单选按钮QRadioButton
    QToolButton按钮
    文本编辑框QTextEdit
    信号-事件汇总
    QMessageBox消息框
  • 原文地址:https://www.cnblogs.com/rain144576/p/12304478.html
Copyright © 2020-2023  润新知