1.市面上的日志框架

JUL(java util logging)、logback、log4j、log4j2
JCL(Jakarta Commons Logging)、slf4j( Simple Logging Facade for Java)
日志门面
JCL、slf4j
日志实现
JUL、logback、log4j、log4j2

当初日志的门面根本对立都是应用的slf4j,而日志实现的话能够抉择我log4j2或者logback,这里须要留神一下,slf4j、log4j、logback这三个是出自同一个人,而log4j2则是Apache的。

2.SpringBoot中的默认日志框架

SpringBoot中默认应用SLF4J和Logback。

3.SpringBoot中日志框架的应用

在开发的时候,日志记录办法的应用,不应该间接调用日志的实现类,而是调用日志的形象层的办法。

案例:

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的官网上的各种实现关系:

引入日志框架如何解决抵触:

当利用的其余jar中有其余的日志实现,就会导致抵触,就须要用两头的jar进行替换,才能够解决,下图就是slf4j官网的抵触的解决图。

如何让利用的中jar对立应用slf4j(即如上图展现):

  1. 将零碎中其余日志框架先排除进来;
  2. 用两头包来替换原有的日志框架;
  3. 咱们导入slf4j其余的实现(咱们本人想用的实现)

3.1 SpringBoot中的日志关系

SpringBoot应用它来做日志性能:

当咱们引入springboot的web模块时,就引入这个依赖:

<dependency>   <groupId>org.springframework.boot</groupId>   <artifactId>spring‐boot‐starter‐logging</artifactId></dependency>

底层依赖关系:

总结:

1)、SpringBoot底层也是应用slf4j+logback的形式进行日志记录
2)、SpringBoot也把其余的日志都替换成了slf4j;
3)、两头替换包的引入

两头替换包的简略案例:

@SuppressWarnings("rawtypes")public abstract class LogFactory {static String UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J ="http://www.slf4j.org/codes.html#unsupported_operation_in_jcl_over_slf4j";static LogFactory logFactory = new SLF4JLogFactory();

他在代码中做了替换,包名还是和你原来应用的包名一样,尽管你应用的还是原来的,然而真正的实现类曾经被替换了。

4)、如果咱们要引入其余框架?肯定要把这个框架的默认日志依赖移除掉

eg:

Spring框架用的是commons-logging;

<dependency>    <groupId>org.springframework</groupId>    <artifactId>spring‐core</artifactId>    <exclusions>        <exclusion>            <groupId>commons‐logging</groupId>            <artifactId>commons‐logging</artifactId>        </exclusion>    </exclusions></dependency>

SpringBoot能主动适配所有的日志,而且底层应用slf4j+logback的形式记录日志,引入其余框架的时候,只须要
把这个框架依赖的日志框架排除掉即可;

3.2 SpringBoot中日志的配置与应用

1. 默认配置

SpringBoot默认帮咱们配置好了日志;咱们间接启动我的项目就能够看到控制台有日志输入。

    //记录器    Logger logger = LoggerFactory.getLogger(getClass());    @Test    public void contextLoads() {        //日志的级别;        //由低到高 trace<debug<info<warn<error        //能够调整输入的日志级别;日志就只会在这个级别以当前的高级别失效        logger.trace("这是trace日志...");        logger.debug("这是debug日志...");        //SpringBoot默认给咱们应用的是info级别的,没有指定级别的就用SpringBoot默认规定的级别;root级别        logger.info("这是info日志...");        logger.warn("这是warn日志...");        logger.error("这是error日志...");    }

日志输入格局:

%d示意日期工夫,%thread示意线程名,%‐5level:级别从左显示5个字符宽度%logger{50} 示意logger名字最长50个字符,否则依照句点宰割。%msg:日志音讯,%n是换行符‐‐>%d{yyyy‐MM‐dd HH:mm:ss.SSS} [%thread] %‐5level %logger{50} ‐ %msg%n

2.批改日志的默认配置

在springboot的配置文件中批改默认配置

# 指定某个包下的类的日志输入级别logging.level.com.njit=trace# 设置springboot默认的日志级别,springboot默认的日志级别就是root,这里指定root的具体级别# logging.level.root=warn# 不指定门路在以后我的项目下生成springboot.log日志# 能够指定残缺的门路;#logging.file=D:/springboot.log# 在以后磁盘的根门路下创立spring文件夹和外面的log文件夹;应用 spring.log 作为默认文件logging.path=/spring/log# 在控制台输入的日志的格局logging.pattern.console=%d{yyyy‐MM‐dd} [%thread] %‐5level %logger{50} ‐ %msg%n# 指定文件中日志输入的格局logging.pattern.file=%d{yyyy‐MM‐dd} === [%thread] === %‐5level === %logger{50} ==== %msg%n

注:如果logging.path 和 logging.file同时存在,则以logging.file为准

