以下文章来源于鸭血粉丝

一、摘要

不论是应用何种编程语言,何种框架,日志输入简直无处不再,也是任何商业软件中必不可少的一部分。

总结起来,日志的用处大抵能够演绎成以下三种:

  • 问题追踪:通过日志不仅仅包含咱们程序的一些bug,也能够在装置配置时,通过日志能够发现问题。
  • 状态监控:通过实时剖析日志,能够监控零碎的运行状态,做到早发现问题、早解决问题。
  • 平安审计:审计次要体现在平安上,通过对日志进行剖析,能够发现是否存在非受权的操作。

以 Java 编程语言为例,打印日志的形式有很多,例如通过System.out.print()办法将要害信息输入到控制台,也能够通过 JDK 自带的日志Logger类输入,尽管 JDK 从1.4开始反对日志输入,然而性能繁多,无奈更好的满足商业要求,于是诞生了很多第三方日志库,像咱们所相熟的支流框架log4jlog4j2logback等,提供的 API 性能都远胜 JDK 提供的Logger

二、Log4j

2.1、介绍

Log4j 是一种十分风行的日志框架,由Ceki Gülcü独创,之后将其开源奉献给 Apache 软件基金会。

Log4j 有三个次要的组件:Loggers(记录器),Appenders (输入源)和Layouts(布局)。这里可简略了解为日志类别日志要输入的中央日志以何种模式输入

综合应用这三个组件能够轻松地记录信息的类型和级别,并能够在运行时管制日志输入的款式和地位。

Log4j 的架构大抵如下:

当咱们应用 Log4j 输入一条日志时,Log4j 主动通过不同的Appender(输入源)把同一条日志输入到不同的目的地。例如:

  • console:输入到屏幕;
  • file:输入到文件;
  • socket:通过网络输入到近程计算机;
  • jdbc:输入到数据库

在输入日志的过程中,通过Filter来过滤哪些log须要被输入,哪些log不须要被输入。

Loggers(记录器)组件中,级别分五种:DEBUGINFOWARNERRORFATAL

这五个级别是有程序的,DEBUG < INFO < WARN < ERROR < FATAL,别离用来指定这条日志信息的重要水平,明确这一点很重要,Log4j有一个规定:只输入级别不低于设定级别的日志信息

假如Loggers级别设定为INFO,则INFOWARNERRORFATAL级别的日志信息都会输入,而级别比INFO低的DEBUG则不会输入。

最初,通过Layout来格式化日志信息,例如,主动增加日期、工夫、办法名称等信息。

具体输入款式配置,能够参考如下内容Log4j2 - Layouts布局介绍

2.2、我的项目利用

以 Java 我的项目为例,在 Maven 的pom.xml中增加如下依赖!

2.2.1、增加 maven 依赖
<dependencies>    <dependency>        <groupId>org.slf4j</groupId>        <artifactId>slf4j-api</artifactId>        <version>1.6.6</version>    </dependency>    <dependency>        <groupId>org.slf4j</groupId>        <artifactId>slf4j-log4j12</artifactId>        <version>1.6.6</version>    </dependency>    <dependency>        <groupId>log4j</groupId>        <artifactId>log4j</artifactId>        <version>1.2.17</version>    </dependency></dependencies>
2.2.2、创立log4j配置

在理论利用中,要使Log4j在零碎中运行须当时设定配置文件。

配置文件实际上也就是对LoggerAppenderLayout进行相应设定。

Log4j反对两种配置文件格式,一种是XML格局的文件,一种是properties属性文件,二选一。

创立一个log4j.xml或者log4j.properties,将其放入我的项目根目录下。

