• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

还在用log.isDebugEnabled()判断debug日志你out了

武飞扬头像
alan2hl
帮助1

作为程序员,程序开发写代码一定少不了记录日志(没日志的代码都是耍流氓!)今天记录一下自己新搭建spring-boot项目后对日志的思考。

  起因:项目是一个无页面,通过直接访问数据库,然后调用第三方api实现数据上传的简单应用。因为项目很小,所以在项目完成后,为了使jar包的大小更小(强迫症,想把无用的maven引用全部去掉),所以打包完成后对lib下的jar包进行查看,发现关于log的jar包很多,由此引发联想,难道一个简单的日志都要用这么多的jar包吗?

学新通

 查看自己的代码,发现只用到了如下代码

学新通

 先说结论

  1. commons-logging和slf4j是java中的日志门面,即它们提供了一套通用的接口,具体的实现可以由开发者自由选择。log4j和logback则是具体的日志实现方案。这是典型的门面模式

  2. 比较常用的搭配是commons-logging log4j,slf4j logback

    spring默认使用commons-logging log4j

    spring-boot默认使用slf4j logback

  3. SLF4J是编译时绑定到具体的日志框架,性能优于采用运行时搜寻的方式的commons-logging

  4. 不需要使用logger.isDebugEnabled()来解决日志因为字符拼接产生的性能问题

      1.  
        logger.info("my name is {}", "medusar");
      2.  
        logger.info("my name is " "medusar");

      在效率上,第一行比第二行更高,因为如果当前日志级别是ERROR,第一行不会进行字符串拼接,而第二行,无论日志级别是什么,都会先进行字符串拼接。

    1. 所以为了解决这个问题,commons-logging等框架提供了下面的方式:

      1.  
        if (log.isDebugEnabled()){
      2.  
        log.debug("dddd" "eee");
      3.  
        }

所以说,现在使用spring-boot开发,已经不需要再使用log.isDebugEnabled()来判断debug了

下面我们顺藤摸瓜开始今天的寻根之旅!

先看下slf4j的实现

学新通

 配合第一张图,可知:

  1. 可单独只使用slf4j
    
  2. logback就是默认slf4j的实现(logback-classic.jar,logback-core.jar)
    
  3. log4j的slf4j实现要通过log4j-to-slf4j.jar
    
  4. 将java.util.logging的日志桥接到slf4j实现要通过jul-to-slf4j-1.7.36.jar
    

这些包的目的是什么?

答案是:统一日志记录。a(slf4j logback): Spring(commons-logging)、Hibernate(jboss-logging)、MyBatis、xxxx等等,每个框架都是自己使用的日志框架,如何统一他们的?

  1. 将系统中其他日志框架先排除出去;
  2. 用中间包来替换原有的日志框架;
  3. 我们导入slf4j其他的实现

说白了就是,其他的框架还以为他们用的还是自己的日志框架,而实际上,他们的日志框架已经不存在了,存在的是slf4j替换过后的对原有框架的实现的中间包

形象的比喻是:春秋战国时期,各个诸侯纷纷自立为王,他们的臣子都拥戴自己的大王,忽然有一天,秦国的影密卫,将其中几个大王偷偷换成了自己的亲信,让他们代替这几个诸侯国的大王,然后将真正的大王们都杀了,做的神不知鬼不觉,他们的大臣们依然死心塌地的拥戴着自己的大王,并不知道大王已经是替身;实际上他们的大王已经都听命于秦国。表面是各国纷乱,而实际上他们已经实现了统一,都归秦国管理!!!

每一个日志的实现框架都有自己的配置文件。使用slf4j以后,配置文件还是做成日志实现框架自己本身的配置文件;

使用logback 配置文件是:

logback.xml:直接就被日志框架识别了。

logback-spring.xml:日志框架就不直接加载日志的配置项,由 SpringBoot 解析日志配置,可以使用 SpringBoot 的高级 Profile 功能。