通过本人的配置文件笼罩默认的配置

springboot中的默认配置文件在你引入的springboot的依赖下的logging目录下,有log4j2和logback的默认配置:

如果你在给类门路下放上每个日志框架本人的配置文件即可;SpringBoot就不应用他默认配置的了

logback.xml:间接就被日志框架辨认了;
logback-spring.xml:日志框架就不间接加载日志的配置项,由SpringBoot解析日志配置,能够应用SpringBoot的高级Profile性能

<springProfile name="staging"><!‐‐ configuration to be enabled when the "staging" profile is active ‐‐>能够指定某段配置只在某个环境下失效</springProfile>

比方,在dev环境输入的格局和非dev环境的格局不同,能够指定不同的:

<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><!‐‐日志输入格局:%d示意日期工夫,%thread示意线程名,%‐5level:级别从左显示5个字符宽度%logger{50} 示意logger名字最长50个字符,否则依照句点宰割。%msg:日志音讯,%n是换行符‐‐><layout class="ch.qos.logback.classic.PatternLayout"><springProfile name="dev"><pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ‐‐‐‐> [%thread] ‐‐‐> %‐5level%logger{50} ‐ %msg%n</pattern></springProfile><springProfile name="!dev"><pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ==== [%thread] ==== %‐5level%logger{50} ‐ %msg%n</pattern></springProfile></layout></appender>

如果应用logback.xml作为日志配置文件,还要应用profile性能,会有以下谬误
no applicable action for [springProfile]

3.logback的配置文件参考

logback会顺次读取以下类型配置文件:
  • logback.groovy
  • logback-test.xml
  • logback.xml 如果均不存在会采纳默认配置
logback组件之间的关系
  1. Logger:日志的记录器,把它关联到利用的对应的context上后,次要用于寄存日志对象,也

能够定义日志类型、级别。

  1. Appender:用于指定日志输入的目的地,目的地能够是控制台、文件、数据库等等。
  2. Layout:负责把事件转换成字符串,格式化的日志信息的输入。在logback中Layout对象被封

装在encoder中。

根本配置信息

<?xml version="1.0" encoding="UTF-8"?><configuration>    <!--    日志输入格局:    %-5level    %d{yyyy-MM-dd HH:mm:ss.SSS}日期    %c类的残缺名称    %M为method    %L为行号    %thread线程名称    %m或者%msg为信息    %n换行    -->    <!--格式化输入:%d示意日期,%thread示意线程名,%-5level:级别从左显示5个字符宽度    %msg:日志音讯,%n是换行符-->    <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %c [%thread]%-5level %msg%n"/>    <!--    Appender: 设置日志信息的去向,罕用的有以下几个    ch.qos.logback.core.ConsoleAppender (控制台)    ch.qos.logback.core.rolling.RollingFileAppender (文件大小达到指定尺    寸的时候产生一个新文件)    ch.qos.logback.core.FileAppender (文件)    -->    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">        <!--输入流对象 默认 System.out 改为 System.err-->        <target>System.err</target>        <!--日志格局配置-->        <encoder                class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">            <pattern>${pattern}</pattern>        </encoder>    </appender>    <!--    用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。    <loger>仅有一个name属性,一个可选的level和一个可选的addtivity属性    name:    用来指定受此logger束缚的某一个包或者具体的某一个类。    level:    用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和    OFF,    如果未设置此属性,那么以后logger将会继承下级的级别。    additivity:    是否向下级loger传递打印信息。默认是true。    <logger>能够蕴含零个或多个<appender-ref>元素,标识这个appender将会增加到这个    logger    -->    <!--    也是<logger>元素,然而它是根logger。默认debug    level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL    和 OFF,    <root>能够蕴含零个或多个<appender-ref>元素,标识这个appender将会增加到这个    logger。    -->    <root level="ALL">        <appender-ref ref="console"/>    </root></configuration>

FileAppender配置

<?xml version="1.0" encoding="UTF-8"?><configuration>    <!-- 自定义属性 能够通过${name}进行援用-->    <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c %M %L [%thread] %m %n"/>    <!--    日志输入格局:    %d{pattern}日期    %m或者%msg为信息    %M为method    %L为行号    4. RollingFileAppender配置    %c类的残缺名称    %thread线程名称    %n换行    %-5level    -->    <!-- 日志文件寄存目录 -->    <property name="log_dir" value="d:/logs"></property>    <!--控制台输入appender对象-->    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">        <!--输入流对象 默认 System.out 改为 System.err-->        <target>System.err</target>        <!--日志格局配置-->        <encoder                class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">            <pattern>${pattern}</pattern>        </encoder>    </appender>    <!--日志文件输入appender对象-->    <appender name="file" class="ch.qos.logback.core.FileAppender">        <!--日志格局配置-->        <encoder                class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">            <pattern>${pattern}</pattern>        </encoder>        <!--日志输入门路-->        <file>${log_dir}/logback.log</file>    </appender>    <!-- 生成html格局appender对象 -->    <appender name="htmlFile" class="ch.qos.logback.core.FileAppender">        <!--日志格局配置-->        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">            <layout class="ch.qos.logback.classic.html.HTMLLayout">                <pattern>%level%d{yyyy-MM-dd                    HH:mm:ss}%c%M%L%thread%m                </pattern>            </layout>        </encoder>        <!--日志输入门路-->        <file>${log_dir}/logback.html</file>    </appender>    <!--RootLogger对象-->    <root level="all">        <appender-ref ref="console"/>        <appender-ref ref="file"/>        <appender-ref ref="htmlFile"/>    </root></configuration>