1、XML格局
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd"><log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">    <!-- 控制台输入配置 -->    <appender name="console" class="org.apache.log4j.ConsoleAppender">        <!-- 指标为控制台 -->        <param name="Target" value="System.out" />        <layout class="org.apache.log4j.PatternLayout">            <!-- 输入格局 -->            <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %l %m%n" />        </layout>    </appender>    <!-- 文件输入配置 -->    <appender name="log_file" class="org.apache.log4j.DailyRollingFileAppender">        <!-- 指标为文件 -->        <param name="File" value="/logs/log/file.log" />        <!-- 向文件追加输入 -->        <param name="Append" value="true" />        <!-- 每个小时生成一个log -->        <param name="DatePattern" value="'.'yyyy-MM-dd-HH" />        <layout class="org.apache.log4j.PatternLayout">            <!-- 输入格局 -->            <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %l %m%n" />        </layout>    </appender>    <!-- Application Loggers -->    <logger name="org.example">        <level value="info" />    </logger>    <!-- 根目录 -->    <!-- Root Logger -->    <root>        <priority value="info" />        <appender-ref ref="console" />        <appender-ref ref="log_file" />    </root></log4j:configuration>

2、properties格局

log4j.rootLogger=INFO,M,C,Elog4j.additivity.monitorLogger=false# INFO级别文件输入配置log4j.appender.M=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.M.File=/logs/info.loglog4j.appender.M.ImmediateFlush=falselog4j.appender.M.BufferedIO=truelog4j.appender.M.BufferSize=16384log4j.appender.M.Append=truelog4j.appender.M.Threshold=INFOlog4j.appender.M.DatePattern='.'yyyy-MM-ddlog4j.appender.M.layout=org.apache.log4j.PatternLayoutlog4j.appender.M.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} %p %l %m %n# ERROR级别文件输入配置log4j.appender.E=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.E.File=/logs/error.loglog4j.appender.E.ImmediateFlush=truelog4j.appender.E.Append=truelog4j.appender.E.Threshold=ERRORlog4j.appender.E.DatePattern='.'yyyy-MM-ddlog4j.appender.E.layout=org.apache.log4j.PatternLayoutlog4j.appender.E.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} %p %l %m %n# 控制台输入配置log4j.appender.C=org.apache.log4j.ConsoleAppenderlog4j.appender.C.Threshold=INFOlog4j.appender.C.layout=org.apache.log4j.PatternLayoutlog4j.appender.C.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %l %m %n
2.2.3、log4j应用

在须要打印日志的类中,引入Logger类,在须要的中央打印即可!

package org.example.log4j.service;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class LogPrintUtil {    /**log动态常量*/    private static final Logger logger = LoggerFactory.getLogger(LogPrintUtil.class);    public static void main(String[] args){            logger.info("info信息");            logger.warn("warn信息");            logger.error("error信息");    }}

当然你还能够这样写

if(logger.isInfoEnabled()) {    logger.info("info信息");}if(logger.isWarnEnabled()) {    logger.warn("warn信息");}

2.2.4、isInfoEnabled()有何作用呢?

简略来说,在某些场景下,用isInfoEnabled()办法判断下是能晋升性能的!

例如咱们打印这段内容logger.info("User:" + userId + appId),程序在打印这行代码时,先对内容("User:" + userId + appId)进行字符串拼接,而后再输入。

如果以后配置文件中日志输入级别是info,是间接输入的,当日志输入级别是error时,logger.info()的内容时不输入的,然而咱们却进行了字符串拼接,如果加上if(logger.isInfoEnabled())进行一次断定,logger.info()就不会执行,从而更好的晋升性能,这个尤其是在高并发和简单log打印状况下晋升十分显著。

另外,ERROR及其以上级别的log信息是肯定会被输入的,所以只有logger.isDebugEnabledlogger.isInfoEnabledlogger.isWarnEnabled()办法,而没有logger.isErrorEnabled办法

三、Log4j2

3.1、介绍

