日志学习:SLF4J & Log4J2

本文介绍了SLF4J作为日志抽象层的优势,如占位符优化和输出级别,并详细讲解了Log4j2的Appender和Layout,包括日志目的地和格式。此外,还提到了Log4j2的配置方式及XML配置文件中的选项,以及两者的关系。最后,讨论了Log4j2中logger的name机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SLF4J

  • SLF4J 不是一个真正的日志实现,而是一个抽象层,它允许在后台使用任意一个日志类库。如果是在编写供内外部都可以使用的API或者通用类库,那么你真不会希望使用你类库的客户端必须使用你选择的日志类库。
  • SLF4J使代码独立于任意一个特定的日志API(类似iterator?)

优势:

  1. 占位符:{} , 可以替换为对应的值,降低了字符串的链接次数,节省了新建的 String 对象。通过使用SLF4J,你可以在运行时延迟字符串的建立,这意味着只有需要的String对象才被建立。

    logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);

输出级别:

  • ERROR:严重错误、一般是指程序错误
  • WARM:一般警告,如session丢失
  • INFO:一般显示的信息,如登入登出
  • DEBUG:程序的调试信息

**日志输出目的地:**appender

  • org.apache.log4j.ConsoleAppender(控制台)
  • org.apache.log4j.FileAppender(文件)
  • org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
  • org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
  • org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

**日志输出格式:**layout

  • org.apache.log4j.HTMLLayout(以HTML表格形式布局)
  • org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
  • org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
  • org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

日志信息格式符号含义:

使用:

-X号: X信息输出时左对齐;
%p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL,
%d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
%r: 输出自应用启动到输出该log信息耗费的毫秒数
%c: 输出日志信息所属的类目,通常就是所在类的全名
%t: 输出产生该日志事件的线程名
%l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main (TestLog4.java:10)
%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像Java servlets这样的多客户多线程的应用中。
%%: 输出一个”%”字符
%F: 输出日志消息产生时所在的文件名称
%L: 输出代码中的行号
%m: 输出代码中指定的消息,产生的日志具体信息
%n: 输出一个回车换行符,Windows平台为”\r\n”,Unix平台为”\n”输出日志信息换行

  1. maven配置

    <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-api</artifactId>
     <version>1.7.21</version>
    </dependency>
    <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-log4j12</artifactId>
     <version>1.7.21</version>
    </dependency>
  2. 日志相关配置

    • properties 方式

      log4j.rootLogger=info, ServerDailyRollingFile, stdout
      log4j.appender.ServerDailyRollingFile=org.apache.log4j.DailyRollingFileAppender
      log4j.appender.ServerDailyRollingFile.DatePattern='.'yyyy-MM-dd
      log4j.appender.ServerDailyRollingFile.File=logs/notify-subscription.log
      log4j.appender.ServerDailyRollingFile.layout=org.apache.log4j.PatternLayout
      log4j.appender.ServerDailyRollingFile.layout.ConversionPattern=%d - %m%n
      log4j.appender.ServerDailyRollingFile.Append=true
      log4j.appender.stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
      log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p [%c] %m%n
    • XML文件方式

      1. 添加依赖
      <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.1.7</version>
      </dependency>
      <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.1.7</version>
      </dependency>
      1. logback.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <configuration debug="true">
          <!-- 应用名称 -->
          <property name="APP_NAME" value="logtest" />
          <!--日志文件的保存路径,首先查找系统属性-Dlog.dir,如果存在就使用其;否则,在当前目录下创建名为logs目录做日志存放的目录 -->
          <property name="LOG_HOME" value="${log.dir:-logs}/${APP_NAME}" />
          <!-- 日志输出格式 -->
          <property name="ENCODER_PATTERN"
                    value="%d{yyyy-MM-dd  HH:mm:ss.SSS} [%thread] %-5level %logger{80} - %msg%n" />
          <contextName>${APP_NAME}</contextName>
      
          <!-- 控制台日志:输出全部日志到控制台 -->
          <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
              <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                  <Pattern>${ENCODER_PATTERN}</Pattern>
              </encoder>
          </appender>
      
          <!-- 文件日志:输出全部日志到文件 -->
          <appender name="FILE"
                    class="ch.qos.logback.core.rolling.RollingFileAppender">
              <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                  <fileNamePattern>${LOG_HOME}/output.%d{yyyy-MM-dd}.log</fileNamePattern>
                  <maxHistory>7</maxHistory>
              </rollingPolicy>
              <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                  <pattern>${ENCODER_PATTERN}</pattern>
              </encoder>
          </appender>
      
          <!-- 错误日志:用于将错误日志输出到独立文件 -->
          <appender name="ERROR_FILE"
                    class="ch.qos.logback.core.rolling.RollingFileAppender">
              <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                  <fileNamePattern>${LOG_HOME}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
                  <maxHistory>7</maxHistory>
              </rollingPolicy>
              <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                  <pattern>${ENCODER_PATTERN}</pattern>
              </encoder>
              <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                  <level>WARN</level>
              </filter>
          </appender>
      
          <!-- 独立输出的同步日志 -->
          <appender name="SYNC_FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
              <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                  <fileNamePattern>${LOG_HOME}/sync.%d{yyyy-MM-dd}.log</fileNamePattern>
                  <maxHistory>7</maxHistory>
              </rollingPolicy>
              <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                  <pattern>${ENCODER_PATTERN}</pattern>
              </encoder>
          </appender>
      
          <logger name="log.sync" level="DEBUG" addtivity="true">
              <appender-ref ref="SYNC_FILE" />
          </logger>
      
          <root>
              <level value="DEBUG" />
              <appender-ref ref="STDOUT" />
              <appender-ref ref="FILE" />
              <appender-ref ref="ERROR_FILE" />
          </root>
      </configuration>