RollingFileAppender配置

<?xml version="1.0" encoding="UTF-8"?><configuration>    <!-- 自定义属性 能够通过${name}进行援用-->    <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c %M %L [%thread] %m %n"/>    <!--    日志输入格局:    %d{pattern}日期    %m或者%msg为信息    %M为method    %L为行号    %c类的残缺名称    %thread线程名称    %n换行    %-5level    -->    <!-- 日志文件寄存目录 -->    <property name="log_dir" value="d:/logs"></property>    <!--控制台输入appender对象-->    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">        <!--输入流对象 默认 System.out 改为 System.err-->        <target>System.err</target>        <!--日志格局配置-->        <encoder                class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">            <pattern>${pattern}</pattern>        </encoder>    </appender>    <!-- 日志文件拆分和归档的appender对象-->    <appender name="rollFile"              class="ch.qos.logback.core.rolling.RollingFileAppender">        <!--日志格局配置-->        <encoder                class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">            <pattern>${pattern}</pattern>        </encoder>        <!--日志输入门路-->        <file>${log_dir}/roll_logback.log</file>        <!--指定日志文件拆分和压缩规定-->        <rollingPolicy                class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">            <!--通过指定压缩文件名称,来确定宰割文件形式-->            <fileNamePattern>${log_dir}/rolling.%d{yyyy-MM-                dd}.log%i.gz</fileNamePattern>            <!--文件拆分大小-->            <maxFileSize>1MB</maxFileSize>        </rollingPolicy>    </appender>    <!--RootLogger对象-->    <root level="all">        <appender-ref ref="console"/>        <appender-ref ref="rollFile"/>    </root></configuration>

Filter和异步日志配置

<?xml version="1.0" encoding="UTF-8"?><configuration>    <!-- 自定义属性 能够通过${name}进行援用-->    <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c %M%L [%thread] %m %n"/>    <!--    日志输入格局:    %d{pattern}日期    %m或者%msg为信息    %M为method    %L为行号    %c类的残缺名称    %thread线程名称    %n换行    %-5level    -->    <!-- 日志文件寄存目录 -->    <property name="log_dir" value="d:/logs/"></property>    <!--控制台输入appender对象-->    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">        <!--输入流对象 默认 System.out 改为 System.err-->        <target>System.err</target>        <!--日志格局配置-->        <encoder                class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">            <pattern>${pattern}</pattern>        </encoder>    </appender>    <!-- 日志文件拆分和归档的appender对象-->    <appender name="rollFile"              class="ch.qos.logback.core.rolling.RollingFileAppender">        <!--日志格局配置-->        <encoder                class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">            <pattern>${pattern}</pattern>        </encoder>        <!--日志输入门路-->        <file>${log_dir}roll_logback.log</file>        <!--指定日志文件拆分和压缩规定-->        <rollingPolicy                class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">            <!--通过指定压缩文件名称,来确定宰割文件形式-->            <fileNamePattern>${log_dir}rolling.%d{yyyy-MM-                dd}.log%i.gz</fileNamePattern>            <!--文件拆分大小-->            <maxFileSize>1MB</maxFileSize>        </rollingPolicy>        <!--filter配置-->        <filter class="ch.qos.logback.classic.filter.LevelFilter">            <!--设置拦挡日志级别-->            <level>error</level>            <onMatch>ACCEPT</onMatch>            6. 官网提供的log4j.properties转换成logback.xml            https://logback.qos.ch/translator/            3.3 logback-access的应用            logback-access模块与Servlet容器(如Tomcat和Jetty)集成,以提供HTTP拜访日志性能。咱们能够使            用logback-access模块来替换tomcat的拜访日志。            1. 将logback-access.jar与logback-core.jar复制到$TOMCAT_HOME/lib/目录下            2. 批改$TOMCAT_HOME/conf/server.xml中的Host元素中增加:            3. logback默认会在$TOMCAT_HOME/conf下查找文件 logback-access.xml            <onMismatch>DENY</onMismatch>        </filter>    </appender>    <!--异步日志-->    <appender name="async" class="ch.qos.logback.classic.AsyncAppender">        <appender-ref ref="rollFile"/>    </appender>    <!--RootLogger对象-->    <root level="all">        <appender-ref ref="console"/>        <appender-ref ref="async"/>    </root>    <!--自定义logger additivity示意是否从 rootLogger继承配置-->    <logger name="com.itheima" level="debug" additivity="false">        <appender-ref ref="console"/>    </logger></configuration>