log4j2 是 log4j 1.x 的升级版,参考了 logback 的一些优良的设计,并且修复了一些问题,因而带来了一些重大的晋升,次要特点有:

  • 异样解决:在logback中,Appender中的异样不会被利用感知到,然而在log4j2中,提供了一些异样解决机制。
  • 性能晋升, log4j2相较于log4j 1和logback都具备很显著的性能晋升,前面会有官网测试的数据。
  • 主动重载配置:参考了logback的设计,当然会提供主动刷新参数配置,最实用的就是咱们在生产上能够动静的批改日志的级别而不须要重启利用——那对监控来说,是十分敏感的。
  • 无垃圾机制:log4j2在大部分状况下,都能够应用其设计的一套无垃圾机制,防止频繁的日志收集导致的jvm gc。

3.2、我的项目利用

3.2.1、增加 maven 依赖
<dependencies>    <!-- slf4j外围包 -->    <dependency>        <groupId>org.slf4j</groupId>        <artifactId>slf4j-api</artifactId>        <version>1.7.13</version>    </dependency>    <!--用于与common-log放弃桥接 -->    <dependency>        <groupId>org.slf4j</groupId>        <artifactId>jcl-over-slf4j</artifactId>        <version>1.7.13</version>        <scope>runtime</scope>    </dependency>    <!--外围log4j2jar包 -->    <dependency>        <groupId>org.apache.logging.log4j</groupId>        <artifactId>log4j-api</artifactId>        <version>2.4.1</version>    </dependency>    <dependency>        <groupId>org.apache.logging.log4j</groupId>        <artifactId>log4j-core</artifactId>        <version>2.4.1</version>    </dependency>    <!--用于与slf4j放弃桥接 -->    <dependency>        <groupId>org.apache.logging.log4j</groupId>        <artifactId>log4j-slf4j-impl</artifactId>        <version>2.4.1</version>    </dependency>    <!--须要应用log4j2的AsyncLogger须要蕴含disruptor -->    <dependency>        <groupId>com.lmax</groupId>        <artifactId>disruptor</artifactId>        <version>3.2.0</version>    </dependency></dependencies>
3.2.2、创立log4j2配置

在我的项目的根目录下创立一个log4j2.xml的文件,与log4j相比,log4j2的异步输入日志性能十分强劲,配置如下:

1、同步输入日志