logback-spring.xml完整配置文件:

  1.  
    <!--
  2.  
    logback的语法可以描述为:<configuration>元素包含零个或多个<appender>元素,后跟零个或多个<logger>元素,后跟至多一个<root>元素。
  3.  
    configuration :根标签
  4.  
    属性:
  5.  
    scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true,在logback-spring.xml使用时可能会报错,所以不能一起使用
  6.  
    scanPeriod:默认情况下,将每分钟扫描一次配置文件的更改。可以以毫秒、秒、分钟或小时为单位指定值。未指定时间单位为毫秒
  7.  
    -->
  8.  
    <configuration>
  9.  
    <!-- 用来引入外部资源文件,resource:表示资源路径 -->
  10.  
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
  11.  
    <!-- 每个logger都关联到logger上下文,默认上下文名称为default,可以设置成其他名字,用于区分不同应用程序的记录,
  12.  
    一旦设置,不能修改,可以通过%contextName来打印日志上下文名称 -->
  13.  
    <contextName>logback</contextName>
  14.  
     
  15.  
    <!-- 日志级别:TRACE, DEBUG, INFO, WARN, ERROR, ALLOFF -->
  16.  
    <!-- 自定义变量,使用${}来使用变量
  17.  
    name:变量名
  18.  
    value:变量值
  19.  
    scope:变量的作用范围-->
  20.  
    <property name="log_path" value="log" scope="context" />
  21.  
    <property name="log_pattern" value="%clr(%d{yy-MM-dd hh-mm-ss.SSS}){yellow} [%clr(%t){magenta}] [%clr(%p)] %clr(%C{1}.%M:%L) |:%clr(%m%n){blue}"/>
  22.  
    <property name="log_fileNamePattern" value="-%d{yyyy-MM-dd}.%i.log"/>
  23.  
    <property name="log_maxFileSize" value="10MB"/>
  24.  
    <property name="log_maxHistory" value="15"/>
  25.  
    <property name="dev_log_level" value="DEBUG" />
  26.  
    <property name="test_log_level" value="DEBUG" />
  27.  
    <property name="prod_log_level" value="INFO" />
  28.  
     
  29.  
    <!-- 输出到控制台 -->
  30.  
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  31.  
    <encoder charset="UTF-8">
  32.  
    <pattern>${log_pattern}</pattern>
  33.  
    </encoder>
  34.  
    </appender>
  35.  
     
  36.  
    <!--
  37.  
    appender标签:定义日志输出策略,包括日志文件名称,输出格式,日志滚动策略,日志文件大小等等,具体看下面说明
  38.  
    属性:
  39.  
    name:策略名称
  40.  
    class:策略类型
  41.  
    控制台输出:ch.qos.logback.core.ConsoleAppender
  42.  
    文件滚动输出:ch.qos.logback.core.rolling.RollingFileAppender
  43.  
    标签:
  44.  
    <file>:日志输出的路径及文件名
  45.  
    <encoder>:设置日志输出的格式和编码
  46.  
    <rollingPolicy>:设置日志切割策略
  47.  
    <fileNamePattern>:定义了日志的切割方式,切割后存放的文件名。
  48.  
    <maxFileSize>:触发策略,指定单个日志文件的上限大小,超限就会进行切割。
  49.  
    <maxHistory>:日志文件保留天数
  50.  
    <filter>:过滤规则
  51.  
    具体可看:http://logback.qos.ch/manual/configuration.html
  52.  
    http://logback.qos.ch/manual/appenders.html
  53.  
    -->
  54.  
    <!-- 时间滚动输出 系统日志 -->
  55.  
    <appender name="SYSTEM" class="ch.qos.logback.core.rolling.RollingFileAppender">
  56.  
    <file>${log_path}/app.log</file>
  57.  
    <encoder>
  58.  
    <pattern>${log_pattern}</pattern>
  59.  
    <charset>UTF-8</charset>
  60.  
    </encoder>
  61.  
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
  62.  
    <fileNamePattern>${logpath}/info/app${log_fileNamePattern}</fileNamePattern>
  63.  
    <maxFileSize>${log_maxFileSize}</maxFileSize>
  64.  
    <maxHistory>${log_maxHistory}</maxHistory>
  65.  
    </rollingPolicy>
  66.  
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
  67.  
    <level>DEBUG</level>
  68.  
    </filter>
  69.  
    </appender>
  70.  
     
  71.  
    <!-- sql输出到sql.log文件 -->
  72.  
    <appender name="SQL" class="ch.qos.logback.core.rolling.RollingFileAppender">
  73.  
    <file>${log_path}/sql.log</file>
  74.  
    <encoder charset="UTF-8">
  75.  
    <pattern>${log_pattern}</pattern>
  76.  
    </encoder>
  77.  
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
  78.  
    <fileNamePattern>${log_path}/sql-${log_fileNamePattern}</fileNamePattern>
  79.  
    <maxFileSize>${log_maxFileSize}</maxFileSize>
  80.  
    <maxHistory>${log_maxHistory}</maxHistory>
  81.  
    </rollingPolicy>
  82.  
    </appender>
  83.  
     
  84.  
    <!-- logger:记录器用来指定某一个包或者具体的类的日志打印级别。
  85.  
    name:指定某个包或者具体的类
  86.  
    level:指定日志输出级别。
  87.  
    additivity:如果没有指定level值,是否从最近的父标签继承level值,值为truefalse-->
  88.  
    <logger name="org.springframework" level="WARN" />
  89.  
    <logger name="org.apache" additivity="false" level="WARN" />
  90.  
    <logger name="org.mybatis" additivity="false" level="DEBUG" />
  91.  
     
  92.  
    <!-- 测试环境 -->
  93.  
    <springProfile name="test">
  94.  
    <root level="${test_log_level}">
  95.  
    <appender-ref ref="CONSOLE" />
  96.  
    </root>
  97.  
    </springProfile>
  98.  
     
  99.  
    <!-- 开发环境 -->
  100.  
    <springProfile name="dev">
  101.  
    <root level="${dev_log_level}">
  102.  
    <appender-ref ref="CONSOLE" />
  103.  
    </root>
  104.  
    </springProfile>
  105.  
     
  106.  
    <!-- 生产环境 -->
  107.  
    <springProfile name="prod">
  108.  
    <logger name="com.boot.sql" level="DEBUG" additivity="false">
  109.  
    <appender-ref ref="SQL" />
  110.  
    </logger>
  111.  
    <root level="${prod_log_level}">
  112.  
    <appender-ref ref="SYSTEM" />
  113.  
    </root>
  114.  
    </springProfile>
  115.  
     
  116.  
    </configuration>
  117.  
     