4.log4j2的配置文件参考

Apache Log4j 2是对Log4j的升级版,参考了logback的一些优良的设计,并且修复了一些问题,因而带来了一些重大的晋升,次要有:

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

log4j2默认加载classpath下的 log4j2.xml 文件中的配置

<?xml version="1.0" encoding="UTF-8"?><Configuration status="warn" monitorInterval="5">    <properties>        <property name="LOG_HOME">D:/logs</property>    </properties>    4.3 Log4j2异步日志    异步日志    log4j2最大的特点就是异步日志,其性能的晋升次要也是从异步日志中受害,咱们来看看如何应用    log4j2的异步日志。    同步日志    <Appenders>        <Console name="Console" target="SYSTEM_OUT">            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n"/>        </Console>        <File name="file" fileName="${LOG_HOME}/myfile.log">            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l%c{36} - %m%n"/>        </File>        <RandomAccessFile name="accessFile" fileName="${LOG_HOME}/myAcclog.log">            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l%c{36} - %m%n"/>        </RandomAccessFile>        <RollingFile name="rollingFile" fileName="${LOG_HOME}/myrollog.log"                     filePattern="D:/logs/$${date:yyyy-MM-dd}/myrollog-%d{yyyy-MM-dd-HH-mm}-%i.log">            <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l%c{36} - %msg%n"/>            <Policies>                <OnStartupTriggeringPolicy/>                <SizeBasedTriggeringPolicy size="10 MB"/>                <TimeBasedTriggeringPolicy/>            </Policies>            <DefaultRolloverStrategy max="30"/>        </RollingFile>    </Appenders>    <Loggers>        <Root level="trace">            <AppenderRef ref="Console"/>        </Root>    </Loggers></Configuration>

5.log4j2的异步日志

log4j2最大的特点就是异步日志,其性能的晋升次要也是从异步日志中受害,咱们来看看如何应用log4j2的异步日志。

  • 同步日志示意图

  • 异步日志示意图

Log4j2提供了两种实现日志的形式,一个是通过AsyncAppender,一个是通过AsyncLogger,别离对应后面咱们说的Appender组件和Logger组件。
留神:配置异步日志须要增加依赖:

<!--异步日志依赖--><dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.3.4</version></dependency>
5.1. AsyncAppender形式
<?xml version="1.0" encoding="UTF-8"?><Configuration status="warn">    <properties>        <property name="LOG_HOME">D:/logs</property>    </properties>    <Appenders>        <File name="file" fileName="${LOG_HOME}/myfile.log">            <PatternLayout>                <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>            </PatternLayout>        </File>        <Async name="Async">            <AppenderRef ref="file"/>        </Async>    </Appenders>    <Loggers>        <Root level="error">            <AppenderRef ref="Async"/>        </Root>    </Loggers></Configuration>
5.2. AsyncLogger形式

AsyncLogger才是log4j2 的重头戏,也是官网举荐的异步形式。它能够使得调用Logger.log返回的更快。你能够有两种抉择:全局异步和混合异步。

  • 全局异步就是,所有的日志都异步的记录,在配置文件上不必做任何改变,只须要增加一个log4j2.component.properties 配置;
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
  • 混合异步就是,你能够在利用中同时应用同步日志和异步日志,这使得日志的配置形式更加灵便。
<?xml version="1.0" encoding="UTF-8"?><Configuration status="WARN">    <properties>        <property name="LOG_HOME">D:/logs</property>    </properties>    <Appenders>        <File name="file" fileName="${LOG_HOME}/myfile.log">            <PatternLayout>                <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>            </PatternLayout>        </File>        <Async name="Async">            <AppenderRef ref="file"/>        </Async>    </Appenders>    <Loggers>        <AsyncLogger name="com.njit" level="trace"                     includeLocation="false" additivity="false">            <AppenderRef ref="file"/>        </AsyncLogger>        <Root level="info" includeLocation="true">            <AppenderRef ref="file"/>        </Root>    </Loggers></Configuration>

如上配置: com.njit日志是异步的,root日志是同步的。

应用异步日志须要留神的问题:

  1. 如果应用异步日志,AsyncAppender、AsyncLogger和全局日志,不要同时呈现。性能会和AsyncAppender统一,降至最低。
  2. 设置includeLocation=false ,打印地位信息会急剧升高异步日志的性能,比同步日志还要慢。