<?xml version="1.0" encoding="UTF-8"?><!-- status : 这个用于设置log4j2本身外部的信息输入,能够不设置,当设置成trace时。 注:本配置文件的指标是将不同级别的日志输入到不同文件,最大1MB一个文件,     文件数据达到最大值时,旧数据会被压缩并放进指定文件夹 ,最多寄存20个文件--><Configuration status="error">    <!-- 配置日志文件输入目录,此配置将日志输入到根目录下的指定文件夹 -->    <Properties>        <Property name="fileDir">/logs/log4j2</Property>        <Property name="fileHistory">/logs/log4j2/history</Property>    </Properties>    <Appenders>        <!-- 优先级从高到低别离是 OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL -->        <!-- 单词解释:Match:匹配 DENY:回绝 Mismatch:不匹配 ACCEPT:承受 -->        <!-- DENY,日志将立刻被摈弃不再通过其余过滤器;NEUTRAL,有序列表里的下个过滤器过接着解决日志;ACCEPT,日志会被立刻解决,不再通过残余过滤器。 -->        <!--输入日志的格局        %d{yyyy-MM-dd HH:mm:ss, SSS} : 日志生产工夫        %t 输入以后线程名称        %-5level 输入日志级别,-5示意左对齐并且固定输入5个字符,如果有余在左边补0        %logger 输入logger名称,因为Root Logger没有名称,所以没有输入        %msg 日志文本        %n 换行        其余罕用的占位符有:        %F 输入所在的类文件名,如Client.java        %L 输入行号        %M 输入所在办法名        %l  输入语句所在的行数, 包含类名、办法名、文件名、行数         -->        <!--这个输入控制台的配置,这里输入all信息到System.out -->        <console name="Console" target="SYSTEM_OUT">            <!-- 输入日志的格局 -->            <PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %l %msg%n" />        </console>        <!--这个输入文件的配置,这里输入info信息到junbao_info.log -->        <RollingFile name="RollingFileInfo" fileName="${fileDir}/info.log" filePattern="${fileHistory}/info/%d{yyyy-MM-dd}-%i.log">            <!-- 此Filter意思是,只输入info级别的数据 DENY,日志将立刻被摈弃不再通过其余过滤器;NEUTRAL,有序列表里的下个过滤器过接着解决日志;                     ACCEPT,日志会被立刻解决,不再通过残余过滤器。 -->            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />            <PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %l %msg%n" />            <Policies>            <!-- 如果启用此配置,则日志会按文件名生成新文件, 即如果filePattern配置的日期格局为 %d{yyyy-MM-dd HH}                     ,则每小时生成一个压缩文件, 如果filePattern配置的日期格局为 %d{yyyy-MM-dd} ,则天生成一个压缩文件,默认为1 -->                <TimeBasedTriggeringPolicy />                <!-- 每个日志文件最大1MB,超过1MB生产新的文件 ; -->                <SizeBasedTriggeringPolicy size="100MB" />            </Policies>             <!--文件夹下最多的文件个数-->              <DefaultRolloverStrategy max="20" />        </RollingFile>        <RollingFile name="RollingFileWarn" fileName="${fileDir}/warn.log" filePattern="${fileHistory}/warn/%d{yyyy-MM-dd}-%i.log">            <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY" />            <PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %l %msg%n" />            <Policies>                <TimeBasedTriggeringPolicy />                <SizeBasedTriggeringPolicy size="100MB" />            </Policies>            <DefaultRolloverStrategy max="20" />        </RollingFile>        <RollingFile name="RollingFileError" fileName="${fileDir}/error.log" filePattern="${fileHistory}/error/%d{yyyy-MM-dd}-%i.log">            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY" />            <PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %l %msg%n" />            <Policies>                <TimeBasedTriggeringPolicy />                <SizeBasedTriggeringPolicy size="100MB" />            </Policies>            <DefaultRolloverStrategy max="20" />        </RollingFile>    </Appenders>    <!--而后定义logger,只有定义了logger并引入的appender,appender才会失效 -->    <Loggers>        <!--全异步输入info级以上的日志信息-->         <!-- <asyncRoot level="info" includeLocation="true">            <appender-ref ref="Console" />            <appender-ref ref="RollingFileInfo" />        </asyncRoot> -->        <!--同步输入info级以上的日志信息-->         <root level="info" includeLocation="true">            <appender-ref ref="Console" />        </root>    </Loggers></Configuration>

2、异步输入日志

