• 框架——日志框架——logback——appender


      appender是日志框架核心对象之一,它的知识点包含两个,原理,类结构。

    1、原理

      它本质就是处理ILoggingEvent对象,并将结果传递给Layout对象进行格式化。它的入参是Event对象,出参是字符串。

      doAppend方法,源码如下:

    public void doAppend(E eventObject) {
    	// WARNING: The guard check MUST be the first statement in the
    	// doAppend() method.
    	// prevent re-entry.
    	if (Boolean.TRUE.equals(guard.get())) {
    		return;
    	}
    	try {
    		guard.set(Boolean.TRUE);
    		if (!this.started) {
    			if (statusRepeatCount++ < ALLOWED_REPEATS) {
    				addStatus(new WarnStatus("Attempted to append to non started appender [" + name + "].", this));
    			}
    			return;
    		}
    		if (getFilterChainDecision(eventObject) == FilterReply.DENY) {
    			return;
    		}
    		// ok, we now invoke derived class' implementation of append
    		this.append(eventObject);
    	} catch (Exception e) {
    		if (exceptionCount++ < ALLOWED_REPEATS) {
    			addError("Appender [" + name + "] failed to append.", e);
    		}
    	} finally {
    		guard.set(Boolean.FALSE);
    	}
    }
    

      第一步,判断guard变量,目的是为了防止多线程情况下,重复进入doAppend方法。

    第二步,判断appender是否已经开启,如果没有开启,抛出异常。例如在linux上设置FileAppender时,若没有创建文件夹的权限,会导致FileAppender创建失败,开启失败。

    第三步,运行过滤器,Appender对象也包含过滤器,它与流程中第一步中的过滤器类型是不同的。

    第四步,将logging request请求封装为ILogging Event对象,并作为参数传入append方法。

    2、类结构

     

    父接口:

    • LifeCycle:它用于管理Appender的生命周期,包含三个方法start,stop,isStarted。
    • ContextAware:它用于将Appender对象与LoggerContext对象进行绑定。
    • FilterAttachable:它用于管理过滤器,包含四个方法,添加过滤器addFilter,清空所有过滤器clearAllFilters,获取所有过滤器getCopyOfAttachedFilterList,获取过滤器执行结果getFilterChainDecision,返回FilterReply,它是一个枚举类,有三个值,DENY(请求失败),NEUTRAL(继续下一个过滤器),ACCEPT(忽略剩余过滤器,请求成功)。

      接口实现类:

    • UnsynchronizeAppenderBase:所有Appender的父类,它是一个抽象类,只有doAppend方法,这个方法的流程在之前已提过。
    • OutputStreamAppender:ConsoleAppender与FileAppender的父类,它需要一个核心对象OutputStream将message写入到Appender中。
    • Filter:过滤器,在第八章中将详细介绍。
    • Encoder:格式化日志信息,在第五章中将详细介绍。
    • ConsoleAppender:Appender种类的其中一种,代表输出控制台。
    • FileAppender:Appender种类的其中一种,代表日志信息将记录到文件中
    • RollingFileAppender:特殊的FileAppender,代表FileAppender会根据RollingPolicy,TriggerPolicy按照某种模式生成新的日志文件。
    • TriggerPolicy:它的作用是定义何时会触发新日志文件的生成。
    • RollingPolicy:它的作用是定义新日志文件的目录,名称,压缩格式等规则。

    2.1   outputStreamAppender

    ConsoleAppender与FileAppender的父类。它包含了两个最基本的属性encoder,immediateFlush。

    属性:

    encoder:appender依赖的Encoder,负责格式化日志信息。

    immediateFlush: 是否将日志信息刷新到Console或File。默认情况下会刷新到缓存区域,通常设置为false,等待缓存区满或者达到一定比例时,刷新。

    2.2   consoleAppender

    ConsoleAppender对应程序的输出控制台,在Java中对应System.out或System.err,也可以是任意一种PrintStream。它是OutputStreamAppender的子类

    属性:

    target:输出控制台对应的输出流对象,默认值为System.out。

    withJansi:不同日志级别设置不同的背景颜色。不常用,略。

    示例:

    <appender name="console"  class="ch.qos.logback.core.ConsoleAppender">
    	<!-- 包含1个encoder -->
    	<encoder>
    		<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    	</encoder>
    	<!-- 包含1个target,System.out 或者是System.err,默认为System.out -->
    	<target>System.out</target>
    	<!-- 包含1个 withJansi, 是否对不同级别的日志用颜色来区分 -->
    	<withJansi>false</withJansi>
    </appender>
    

    2.3  fileAppender

    FileAppender对应文件系统,Java语言是跨平台的,它的输出终端是File。此时File不能是目录。

    属性:

    append:新日志信息是否追加到文件的末尾,默认值为true。

    encoder:公共内容。略。

    file: 文件的绝对路径或相对路径,不能是目录。

    示例:

    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    	<!-- 设置日志文件的名称,default_file_name是一个自定义变量 -->
    	<file>${default_file_name}</file>
    	<!-- 设置是否追加在日志文件,该值默认为true,无需配置 -->
    	<append>true</append>
    	<!-- 设置immediateFlush,该值默认为true,无需配置 -->
    	<immediateFlush>true</immediateFlush>
    	<!-- 设置一个或者多个encoder -->
    	<encoder>
    		<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    	</encoder>
    </appender>
    

    2.4  rollingFileAppender

    RollingFileAppender是FileAppender的增强版,可以动态的生成新的日志文件。动态包含两项内容,

    第一,何时生成,即when,通常是日志文件达到一定大小,或者是根据日期。

    第二,新日志文件的命名规则。

    属性:

    triggeringPolicy:指定何时生成日志文件。

    rollingPolicy: 定义新日志的命名规则,这里的命名包含日志文件的目录结构和日志文件名。

    类结构:

     

    • FixedWindowRollingPolicy只实现了RollingPolicy接口
    • SizeBasedTriggeringPolicy只实现了TriggeringPolicy接口。
    • TimeBasedRollingPolicy同时实现了RollingPolicy接口和TriggeringPolicy,SizeAndTimeBasedRollingPolicy是它的子类。

    2.4.1   FixedWindowRollingPolicy

    它是一种新日志文件名称的生成规则。

    步骤如下:

    第一步,重命名日志文件为name + index。

    第二步,创建新日志文件,名称为name。

    示例:假设name为log.txt

    第一次,将log.txt重命名为log1.txt,创建log.txt。

    第二次,log1.txt重命名为log2.txt,log重命名为log1.txt,创建log.txt。

    Log.txt始终重命名为log1.txt,而log1.txt会导致index(当前) -1 次重命名,所以index不应该过大。

    属性:

    minIndex:index的最小值,默认为1,通常不修改。

    maxIndex:index的最大值,当设置超过20时,会被设置为20。

    fileNamePattern:日志文件名称的格式,默认值为name + index,可以任意设置,其中i%表示index变量。例如上述示例指定name_%i,则日志文件名称为log_1.txt。

    2.4.2     SizeBasedTriggeringPolicy

    它定义当日志文件超出一定大小时,触发生成新日志。

    属性:

    maxFileSize单个日志文件的最大值

    示例:

    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
    	<maxFileSize>3MB</maxFileSize>
    </triggeringPolicy>
    

    2.4.3   TimeBasedRollingPolicy

    前面两个类有很明显的短板,它们只能定义单个日志大小的条件,而且只能触发新日志文件的生成,无法触发删除旧日志。TimeBasedRollingPolicy可以全部实现,但是它也同样有短板,就是只能定义时间条件作为触发机制。

    属性:

    maxHistory: 日志文件保留的最长时间。它由fileNamePattern中的最小单位决定。

    totalSizeCap:日志文件的总大小,当超过这个数值时,会触发旧日志的删除。

    clearHistoryOnStart:触发删除旧日志的时机,当此值为true时,Appender在启动时便会触发。当此值为false时,会在rollOver阶段触发。 本质是调用appender.start方法时触发还是RollingPolicy接口的rollOver时触发。

    fileNamePattern:日志的文件名称格式。必须包含%d{dateFormat}。

    dateFormat日期格式:

    dateFormat格式与Java的日期格式相同。

    yyyy,MM,ww,dd,HH,mm,ss分别代表年,月,周,天,时(24小时制),分,秒。分,秒基本上用不到,不可能短时间就生成新日志。

    当fileNamePattern中只出现一个%d时,此时%d{yyyy-MM-dd}会以每天生成新的日志文件

    当fileNamePattern中出现多个%d时,其他的时间日期需要添加aux,表示不以该日期格式的最小单位作为间隔。例如 %d{yyyy-MM,aux}/log-%d{yyyy-MM-dd}.zip。

    当fileNamePattern中出现”/” 时,它定义了多层目录结构,例如%d{yyyy/MM}会生成年/月的目录结构

    当fileNamePattern中需要选择不同时区时,第二个参数指定时区,例如%d{yyyy-MM,UTC},该日期格式的时区为UTC。

    file与fileNamePattern:

    当同时指定file属性和fileNamePattern属性时,file属性会作为当前日志文件,fileNamePattern会作为历史日志存放目录。它们可以指定为不同的目录。

    假设fileNamePattern设置为%d{yyyy/MM/dd}/log.txt,file设置为applicationLog.txt,此时触发一次新日志生成的步骤如下:

    1. applicationLog.txt重命名为log.txt,并移动到yyyy/MM/dd的目录下,
    2. 在file属性的目录下重新生成applicationLog.txt,当前的日志信息都记录在此文件中。

      示例:

    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    	<!-- 指定fileNamePattern,定义日志文件或者是压缩包存放的位置,如果存在file属性,日志输出到file文件中,fileNamePattern存放日志压缩文件的路径 -->
    	<fileNamePattern>${file_dir}/%d{yyyy/MM,aux}/%d{yyyy-MM-dd}_log.zip</fileNamePattern>
    	<!-- 指定历史日志的最长存放时间,它的单位为fileNamePattern中的最小单位,此示例中为天,所以会删除10天以上的历史日志 -->
    	<maxHistory>10</maxHistory>
    	<!-- 最大的大小,100MB -->
    	<totalSizeCap>100MB</totalSizeCap>
    </rollingPolicy>
    

    2.4.4    SizeAndTimeBasedRollingPolicy

    在TimeBasedRollingPolicy基础上添加了大小的条件,这个属性是maxFileSize,在生成新日志文件时,添加了%i格式。其他属性同TimeBasedRollingPolicy。

    属性:

    maxFileSize:单个日志文件的最大值。

    fileNamePattern:新日志文件的命名规则。名称中包含%d{dateFormat}或%i。

    示例:

    <!-- 设置rollingPolicy -->
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    	<!-- 指定fileNamePattern,定义日志文件或者是压缩包存放的位置,如果存在file属性,日志输出到file文件中,fileNamePattern存放日志压缩文件的路径 -->
    	<fileNamePattern>${file_dir}/%d{yyyy/MM,aux}/%d{yyyy-MM-dd}_log.zip</fileNamePattern>
    	<!-- 每个文件的大小 -->
    	<maxFileSize>5MB</maxFileSize>
    	<!-- 指定最大的历史,10分钟,对应fileNamePattern中的日期格式 -->
    	<maxHistory>10</maxHistory>
    	<!-- 最大的大小,100MB -->
    	<totalSizeCap>100MB</totalSizeCap>
    </rollingPolicy>
    

      综上所述:

    FixedWindowRollingPolicy与SizeBasedTriggeringPolicy不能单独使用,而且不支持删除历史日志的功能,只支持生成新日志,新日志的名称只支持%i变量,触发的条件也只能选择大小。

    TimeBasedRollingPolicy同时支持新日志的生成和历史日志的删除,但是在新日志的名称只支持%d变量,触发的条件也只能选择时间。

    SizeAndTimeBasedRollingPolicy功能最全面,同时支持新日志的生成和历史日志的删除,新日志的名称同时支持%d和%i变量,触发的条件也最全面,同时支持时间,单个日志大小,总日志大小但同时配置也最繁琐。

    2.5   dBAppender

    DBAppender是将日志的信息记录到数据库中,需要配置数据源的信息。

    配置DBAppender的步骤如下:

      第一步,在ch/qos/logback/classic/db/script包下找到对应数据库的脚本。在数据库中执行脚本。

      第二步,配置数据源,如果数据源指定为DriverManagerConnectionSource,它使用JDBC的方式,没有任何数据连接池的概念,效率较低。如果数据源指定为DataSourceConnectionSource,可以配置dataSource,可以使用C3P0,Apache的dataSource或者阿里的durid数据源。如果数据源指定为JNDIConnectionSource,则配置JNDI的数据源,一般这种方式很少使用。

      第三步,将数据库的信息提取到properties文件当中,使用property标签引入相应的properties文件。

      注:logback相关表的主键需要由数据库来生成主键,logback在插入时不会生成主键。会导致插入语句失败。

    2.5.1 表结构

      

      

    2.5.2    属性

    当connectionSource为DriverManagerConnectionSource, 属性为driverClass,url,user,password。

    当connectionSource为DataSourceConnectionSource, 属性为任意的一种数据库连接池技术,例如C3P0。

    当connectionSource为JNDIConnectionSource时,略。

    2.5.3     配置

    <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
    	<!-- 连接信息 -->
    	<connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
    		<dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
    			<!-- 驱动类 -->
    			<driverClass>${logback.driver}</driverClass>
    			<!-- 数据库地址 -->
    			<jdbcUrl>${logback.url}</jdbcUrl>
    			<!-- 用户名 -->
    			<user>${logback.userName}</user>
    			<!-- 密码 -->
    			<password>${logback.password}</password>
    		</dataSource>
    	</connectionSource>
    </appender>
    

    2.6  SMTPAppender

    SMTPAppender是将日志发送到邮件当中,它默认的发送方式是异步的。底层的实现方式是java.mail.api,所以需要引入相应的jar包。

    使用步骤如下:

    第一步,填写java.mail.api所需要的必要属性,例如发件的服务器地址,端口,发件人,收件人,主题,用户名,密码等等信息。

    第二步,配置SMTPAppender。

    2.6.1   属性

    邮箱服务器信息:

    smtpHost:发件服务器的地址。例如126邮箱的为smtp.126.com。

    smtpPort:服务器的端口号,默认情况下时25,开始SSL时为465.

    to:收件人的邮箱地址,多个使用逗号分隔或者使用多个to标签。

    from:发件人的邮箱地址。

    subject:邮件的主题,默认是%logger{20} - %m

    username:用户名

    password:密码

    SSL:是否开启SSL,默认为false。

    STARTTLS:没有理解。

    CharsetEncoding:默认的字符编码集。

    Evaluator

        默认情况下只有error级别的日志才会触发发送邮件。可以通过配置Evaluator来覆盖默认的触发行为。

    第一种,编写自定义的Evaluator。

      1. 编写自定义XXEvaluator继承ContextAwareBase并且实现EventEvaluator接口。
      2. 配置evaluator,class属性指定为类的全名。

    第二种,使用内置的OnMarkerEvaluator。

      1. 使用MarkerFactory.getMarker(“key”)来获取marker对象。
      2. 将marker对象作为参数传入到打印日志的方法中。
      3. 在evaluator下配置marker子标签,每一个子标签对应一个value值。

    第三种,使用内置的JaninoEventEvaluator。

      1. 同onMarkerEvaluator,只不过在evaluator下面配置expression子标签。类似于marker!=null 或者marker.contains(“key”)等这样的表达式。

    第四种,使用内置的GEventEvaluator。

      1. 同JaninoEventEvaluator,只不过表达式的写法不同。

      其他:

    cyclicBufferTracker:配置缓存日志请求的数量,默认为64。

    localhost:主机的地址,未理解。

    asynchronousSending:是否异步发送,默认为true。

    includeCallerData:未理解。

    sessionViaJNDI:忽略。

    jndiLocation:忽略。

    2.6.2     配置

    <appender name="email" class="ch.qos.logback.classic.net.SMTPAppender">
    	<!-- 邮箱地址 -->
    	<smtpHost>${logback.smtpHost}</smtpHost>
    	<!-- 使用SSL -->
    	<SSL>true</SSL>
    	<!-- 收件人 -->
    	<to>${logback.to}</to>
    	<!-- 发送人 -->
    	<from>${logback.from}</from>
    	<!-- 主题 -->
    	<subject>TESTING:%logger{20} - %m{5}</subject>
    	<!-- 编码方式 -->
    	<charsetEncoding>${logback.charsetEncoding}</charsetEncoding>
    	<!-- 用户名 -->
    	<username>${logback.username}</username>
    	<!-- 密码 -->
    	<password>${logback.passWord}</password>
    	<!-- 布局 -->
    	<layout class="ch.qos.logback.classic.html.HTMLLayout" />
    	<!-- 缓存 -->
    	<cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
    		<!-- send just one log entry per email -->
    		<bufferSize>1</bufferSize>
    	</cyclicBufferTracker>
    	<!-- evaluator,相当于何时触发发送邮件的事件 -->
    	<!-- <evaluator class="com.module.logback.evaluator.SelfEvaluator" /> -->
    	<!-- marker -->
    	<evaluator class="ch.qos.logback.classic.boolex.OnMarkerEvaluator">
    		<marker>notify</marker>
    	</evaluator>
    </appender>
  • 相关阅读:
    web api中允许跨域访问
    HTTP Error 500.19
    使用SQL语句时应该注意的一些问题
    关于EsayUI中datagrid重复提交后台查询数据的问题
    EF6中使用事务的方法
    jquery中常用的方法和注意点
    在EF中正确的使用事务
    css解决移动端1px边框问题
    判定 JS 数据类型的最佳解决方案
    将伪数组转化为真数组
  • 原文地址:https://www.cnblogs.com/rain144576/p/16749319.html
Copyright © 2020-2023  润新知