学新通

使用log42 配置文件是(pom排除其他,引入中间包):

log4j2.xml

log4j2-spring.xml

使用jul 配置文件是(pom排除其他,引入中间包,存在已知的类加载问题,这些问题会导致从“可执行 jar”运行时出现问题。建议在从“可执行 jar”运行时尽可能避免使用。):

logging.properties

  补充,以前我们使用spring的时候,Logging是spring中唯一强制的外部依赖,spring中默认使用的日志是commons-logging,简称JCL,这里说的强制性,是因为在spring-core这个模块中引入了该依赖。不过,引入了该依赖,也无需做任何其他的配置,它是日志门面,它内部会有自己的算法去找日志门面的实现类,比如log4j,如果说没有引入其他日志依赖,它默认就会去找JDK自带的java.util.logging简称jul作为其日志实现类

log4j1.x版本已经停止更新了,log4j2.x习惯性叫做`log4j2`。(大家还记得前段时间关于log4j漏洞的事情吧)

更换spring的common-logging日志系统 依赖配置,排除commons-logging

  1.  
    <dependency>
  2.  
    <groupId>org.springframework</groupId>
  3.  
    <artifactId>spring-orm</artifactId>
  4.  
    <exclusions>
  5.  
    <exclusion>
  6.  
    <groupId>commons-logging</groupId>
  7.  
    <artifactId>commons-logging</artifactId>
  8.  
    </exclusion>
  9.  
    </exclusions>
  10.  
    </dependency>

这个时候如果运行程序会抛异常,因为我们把 Spring 依赖的 commons-logging 排除了, 而这个依赖是必须有的,不是可选的。

加入转换包

这个转换包就相当于我们上面说的那个转换器,spring会调用jcl-over-slf4j,spring以为调用的还是commons-logging,但是实际上commons-logging已经被我们删除掉了,并且jcl-over-slf4j还可以将输出转换为slf4j类型的输出,又因为我们前面引入了logback的依赖,lagback是slf4j的实现,所以最终输出的就是logback的日志系统

  1.  
    <!-- 其他日志框架的中间转换包 -->
  2.  
    <dependency>
  3.  
    <groupId>org.slf4j</groupId>
  4.  
    <artifactId>jcl-over-slf4j</artifactId>
  5.  
    </dependency>

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfkfkbg
系列文章
更多 icon
同类精品
更多 icon
继续加载