<?xml version="1.0" encoding="UTF-8"?><!-- status : 这个用于设置log4j2本身外部的信息输入,能够不设置,当设置成trace时。 注:本配置文件的指标是将不同级别的日志输入到不同文件,最大1MB一个文件,     文件数据达到最大值时,旧数据会被压缩并放进指定文件夹 ,最多寄存20个文件--><Configuration status="error">    <!-- 配置日志文件输入目录,此配置将日志输入到根目录下的指定文件夹 -->    <Properties>        <Property name="fileDir">/logs/log4j2</Property>        <Property name="fileHistory">/logs/log4j2/history</Property>    </Properties>    <Appenders>        <!-- 优先级从高到低别离是 OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL -->        <!-- 单词解释:Match:匹配 DENY:回绝 Mismatch:不匹配 ACCEPT:承受 -->        <!-- DENY,日志将立刻被摈弃不再通过其余过滤器;NEUTRAL,有序列表里的下个过滤器过接着解决日志;ACCEPT,日志会被立刻解决,不再通过残余过滤器。 -->        <!--输入日志的格局        %d{yyyy-MM-dd HH:mm:ss, SSS} : 日志生产工夫        %t 输入以后线程名称        %-5level 输入日志级别,-5示意左对齐并且固定输入5个字符,如果有余在左边补0        %logger 输入logger名称,因为Root Logger没有名称,所以没有输入        %msg 日志文本        %n 换行        其余罕用的占位符有:        %F 输入所在的类文件名,如Client.java        %L 输入行号        %M 输入所在办法名        %l  输入语句所在的行数, 包含类名、办法名、文件名、行数         -->        <!--这个输入控制台的配置,这里输入all信息到System.out -->        <console name="Console" target="SYSTEM_OUT">            <!-- 输入日志的格局 -->            <PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %l %msg%n" />        </console>        <!--这个输入文件的配置,这里输入info信息到junbao_info.log -->        <RollingFile name="RollingFileInfo" fileName="${fileDir}/info.log" filePattern="${fileHistory}/info/%d{yyyy-MM-dd}-%i.log">            <!-- 此Filter意思是,只输入info级别的数据 DENY,日志将立刻被摈弃不再通过其余过滤器;NEUTRAL,有序列表里的下个过滤器过接着解决日志;                     ACCEPT,日志会被立刻解决,不再通过残余过滤器。 -->            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />            <PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %l %msg%n" />            <Policies>            <!-- 如果启用此配置,则日志会按文件名生成新文件, 即如果filePattern配置的日期格局为 %d{yyyy-MM-dd HH}                     ,则每小时生成一个压缩文件, 如果filePattern配置的日期格局为 %d{yyyy-MM-dd} ,则天生成一个压缩文件,默认为1 -->                <TimeBasedTriggeringPolicy />                <!-- 每个日志文件最大1MB,超过1MB生产新的文件 ; -->                <SizeBasedTriggeringPolicy size="100MB" />            </Policies>             <!--文件夹下最多的文件个数-->              <DefaultRolloverStrategy max="20" />        </RollingFile>        <RollingFile name="RollingFileWarn" fileName="${fileDir}/warn.log" filePattern="${fileHistory}/warn/%d{yyyy-MM-dd}-%i.log">            <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY" />            <PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %l %msg%n" />            <Policies>                <TimeBasedTriggeringPolicy />                <SizeBasedTriggeringPolicy size="100MB" />            </Policies>            <DefaultRolloverStrategy max="20" />        </RollingFile>        <RollingFile name="RollingFileError" fileName="${fileDir}/error.log" filePattern="${fileHistory}/error/%d{yyyy-MM-dd}-%i.log">            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY" />            <PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %l %msg%n" />            <Policies>                <TimeBasedTriggeringPolicy />                <SizeBasedTriggeringPolicy size="100MB" />            </Policies>            <DefaultRolloverStrategy max="20" />        </RollingFile>    </Appenders>    <!--而后定义logger,只有定义了logger并引入的appender,appender才会失效 -->    <Loggers>        <!--全异步输入info级以上的日志信息-->         <asyncRoot level="info" includeLocation="true">            <appender-ref ref="Console" />            <appender-ref ref="RollingFileInfo" />        </asyncRoot>        <!--同步输入info级以上的日志信息-->         <!-- <root level="info" includeLocation="true">            <appender-ref ref="Console" />        </root> -->    </Loggers></Configuration>

具体 API 能够参考官方网站!

3.2.3、log4j2应用

与 log4j 相似,间接在须要地位打印日志即可

package org.example.log4j.service;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class LogPrintUtil {    /**log动态常量*/    private static final Logger logger = LoggerFactory.getLogger(LogPrintUtil.class);    public static void main(String[] args){            logger.info("info信息");            logger.warn("warn信息");            logger.error("error信息");    }}

四、Logback

4.1、介绍

Logback 也是用 java 编写一款十分热门的日志开源框架,由 log4j 创始人写的,性能比 log4j 要好!

logback 次要分为3个模块:

  • logback-core:外围代码模块
  • logback-classic:log4j的一个改进版本,同时实现了slf4j的接口,这样你如果之后要切换其余日志组件也是一件很容易的事
  • logback-access:拜访模块与Servlet容器集成提供通过Http来拜访日志的性能