各个Appender选项

  1. ConsoleAppender

    Threshold=DEBUG:指定日志消息的输出最低层次。
    ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
    Target=System.err:默认情况下是System.out,指定输出控制台

  2. FileAppender

    Threshold=DEBUG:指定日志消息的输出最低层次。
    ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
    File=mylog.txt:指定消息输出到mylog.txt文件。
    Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。

  3. RollingFileAppender

    Threshold=DEBUG:指定日志消息的输出最低层次。
    ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
    File=mylog.txt:指定消息输出到mylog.txt文件。
    Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。
    MaxFileSize=100KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小时,将会自动滚动,即将原来的内容移到mylog.log.1文件。
    MaxBackupIndex=2:指定可以产生的滚动文件的最大数。

关系:

  1. appender是日志文件的设置,有File、FileRolling、Console等,是设定日志文件格式、文件名、日志文件更新的方式
  2. Root、logger 是日志输出对象用于设置日志输出级别,包含appender

Log4j2

使用

  1. maven引入:log4j-core 和 log4j-api

  2. XML文件(log4j2.xml)

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration status="OFF">
       <appenders>
           <Console name="Console" target="SYSTEM_OUT">
               <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
           </Console>
       </appenders>
       <loggers>
           <!--我们只让这个logger输出trace信息,其他的都是error级别-->
           <!--additivity开启的话,由于这个logger也是满足root的(root相当于一个全局配置的logger),所以会被打印两遍。只要配置了多个logger,且additivity 为TRUE时,就会被打印多次,只要级别符合的情况下 -->
    
           <logger name="com.meituan.test.log4j2.Hello" level="trace" additivity="false">
               <appender-ref ref="Console"/>
           </logger>
           <root level="error">
               <appender-ref ref="Console"/>
           </root>
       </loggers>
    </configuration>
  3. 例子

    <?xml version="1.0" encoding="UTF-8"?>
    
    <configuration status="error">
       <!--先定义所有的appender-->
       <appenders>
           <!--这个输出控制台的配置-->
           <Console name="Console" target="SYSTEM_OUT">
               <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
               <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/>
               <!--这个都知道是输出日志的格式-->
               <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
           </Console>
           <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用-->
           <File name="log" fileName="log/test.log" append="false">
               <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
           </File>
    
           <!--这个会打印出所有的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
           <RollingFile name="RollingFile" fileName="logs/app.log"
                        filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
               <PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
               <SizeBasedTriggeringPolicy size="50MB"/>
           </RollingFile>
       </appenders>
       <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
       <loggers>
           <!--建立一个默认的root的logger-->
           <root level="trace">
               <appender-ref ref="RollingFile"/> 
               <appender-ref ref="Console"/>
           </root>
    
       </loggers>
    </configuration>

name机制:

  • 当需要对某个特定的类配置特有的logger时,可以通过packageName.ClassName 来进行命名 ,因为生成Logger对象的时候,都是通过 Class.class.getName()。而包之间可以继承,也就是说com.meituan定制的logger 也适用于com.meituan.test包下的类。而 root 没有name属性,它相当于一个全局的logger,所有的类的logger都适用于它。

参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值