java 日志框架总结
日志级别
ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
- ALL:最低等级的,用于打开所有日志记录。
- TRACE: designates finer-grained informational events than the DEBUG.Since:1.2.12,很低的日志级别,一般不会使用。
- DEBUG: 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打印一些运行信息。
- INFO: 消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避免打印 过多的日志。
- WARN: 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员的一些提示。
- ERROR: 指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息,如果不想输出太多的日志,可以使用这个级别。
- FATAL: 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。
- OFF: 最高等级的,用于关闭所有日志记录。
常见日志框架之间的关系
log4j,logback,log4j2
log4j的作者(Ceki)写了 log4j 把它捐献给apache基金会,然后他写了支持异步的logback
log4j2发布以后,log4停止维护。
目目前一般认为log4j2效率>logback
slf4j也是Ceki写的
slf4j和Conmon Logging
slf4j 和Conmon Logging 都是日志通用接口层,可以理解成是具体日志的适配器,虽然叫做日志门面感觉和外观模式有关,但是我觉得这里使用的适配器模式,可以理解成具体日志的通用接口。它们必须和具体的日志实现搭配使用,不能独立存在。
spring boot 使用log4j2
spring 默认使用的logback,如果要使用log4j需要排除logback,然后导入log4j
排除logback
<!-- spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.5.5</version>
<exclusions>
<!--排查logback -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
导入log4j2,一般我们还会配合slf4j使用
<!-- log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>2.5.5</version>
</dependency>
spring可以通过修改application.yml,指定日志配置文件的位置
#日志配置
logging:
config: classpath:log4j2.xml #日志配置文件位置
level:
com.lomi.mapper.GoodsMapper: info #部分包下面的日志级别
org.mybatis.spring: info
com.zaxxer.hikari: info
org.redisson: info
log4j2.xml 配置示例
<?xml version="1.0" encoding="UTF-8"?>
<!--
status : 这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,会看到log4j2内部各种详细输出
monitorInterval : Log4j能够自动检测修改配置文件和重新配置本身, 设置间隔秒数。此处表示每隔600秒重读一次配置文件
-->
<Configuration status="OFF" monitorInterval="600" >
<!--日志级别:TRACE < DEBUG < INFO < WARN < ERROR < FATAL-->
<!--如果设置为WARN,则低于WARN的信息都不会输出-->
<Properties>
<!-- 配置日志文件输出目录,此处为项目根目录下的logs文件夹 -->
<Property name="log_home">/log4j2</Property>
<property name="file_name">TestExample</property>
<property name="console_pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{requestId}] [%t] %-5level %logger{36} - %msg %n</property>
<property name="debug_pattern">%d{yyyy-MM-dd 'at' HH:mm:ss z} C:%X{MDC.REQUSETIDKEY} %-5level %class{36} %L %M - %style%msg{red}! %xEx%n</property>
<property name="info_pattern">%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n</property>
<property name="error_pattern">%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n</property>
<property name="error_pattern">%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n</property>
</Properties>
<Appenders>
<!--这个输出控制台的配置-->
<Console name="console" target="SYSTEM_OUT">
<!--控制台只输出level及其以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="TRACE" onMatch="ACCEPT" onMismatch="DENY"/>
<!--日志输出的格式-->
<!--
%d{yyyy-MM-dd HH:mm:ss, SSS} : 日志生产时间,输出到毫秒的时间
%-5level : 输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补0
%c : logger的名称(%logger)
%t : 输出当前线程名称
%p : 日志输出格式
%m : 日志内容,即 logger.info("message")
%n : 换行符
%C : Java类名(%F)appender
%L : 行号
%M : 方法名
%l : 输出语句所在的行数, 包括类名、方法名、文件名、行数
hostName : 本地机器名
hostAddress : 本地ip地址
-->
<PatternLayout pattern="${console_pattern}"/>
</Console>
<!--debug以上的都打印-->
<!--
循环日志文件:日志文件大于阀值的时候,就开始写一个新的日志文件
这个会打印出所有的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档
fileName : 指定当前日志文件的位置和文件名称
filePattern : 指定当发生Rolling时,文件的转移和重命名规则
SizeBasedTriggeringPolicy : 指定当文件体积大于size指定的值时,触发Rolling
DefaultRolloverStrategy : 指定最多保存的文件个数
TimeBasedTriggeringPolicy : 这个配置需要和filePattern结合使用
注意filePattern中配置的文件重命名规则是${file_name}_%d{yyyy-MM-dd}_%i,最小的时间粒度是dd,即天,
TimeBasedTriggeringPolicy指定的size是1,结合起来就是每1天生成一个新文件
-->
<RollingRandomAccessFile name="debugFileAppender" fileName="${log_home}/${file_name}-debug.log"
filePattern="${log_home}/debug/${file_name}-debug-%d{yyyy-MM-dd HH}-%i.log">
<Filters>
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<PatternLayout pattern="${debug_pattern}"/>
<Policies>
<!--文件日期滚动,间隔时间(filePattern里面的最小日期单元的倍数),modulate是true的时候使用的系统时间边界,false的时候使用的好像是启动时间边界-->
<TimeBasedTriggeringPolicy interval="2" modulate="false"/>
<!--单个文件的大小-->
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!--max 20 表示最大生成20个滚动文件,超过的会保留最新的,编号会重名-->
<DefaultRolloverStrategy max="20"/>
</RollingRandomAccessFile>
<!--info以上的都打印-->
<!--filePattern .gz结尾会压缩文件-->
<RollingRandomAccessFile name="infoFileAppender" fileName="${log_home}/${file_name}-info.log"
filePattern="${log_home}/info/${file_name}-info-%d{yyyy-MM-dd}-%i.log.gz">
<Filters>
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<PatternLayout pattern="${info_pattern}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<DefaultRolloverStrategy max="40"/>
</RollingRandomAccessFile>
<!--error以上的都打印-->
<RollingRandomAccessFile name="errorFileAppender" fileName="${log_home}/${file_name}-error.log"
filePattern="${log_home}/error/${file_name}-error-%d{yyyy-MM-dd}-%i.log.gz">
<Filters>
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<PatternLayout pattern="${error_pattern}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<DefaultRolloverStrategy max="20"/>
</RollingRandomAccessFile>
<!--只打印指定级别(warn)-->
<!--正常不会只打印一个级别,都是关心这个级别或者以上级别的日志,这里只是演示可以这么用-->
<RollingRandomAccessFile name="warnOnly" fileName="${log_home}/${file_name}-warnonly.log"
filePattern="${log_home}/warnonly/${file_name}-warnonly-%d{yyyy-MM-dd}-%i.log.gz">
<!--上下限制只取warn级别-->
<Filters>
<ThresholdFilter level="warn" onMatch="NEUTRAL" onMismatch="DENY"/>
<ThresholdFilter level="error" onMatch="DENY" onMismatch="ACCEPT"/>
</Filters>
<PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<DefaultRolloverStrategy max="20"/>
</RollingRandomAccessFile>
<!--配置异步写日志-->
<!-- <Async name="Async">
<AppenderRef ref="ALL"/>
</Async>-->
<!--输出到MongoDB中-->
<!--<NoSql name="databaseAppender">
<MongoDb databaseName="test" collectionName="errorlog" server="localhost" port="27017"/>
</NoSql>-->
</Appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<Loggers>
<!-- 这儿为trace表示什么都可以打印出来了,其他几个级别分别为:TRACE、DEBUG、INFO、WARN、ERROR和FATAL -->
<Root level="INFO">
<appender-ref ref="console"/>
<appender-ref ref="infoFileAppender"/>
<appender-ref ref="errorFileAppender"/>
</Root>
<!--additivity:是否继承父的appender,默认是true继承-->
<logger name="org.springframework" level="INFO" additivity="false">
<appender-ref ref="console"/>
<appender-ref ref="infoFileAppender"/>
<appender-ref ref="errorFileAppender"/>
</logger>
<logger name="org.mybatis" level="debug">
<appender-ref ref="debugFileAppender"/>
</logger>
<Logger name="com.lomi" level="debug">
<appender-ref ref="debugFileAppender"/>
<!--正常不会只打印一个级别,都是关心这个级别或者以上级别的日志-->
<appender-ref ref="warnOnly"/>
</Logger>
<!--java.lang.NoClassDefFoundError: com/lmax/disruptor/EventHandler-->
<!--<AsyncLogger name="com.lomi" level="info" additivity="false">
<AppenderRef ref="Console"/>
</AsyncLogger >-->
<!--输出到NoSQL中-->
<!-- <Logger name="mongoLog" level="trace" additivity="false">
<AppenderRef ref="databaseAppender"/>
</Logger>-->
</Loggers>
</Configuration>
log4j2配置说明
-
Configuration是最外层标签
- status:用于控制log4j自身的日志级别
- monitorInterval: 含义是每隔多少秒重新读取配置文件,可以不重启应用的情况下修改配置
-
Properties: 使用来定义常量,以便在其他配置的时候引用,该配置是可选的,例如定义日志的存放位置
-
Loggers: 定义那些包下面的日志应该怎么输出
- Logger:定义指定包下面的日志应该交给那些Appender输入
- level:大于等于该日志级别的才向下传递
- additivity: 若是additivity设为false,则子Logger只会在自己的appender里输出,而不会在父Logger的appender里输出。
- name: 给 logger去一个名字,一般就是包名倒写(包含当前包和子包,可以精确到类)
- AppenderRef: 指定由那个Appender输入(一个日志会经过logger的level和Appender的filter两次过滤才会有机会输出)
- logger的父子关系: 按照包名的父子关系匹配的父子关系com.xxx的父logger就是com,root是最根上的logger
- Root:如果没有在Logger里面指定的包默认使用那些Appender输入
- Logger:定义指定包下面的日志应该交给那些Appender输入
-
Appenders
-
Appender的类型
- Console 输出到控制台
- File 输入到文件
- RollingRandomAccessFile 输入到滚动文件
- fileName: 初始输入的文件名字,或者说当前日志文件名字,触发滚动以后,把文件复制到归档文件,并且重新开始写入一个新的文件
- filePattern: 文件滚动的时候(跨天,或者文件大小达到限制),新文件的名字模板,如果文件.gz结尾,会压缩历史日志
- Policies:滚动策略
- DefaultRolloverStrategy :文件滚动策略(保留多少个滚动文件),如果文件超过限制,会所有文件编号都-1,然后删除掉编号最小的那个,在新建一个编号位max的文件中写入数据
- TimeBasedTriggeringPolicy: 触发文件滚动是基本时间周期数
- 基本时间周期来自于filePattern里面配置的时间,filePattern里面的%d{yyyy-MM-dd}除以TimeBasedTriggeringPolicy的值就是%i
- SizeBasedTriggeringPolicy: 指定触发文件滚动的文件大小
- NoSql 输入到MongoDB
- Flume 输出到Apache Flume
- Async 指定那些Appender需要异步输出,也可以在 logger处使用 AsyncLogger 指定。
-
Appender的通用属性
-
name: 个appender取一个名字
-
ThresholdFilter: 可以使用 ThresholdFilter直接过滤,也可以使用 Filters 里面在套用 ThresholdFilter 这样的过滤器链过滤
- level:指定日志级别(大于等于当前的基本就是匹配到的)
- onMatch:匹配到的值级别应该怎么处理
- ACCEPT: 直接输入
- DENY:不输出
- NEUTRAL:传递给下一个过滤器
- onMismatch:没有匹配到的应该怎么处理
- ACCEPT: 直接输入
- DENY:不输出
- NEUTRAL:传递给下一个过滤器
-
MarkerFilter:和ThresholdFilter类似,区别在于他是按照标记匹配的,ThresholdFilter是按照日志界别匹配的
#marker是 Flow的 日志才会匹配 <MarkerFilter marker="FLOW" onMatch="DENY" onMismatch="ACCEPT" />
输出FlOW标记的日志
Marker marker = MarkerManager.getMarker("FLOW"); logger.debug(marker,"debug level");
-
PatternLayout:指定输入格式(PatternLayout 继承自Layout,实现了按照正则来输入日志格式)
模式转换字符
转换字符 含义 c LoggerFactory.getLogger( "c.b.a" ) 后面指定的部分,传入class的时候默认是包名+类名
也是Logger的nameC logger对象的全类名,和LoggerFactory.getLogger( "c.b.a" )指定的name没有关系
传入class的时候和小写一样d 使用它输出记录日志的日期,比如 %d{HH:mm:ss,SSS} 或 %d{dd MMM yyyy HH:mm:ss,SSS}。 F 在记录日志时,使用它输出java文件名。
输出:LoggerTest.javal 用它输出生成日志的调用者的位置信息,location的缩写。
输出:com.lomi.logger.LoggerTest.t1(LoggerTest.java:32)L 使用它输出发起日志请求的行号。 m 我们在程序里面控制输入的日志信息,message的缩写。 M 使用它输出发起日志请求的方法名。 n 输出平台相关的换行符。 p 输出日志事件的优先级。和level输入的一样
%-5level:左对齐的5位日志级别,缺位补空格,[%5level]:输出右对齐的5位日志级别,缺位补空格r 使用它输出从构建布局到生成日志事件所花费的时间,以毫秒为单位。 t 输出生成日志事件的线程名。 x 输出和生成日志事件线程相关的 NDC (嵌套诊断上下文)。 X 该字符后跟 MDC 键,比如 X{clientIP} 会输出保存在 MDC 中键 clientIP 对应的值。 xEx x +Ex 的缩写打印异常 % 百分号, %% 会输出一个 %。 格式修饰符
基本格式:
%最小值.最大值 变量: 表示最小保留多少位,最大保留多少位。
省略 .最大致: 最大值不限制
省略 最小值: 最最小值默认0,省略最小值的时候英文句号不能省略,才能区分是最大值还是最小值
默认都是右对齐然,左边加0或裁剪。可以分别使用-号表示对齐对齐方式反转
格式修饰符 删补对齐方向 最小宽度 最大宽度 注释 %20c 右 20 无 少于 20 个字符,左边使用空格补齐,大于20个全量显示 %-20c 左 20 无 少于 20 个字符,右边使用空格补齐,大于20个全量显示 %.30c 右 无 30 如果列名长于 30 个字符,超过部分删除,优先删除左边的。
%-.30c: 表示优先删除右边%20.30c 右(补),右(删) 20 30 如果列名少于 20 个字符,左边使用空格补齐,如果列名长于 30 个字符,从左边开始删除。 %-20.-30c 左(补),左(删) 20 30 如果列名少于 20 个字符,右边使用空格补齐,如果列名长于 30 个字符,右边开始删除。 异步日志:
log4j2中,AsyncAppender采用了ArrayBlockingQueue来保存需要异步输出的日志事件;AsyncLogger则使用了Disruptor框架来实现高吞吐。
AsyncAppender的常用参数
参数名 类型 说明 name String Async Appender的名字。 AppenderRef String 异步调用的Appender的名字,可以配置多个。 blocking boolean 默认为true。如果为true,appender将一直等待直到queue中有空闲;如果为false,当队列满的时候,日志事件将被丢弃。(如果配置了error appender,要丢弃的日志事件将由error appender处理) bufferSize integer 队列中可存储的日志事件的最大数量,默认为128。(源码中为128,Log4j2官网为1024,官网信息有误) 日志颜色
%style{内容表达式}{颜色} #比如 %style{%msg}{red}
spring: output: ansi: enabled: always
修改jvm参数 -Dlog4j.skipJansi=false
用处不大,设置麻烦,直接使用idea插件 grep console 方便的
-
-
spring boot 使用logback
spring boot默认使用的就是 logback
下面是一个logback文件配置文件的例子
<?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">
<!--可以通过%contextName来打印日志上下文名称-->
<contextName>logback</contextName>
<!--属性,key-value格式 使用 ${key}引用-->
<property name="log_home" value="/logback"/>
<property name="file_name" value="TestExample"/>
<property name="console_pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%logger{50}] - %msg%n"/>
<property name="file_pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%logger{50}] - %msg%n"/>
<property name="encode" value="UTF-8"/>
<!--控制台的appender-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>${console_pattern}</Pattern>
<!-- 设置字符集 -->
<charset>${encode}</charset>
</encoder>
</appender>
<!-- 滚动文件只记录debug级别 -->
<appender name="debugFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志文件路径-->
<file>${log_home}/${file_name}-debug.log</file>
<!--日志文件输出格式和编码-->
<encoder>
<pattern>${file_pattern}</pattern>
<charset>${encode}</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log_home}/debug/${file_name}-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--每个日志文件最大10MB-->
<maxFileSize>10MB</maxFileSize>
<!--日志量最大20GB-->
<totalSizeCap>20GB</totalSizeCap>
<!--最大归档文件个数-->
<maxHistory>60</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录debug级别的 -->
<!--LevelFilter 匹配指定类型-->
<!-- ACCEPT 打印-->
<!--DENY 不打印 -->
<!-- NEUTRAL 看下面的过滤器要不要打印 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 滚动文件 记录info级别以上日志 -->
<appender name="infoFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志文件路径-->
<file>${log_home}/${file_name}-info.log</file>
<!--日志文件输出格式和编码-->
<encoder>
<pattern>${file_pattern}</pattern>
<charset>${encode}</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log_home}/info/${file_name}-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--每个日志文件最大10MB-->
<maxFileSize>10MB</maxFileSize>
<!--日志量最大20GB-->
<totalSizeCap>20GB</totalSizeCap>
<!--最大归档文件个数-->
<maxHistory>60</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录debug级别的 -->
<!--ThresholdFilter 匹配指定类型,是确定的类型,不能高于指定界别 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</level>
</filter>
</appender>
<!-- 滚动文件 记录error以上的级别的日志 -->
<appender name="errorFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log_home}/${file_name}-error.log</file>
<encoder>
<pattern>${file_pattern}</pattern>
<charset>${encode}</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log_home}/error/${file_name}-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--每个日志文件最大10MB-->
<maxFileSize>10MB</maxFileSize>
<!--日志量最大20GB-->
<totalSizeCap>20GB</totalSizeCap>
<!--最大归档文件个数-->
<maxHistory>60</maxHistory>
</rollingPolicy>
<!--ThresholdFilter 指定级别一下直接不打印 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!--WARN以上的级别向下决定是否打印,一下的级别直接拒绝-->
<level>ERROR</level>
</filter>
</appender>
<!--全局info,我们关心的包下面开启debug-->
<!-- root 是所有 logger 的父亲 -->
<root level="INFO">
<appender-ref ref="console"/>
<appender-ref ref="infoFileAppender"/>
<appender-ref ref="errorFileAppender"/>
<!--root 和 logger 里面不允许 filter,只能写在 appender里面-->
</root>
<!--additivity:是否继承父的appender,默认是true继承-->
<logger name="org.springframework" level="INFO" additivity="false">
<appender-ref ref="console"/>
<appender-ref ref="infoFileAppender"/>
<appender-ref ref="errorFileAppender"/>
</logger>
<logger name="org.mybatis" level="debug">
<appender-ref ref="debugFileAppender"/>
</logger>
<Logger name="com.lomi" level="debug">
<appender-ref ref="debugFileAppender"/>
</Logger>
</configuration>
logback和log2的用法大同小异,配置文件的区别在于 log4j2
关于日志的几个注意点
-
spring-boot.jar里面有关于logback和log4j2等的一些配置可以include
-
log4j2的滚动日志文件如果filePattern的日期精度在小时以下就不生效了。
-
logger.isDebugEnabled() 之类的方法只是输入的 logger的level是否允许向下过滤和 append是否会输入没关系
-
logger.isDebugEnabled()之类的方法的作用,看下面的代码
@Test public void loggerPrint1(){ //一个耗时的操作 Function<Long,String> getMsg = (i)->{ try { Thread.sleep(i); } catch (InterruptedException e) { throw new RuntimeException(e); } return "返回的json结果"; }; //当trace不可用的时候依旧执行了getMsg方法(耗时1003毫秒) StopWatch stopWatch = new StopWatch(); stopWatch.start(); logger.trace("打印结果1{}",getMsg.apply(1000*1L)); stopWatch.stop(); System.out.println( stopWatch.getLastTaskTimeMillis() ); //当trace不可用的时候不会getMsg方法,可以节省资源(耗时1毫秒) stopWatch.start(); if( logger.isTraceEnabled() ){ logger.trace("打印结果2{}",getMsg.apply(1000*1L)); } stopWatch.stop(); System.out.println( stopWatch.getLastTaskTimeMillis() ); }
结论:
如果日志是直接打印现成的数据,那么没区别,甚至重复判断了2次
如果日志输内容是现成数据,并且这个现生成数据比较耗时,那么一定要先判断日志级别是否可用,这样可以在节省大量资源,异步日志是输入日志的时候异步,生成日志类容还是业务线程干的。
能耍的时候就一定要耍,不能耍的时候一定要学。
--天道酬勤,贵在坚持posted on 2023-04-10 19:55 zhangyukun 阅读(148) 评论(0) 编辑 收藏 举报