4.2、我的项目利用

4.2.1、增加 maven 依赖
<!--这个依赖间接蕴含了 logback-core 以及 slf4j-api的依赖--><dependency>    <groupId>ch.qos.logback</groupId>    <artifactId>logback-classic</artifactId>    <version>1.2.3</version></dependency><!-- 反对在xml中写判断标签 --><dependency>    <groupId>org.codehaus.janino</groupId>    <artifactId>janino</artifactId>    <version>2.7.8</version></dependency>
4.2.2、创立logback配置文件
1、配置阐明

logback在启动的时候,会依照上面的程序加载配置文件:

  • 如果java程序启动时指定了logback.configurationFile属性,就用该属性指定的配置文件。如java -Dlogback.configurationFile=/path/to/mylogback.xml Test,这样执行Test类的时候就会加载/path/to/mylogback.xml配置
  • classpath中查找logback.groovy文件
  • classpath中查找logback-test.xml文件
  • classpath中查找logback.xml文件
  • 如果是jdk6+,那么会调用ServiceLoader查找 com.qos.logback.classic.spi.Configurator接口的第一个实现类
  • 主动应用ch.qos.logback.classic.BasicConfigurator,在控制台输入日志

下面的程序示意优先级,应用java -D配置的优先级最高,只有获取到配置后就不会再执行上面的流程。相干代码能够看ContextInitializer#autoConfig()办法。

2、同步输入日志
<?xml version="1.0" encoding="UTF-8"?><!-- scan:当此属性设置为true时,配置文件如果产生扭转,将会被从新加载,默认值为true。scanPeriod:设置监测配置文件是否有批改的工夫距离,如果没有给出工夫单位,默认单位是毫秒。当scan为true时,此属性失效。默认的工夫距离为1分钟。     debug:当此属性设置为true时,将打印出logback外部日志信息,实时查看logback运行状态。默认值为false。 --><configuration scan="true" scanPeriod="60 seconds" debug="false">    <!-- 运行环境,dev:开发,test:测试,pre:预生产,pro:生产 -->    <property name="system_host" value="dev" />    <property file="system.properties" />    <!-- 上下文变量设置,用来定义变量值,其中name的值是变量的名称,value的值时变量定义的值。 通过<property>定义的值会被插入到logger上下文中。定义变量后,能够使“${}”来应用变量。 -->    <property name="CONTEXT_NAME" value="logback-test" />    <!-- 日志文件寄存门路设置,绝对路径 -->    <property name="logs.dir" value="/opt/logs" />    <!-- 日志文件寄存门路设置,tomcat门路 -->    <property name="logs.dir" value="${catalina.base}/logs" />    <!-- 定义日志文件 绝对输出地位 -->      <property name="log_dir" value="log" />    <!-- 日志输入格局设置 -->    <!--     %d{yyyy-MM-dd HH:mm:ss} [%level] - %msg%n      Logger: %logger      Class: %class      File: %file      Caller: %caller      Line: %line      Message: %m      Method: %M      Relative: %relative      Thread: %thread      Exception: %ex      xException: %xEx      nopException: %nopex      rException: %rEx      Marker: %marker      newline:%n    -->    <property name="CUSTOM_LOG_PATTERN"        value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{90} - %msg%n" />    <!-- 上下文名称:<contextName>, 每个logger都关联到logger上下文, 默认上下文名称为“default”。但能够应用<contextName>设置成其余名字,用于辨别不同应用程序的记录。         一旦设置,不能批改。 -->    <contextName>${CONTEXT_NAME}</contextName>    <!-- <appender>是<configuration>的子节点,是负责写日志的组件。 有两个必要属性name和class。name指定appender名称,         class指定appender的实现类。 -->    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">        <!-- 对日志进行格式化。 -->        <encoder>            <pattern>${CUSTOM_LOG_PATTERN}</pattern>            <charset>UTF-8</charset>        </encoder>    </appender>    <appender name="file"        class="ch.qos.logback.core.rolling.RollingFileAppender">        <!-- 按天来回滚,如果须要按小时来回滚,则设置为{yyyy-MM-dd_HH} -->        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">            <fileNamePattern>log/testC.%d{yyyy-MM-dd}.%i.log</fileNamePattern>            <!-- 如果按天来回滚,则最大保留工夫为30天,30天之前的都将被清理掉 -->            <maxHistory>30</maxHistory>            <!-- 按工夫回滚的同时,按文件大小来回滚 -->            <timeBasedFileNamingAndTriggeringPolicy                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">                <maxFileSize>100MB</maxFileSize>            </timeBasedFileNamingAndTriggeringPolicy>        </rollingPolicy>        <!-- 过滤器,只记录WARN级别的日志 -->        <!-- 果日志级别等于配置级别,过滤器会依据onMath 和 onMismatch接管或回绝日志。 -->        <filter class="ch.qos.logback.classic.filter.LevelFilter">            <!-- 设置过滤级别 -->            <level>WARN</level>            <!-- 用于配置合乎过滤条件的操作 -->            <onMatch>ACCEPT</onMatch>            <!-- 用于配置不合乎过滤条件的操作 -->            <onMismatch>DENY</onMismatch>        </filter>        <!-- 日志输入格局 -->        <encoder>            <pattern>${CUSTOM_LOG_PATTERN}</pattern>            <charset>UTF-8</charset>        </encoder>    </appender>     <appender name="log_file"        class="ch.qos.logback.core.rolling.RollingFileAppender">        <!-- 被写入的文件名,能够是绝对目录,也能够是相对目录,如果下级目录不存在会主动创立,没有默认值。 -->        <file>${logs.dir}/logback-test.log</file>        <!-- 依照固定窗口模式生成日志文件,当文件大于20MB时,生成新的日志文件。窗口大小是1到3,当保留了3个归档文件后,将笼罩最早的日志 -->        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">            <!-- 必须蕴含“%i”例如,假如最小值和最大值别离为1和2,命名模式为 mylog%i.log,会产生归档文件mylog1.log和mylog2.log。还能够指定文件压缩选项,例如,mylog%i.log.gz                 或者 没有log%i.log.zip -->            <FileNamePattern>${logs.dir}/logback-test.%i.log</FileNamePattern>            <!-- 窗口索引最小值 -->            <minIndex>1</minIndex>            <!-- 窗口索引最大值 -->            <maxIndex>3</maxIndex>        </rollingPolicy>        <!-- 日志级别过滤器 -->        <filter class="ch.qos.logback.classic.filter.LevelFilter">            <!-- 日志级别过滤器 -->            <level>INFO</level>            <!-- 符合要求的日志级别,过滤,ACCEPT:承受 -->            <onMatch>ACCEPT</onMatch>            <!-- 不符合要求的日志级别,过滤,DENY:回绝 -->            <onMismatch>DENY</onMismatch>        </filter>        <!-- 激活滚动的条件。 -->        <triggeringPolicy            class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">            <!-- 流动文件的大小,默认值是10MB -->            <maxFileSize>30MB</maxFileSize>        </triggeringPolicy>        <!-- 对记录事件进行格式化。 -->        <encoder>            <pattern>${CUSTOM_LOG_PATTERN}</pattern>            <charset>UTF-8</charset>        </encoder>    </appender>     <!-- 异步输入 -->    <appender name="ASYNC_logback" class="ch.qos.logback.classic.AsyncAppender">        <!-- 不失落日志.默认的,如果队列的80%已满,则会抛弃TRACT、DEBUG、INFO级别的日志 -->        <!-- <discardingThreshold>0</discardingThreshold> -->        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->        <!-- <queueSize>256</queueSize> -->        <!-- 增加附加的appender,最多只能增加一个 -->        <appender-ref ref="log_file" />    </appender>    <!-- 指定包输入门路 -->    <!-- 用来设置某一个 包 或者具体的某一个 类 的日志打印级别、以及指定<appender>, name:用来指定受此logger束缚的某一个包或者具体的某一个类。         level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,还有一个特俗值INHERITED或者同义词NULL,代表强制执行下级的级别。如果未设置此属性,那么以后loger将会继承下级的级别。         additivity:是否向下级logger传递打印信息。默认是true。(这个logger的下级就是下面的root) <logger>能够蕴含零个或多个<appender-ref>元素,标识这个appender将会增加到这个logger。 -->    <logger name="org.logback.test" level="DEBUG" additivity="true">        <appender-ref ref="stdout" />    </logger>    <!-- 非凡的<logger>元素,是根logger。只有一个level属性,应为曾经被命名为"root". level:设置打印级别,大小写无关:TRACE,         DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能设置为INHERITED或者同义词NULL。默认是DEBUG。 <root>能够蕴含零个或多个<appender-ref>元素,标识这个appender将会增加到这个loger。 -->    <root>        <level value="WARN" />        <!-- if表达式,须要Janino jar -->        <!-- Janino 2.6.0版本开始,除了janino.jar之外, commons-compiler.jar也须要在类门路中 -->        <if condition='property("system_host").contains("dev")'>            <then>                <appender-ref ref="stdout" />            </then>        </if>        <appender-ref ref="file" />    </root></configuration>

留神:logback如果配置要输入行号,性能会明显降低,如果不是必须,倡议不要配置!

4.2.3、logback应用
package org.example.logback.service;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class LogPrintUtil {    /**log动态常量*/    private static final Logger logger = LoggerFactory.getLogger(LogPrintUtil.class);    public static void main(String[] args){         logger.info("info信息");            logger.warn("warn信息");            logger.error("error信息");    }}

五、SLF4J桥接

仔细的你,会发现下面代码应用时,都应用的是private static final Logger logger = LoggerFactory.getLogger(LogPrintUtil.class)这个,其中都来自org.slf4j包,SLF4J是啥?有什么作用呢?

SLF4J自身并不输入日志,最大的特色是:它能够通过适配的形式挂接不同的日志零碎,属于一个日志接口

如果我的项目适配到log4j就应用log4j日志库进行输入;如果适配到logback就应用logback日志库进行输入;如果适配到log4j2就应用log4j2日志库进行输入。

这样最大的益处,就是当你想将我的项目从log4j换成log4j2的时候,只须要在我的项目pom.xml中进行桥接适配即可,不必批改具体须要打印日志的代码

六、三大支流日志框架性能比拟

介绍了这么多,然而咱们还不晓得三个日志框架的日志输入性能如何,本文以10000条数据进行打印,比拟log4jlog4j2logback日志的输入工夫。

本次测试采纳的是本地电脑(win7),每个电脑的配置不一样,测试的后果也不一样,后果是实在的。

  • 同步输入

  • 异步输入

从测试后果上能够看出:

  • 不倡议生产环境进行控制台输入;
  • 在纯文件输入的环境下,logback的输入优于log4j2,而log4j2要优于log4j,如果要进行生产环境的部署,倡议采纳logback,如果是应用log4j2,倡议应用异步形式进行输入,输入后果根本是实时输入;

最初须要留神的中央是:log有危险,输入需谨慎!

因为输入log过程须要进行磁盘操作,且log4j为了保障log输入过程的线程安全性而应用同步锁,就使得输入log成为很耗时的操作,所以log信息肯定要长篇累牍,不要输入一些无用的log

七、总结

本文次要围绕我的项目中应用到的日志框架进行利用介绍,限于笔者的满腹经纶,对本文内容可能还有了解不到位的中央,如有论述不合理之处还望留言一起探讨。