• logback--进阶--04--配置


    logback–进阶–04–配置


    代码位置

    https://gitee.com/DanShenGuiZu/learnDemo/tree/master/logback-learn
    
    • 1

    1、加载配置的步骤

    1.1、步骤

    步骤1

    Logback 尝试在 classpath 中找一个名为 logback-test.xml 的文件 。

    步骤2

    如果找不到此类文件,则 logback 尝试在 classpath 中找一个名为 logback.groovy 的文件 。

    步骤3

    如果找不到这样的文件,它将在 classpath 中找一个名为 logback.xml 的文件。

    步骤4

    如果还没有找到这样的文件, ServiceLoader会通过 META-INF\services\ch.qos.logback.classic.spi.Configurator 加载 com.qos.logback.classic.spi.Configurator 接口的实现类。

    步骤5

    1. 如果以上方法均未成功,则 logback 将使用 BasicConfigurator 进行自动配置,这会将日志输出定向到控制台。
      1. 调用 BasicConfigurator ,创建一个最小化配置。
      2. 最小化配置由一个关联到根 logger 的 ConsoleAppender 组成。输出用模式为 %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 的 PatternLayoutEncoder 进行格式化。
    2. 默认情况下,为 root logger 分配了 DEBUG 级别。

    1.2、案例1

    演示没有配置文件,logback 使用默认配置的效果

    1.2.1、代码

    public class MyApp1 {
        private static final Logger LOGGER = LoggerFactory.getLogger(MyApp1.class);
        public static void main(String[] args) {
            LOGGER.info("我是在 MyApp1 类中,使用info级别打印日志");
            User user = new User();
            user.say();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    
    public class User {
        private static final Logger LOGGER = LoggerFactory.getLogger(User.class);
    
        public void say() {
            LOGGER.debug("我是在 User 类中,使用debug级别打印日志");
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    1.2.2、运行程序,控制台输出日志如下

    10:30:25.543 [main] INFO fei.zhou.logbacklearn.business.test.MyApp1 - 我是在 MyApp1 类中,使用info级别打印日志
    10:30:25.563 [main] DEBUG fei.zhou.logbacklearn.business.test.User - 我是在 User 类中,使用debug级别打印日志
    
    • 1
    • 2

    1.3、案例2

    演示使用 logback.xml 进行配置

    1.3.1、 logback.xml

    在这里插入图片描述

    <configuration>
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <!-- encoders are assigned the type
                       ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
            <encoder>
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>
    
        <root level="debug">
            <appender-ref ref="STDOUT" />
        </root>
    </configuration>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    1.3.2、 再运行上面的程序,控制台会输出如下信息

    10:36:33.698 [main] INFO  f.z.l.business.test.MyApp1 - 我是在 MyApp1 类中,使用info级别打印日志
    10:36:33.705 [main] DEBUG f.z.logbacklearn.business.test.User - 我是在 User 类中,使用debug级别打印日志
    
    • 1
    • 2

    在这里插入图片描述

    2、打印内部状态

    2.1、介绍

    如果程序在解析配置文件期间发生警告或错误,则 logback 会自动在控制台上打印其内部状态信息。如果在没有警告或错误时,你也希望检查 logback 的内部状态,你可以指示通过调用 StatusPrinter 类的 print() 方法。如下所示:

    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
    StatusPrinter.print(lc);
    
    • 1
    • 2

    如果你不想在程序中编写打印 logback 的内部状态,那可以在配置文件 configuration 元素的 debug 属性设置为 true,同样也可以在程序启动时打印 logback 内部状态。

    <configuration debug = "true">
     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
      <!-- encoders are assigned the type
                 ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
      <encoder>
       <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
      </encoder>
     </appender>
    
     <root level="debug">
      <appender-ref ref="STDOUT" />
     </root>
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.2、案例

    在这里插入图片描述

    3、直接指定配置文件的位置

    1. 通过配置系统属性(logback.configurationFile)的方式,指定 logback配置文件的位置。
    2. 系统属性的值
      1. 可以是 URL
      2. 可以是 类路径上的资源
      3. 可以是 应用程序外部文件的路径。

    3.1、案例

    java -Dlogback.configurationFile=/path/to/logback.xml fei.zhou.logbacklearn.business.test.MyApp1
    
    
    • 1
    • 2

    4、自动重新加载配置文件

    如果开启了自动重新加载配置文件,logback-classic 会扫描配置文件中的更改,并在配置文件更改时自动重新配置自身。在 < configuration> 标签中将 scan 属性设置为 true 即可开启。

    当将 scan 属性设置为 true 时,在后台 ReconfigureOnChangeTask 会在单独的线程中运行,它会检查配置文件是否已更改。

    由于在编辑配置文件时很容易出错,因此如果最新版本的配置文件具有 XML 语法错误,则它将回退到先前没有 XML 语法错误的配置文件。

    <configuration scan="true"> 
      ... 
    </configuration> 
    
    • 1
    • 2
    • 3

    默认情况下,每1分钟扫描一次配置文件是否有更改。我们可以设置 < configuration> 标签中的 scanPeriod 属性来指定扫描周期。单位可以为毫秒,秒,分钟或小时。如果未指定时间单位,则时间单位默认为毫秒

    <configuration debug = "true" scan="true" scanPeriod="30 seconds">
     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
      <!-- encoders are assigned the type
                 ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
      <encoder>
       <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
      </encoder>
     </appender>
    
     <root level="debug">
      <appender-ref ref="STDOUT" />
     </root>
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    5、在堆栈跟踪中启用包数据

    注意从版本1.1.4开始,包装数据默认为禁用。可按如下配置开启包数据:

    <configuration packagingData="true">
      ...
    </configuration>
    
    • 1
    • 2
    • 3

    当然,也可以在程序中进行配置,如下:

    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
    lc.setPackagingDataEnabled(true);
    
    • 1
    • 2

    如果开启了,logback 会在输出的堆栈行中显示它是属于哪个 jar 或者哪个类的。

    此信息由 jar 文件的名称和版本组成,表明堆栈信息来源于此。

    此机制对于识别软件版本问题非常有用。但是,计算成本相当昂贵,尤其是在经常引发异常的应用程序中。以下演示开启的结果,即多了 [] 括号内的信息。

    14:28:48.835 [btpool0-7] INFO  c.q.l.demo.prime.PrimeAction - 99 is not a valid value
    java.lang.Exception: 99 is invalid
      at ch.qos.logback.demo.prime.PrimeAction.execute(PrimeAction.java:28) [classes/:na]
      at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431) [struts-1.2.9.jar:1.2.9]
      at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236) [struts-1.2.9.jar:1.2.9]
      at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432) [struts-1.2.9.jar:1.2.9]
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) [servlet-api-2.5-6.1.12.jar:6.1.12]
      at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:502) [jetty-6.1.12.jar:6.1.12]
      at ch.qos.logback.demo.UserServletFilter.doFilter(UserServletFilter.java:44) [classes/:na]
      at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115) [jetty-6.1.12.jar:6.1.12]
      at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:361) [jetty-6.1.12.jar:6.1.12]
      at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417) [jetty-6.1.12.jar:6.1.12]
      at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230) [jetty-6.1.12.jar:6.1.12]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    6、停止 logback-classic

    为了释放 logback-classic 资源,停止 logback context 是一个好主意。如果停止,会关闭所有 loggers 关联的 appenders,并有序的停止所有活动线程。

    import org.sflf4j.LoggerFactory;
    import ch.qos.logback.classic.LoggerContext;
    ...
    
    LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    loggerContext.stop();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    7、配置文件语法

    7.1、 元素

    一个 logger 记录器可以使用 元素配置。

    < logger> 元素中,name 属性是必须的,level 级别属性是可选的,additivity 可叠加性属性也是可以选的(它的值是 true 或 false)。级别 level 属性的值是不区分大小写的字符串 TRACE,DEBUG,INFO,WARN,ERROR,ALL,OFF。还有不区分大小写的值 INHERITED 或其同义词 NULL,代表将强制从层次结构中较高的层次继承记录器继承级别。

    < logger> 元素里面可包含0或多个 < appender-ref> 元素,这样引用的 appender 会关联到此 logger。不同 log4j,即便你在配置文件配置了 logger 关联的 appender,logback-classic 也不会关闭或者移除之前关联的 appender。

    7.2、配置 root logger,< root> 元素

    < root>元素用来配置 root logger。
    它支持单个属性,即 level 级别属性。
    它没有其他属性,因为可叠加性标志不适用于根记录器。
    由于根记录器已被命名为 " ROOT" ,因此它也不允许使用 name 属性。
    level 属性的值可以是不区分大小写的字符串 TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF之一。但是,根记录器的级别不能设置为 INHERITED 或 NULL。

    与 < logger> 元素类似,< root> 元素也可以包含零个或多个 < appender-ref>元素。如此引用的每个附加程序都会添加到根记录器中。不同 log4j,即便你在配置文件配置了 root logger 关联的 appender,logback-classic 也不会关闭或者移除之前关联的 appender。

    7.2.1、案例1

    下面演示个 demo,假设我们不想打印 “com.nobody.entity” 包下任何组件的任何 DEBUG 消息。可以按如下配置:

    <configuration>
    
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- encoder 默认被分配 ch.qos.logback.classic.encoder.PatternLayoutEncoder 类 -->
        <!-- 当然你也可以通过 class 属性 显示指定,即 <encoder class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> -->
        <encoder>
          <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
      </appender>
    
      <logger name="com.nobody.entity" level="INFO"/>
    
      <!-- 其实此level属性设置也可以去除,因为默认就是 DEBUG 级别 -->
      <root level="DEBUG">          
        <appender-ref ref="STDOUT"/>
      </root>  
      
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    7.2.2、案例2

    我们可以根据需要配置任意数量的记录器。如下,我们将 com.nobody.A 记录器的级别设置 为 INFO,但同时将 com.nobody.B 记录器的级别设置为DEBUG。

    <configuration>
    
      ...
    
      <logger name="com.nobody.A" level="INFO"/>
      <logger name="com.nobody.B" level="DEBUG"/>
     
      ... 
     
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    7.3、配置 Appenders

    一个 appender 使用 < appender> 元素配置,该元素具有两个必填属性 name 和 class。
    1. name 属性指定 appender 的名称
    2. class 属性指定实例化此 appender 的类。

    < appender> 元素可包含零个或一个 < layout> 元素,零个或多个 < encoder> 元素,零个或多个层 < filter> 元素。

    除了这三个公共元素之外,< appender> 可以包含任意数量的与 appender 类的JavaBean属性相对应的元素。

    < layout> 有个必填的属性指定实例化此对象的全限定类名。和 < appender>一样,它也有自己的相关属性。PatternLayout 有默认的属性值,所以可以不指定属性值。

    < encoder>有个必填的属性指定实例化此对象的全限定类名。PatternLayoutEncoder 有默认的属性值,所以可以不指定属性值。

    <configuration debug="false" scan="true" scanPeriod="30 seconds" packagingData="true">
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <!--   <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>-->
                <pattern>%-4relative [%thread] %-5level %logger{32} - %msg%n</pattern>
            </encoder>
        </appender>
        <appender name="FILE" class="ch.qos.logback.core.FileAppender">
      <file>myApp.log</file>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>
    
        <root level="INFO">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="FILE"/>
        </root>
    </configuration>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    上述配置文件定义了两个命名为 FILE 和STDOUT 的 appender 。
    1. FILE appender 将日志输出到 myApp.log 文件。
    2. STDOUT appender 将日志输出到控制台。

    默认情况下,附加程序是累积式的:记录器将记录到附加到其自身的附加程序(如果有)以及附加到其祖先的所有附加程序。因此,将同一附加程序附加到多个记录器将导致记录输出重复。

    默认情况下,appender 是累积式的:一个 logger 会将日志输出到它自己关联的所有 appender 和 它上层级(祖先)所关联的所有 appender。所以,如果将同一个 appender 关联到不同的 logger,有可能会导致输出的日志会重复。例如下面这个例子:

    <configuration debug="false" scan="true" scanPeriod="30 seconds" packagingData="true">
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <!--   <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>-->
                <pattern>%-4relative [%thread] %-5level %logger{32} - %msg%n</pattern>
            </encoder>
        </appender>
    
        <appender name="FILE" class="ch.qos.logback.core.FileAppender">
            <file>myApp.log</file>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>
    
        <logger name="fei.zhou.logbacklearn.business.test.Main">
            <appender-ref ref="STDOUT"/>
        </logger>
    
        <root level="INFO">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="FILE"/>
        </root>
    </configuration>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    public class Main {
        private static final Logger logger = LoggerFactory.getLogger(Main.class);
    
        public static void main(String[] args) {
    
            logger.info("Hello Logback!");
    
            Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
            rootLogger.info("rootLogger:{}", rootLogger.getName());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    会在控制台输出如下结果,因为名为 fei.zhou.logbacklearn.business.test.Main 的 logger 的可叠加性标识默认为 true,所以会将日志输出到它上级的 logger 关联的 appender 中,所以输出2遍。而 root logger 没有上级,输出1遍。

    790  [main] INFO  f.z.l.business.test.Main - Hello Logback!
    790  [main] INFO  f.z.l.business.test.Main - Hello Logback!
    803  [main] INFO  ROOT - rootLogger:ROOT
    
    • 1
    • 2
    • 3

    当然,你可以将 com.nobody.Main 的 logger 的可叠加性标识默认为 false,那它的日志就不会输送到上层级中。

    <logger name="fei.zhou.logbacklearn.business.test.Main" additivity="false">
        <appender-ref ref="STDOUT"/>
    </logger>
    
    • 1
    • 2
    • 3

    8、设置上下文名称

    每个 logger 记录器都附加到一个记录器上下文。默认情况下,它的名称为 “default”。
    通过 < contextName> 配置可以更改其名称,使用此值打印到日志中,用于区分不同应用程序的记录。但一旦设置,它的名称就无法变更。

    <configuration>
      <contextName>myAppName</contextName>
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
      </appender>
    
      <root level="INFO">
        <appender-ref ref="STDOUT" />
      </root>
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    9、变量定义和替换

    9.1、介绍

    logback 配置文件支持变量的定义和替换。
    变量具有作用域。
    变量可以在配置文件中,在外部文件中,在外部资源中,甚至可以即时计算和定义。

    变量替换可以发生在配置文件中可以指定值的任何位置。语法是 ${variableName}。

    考虑到常用性,HOSTNAME 和 CONTEXT_NAME 变量默认已定义,并具有上下文作用域。考虑到在某些环境中可能需要花费一些时间来计算主机名,因此它的值是延迟计算的(仅在需要时)。

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{HH:mm:ss.SSS} ${HOSTNAME} ${CONTEXT_NAME} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    变量可以在 logback 自己的配置文件中定义,也可以从外部属性文件或外部资源中批量加载。由于历史原因,用于定义变量用 。

    <configuration>
    
      <property name="LOG_HOME" value="./logs"/>
    
      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_HOME}/myApp.log</file>
        <encoder>
          <pattern>%msg%n</pattern>
        </encoder>
      </appender>
    
      <root level="debug">
        <appender-ref ref="FILE" />
      </root>
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    它下面的效果一样,logback 将在 System 属性中查找它。

    java -LOG_HOME="./logs" MyApp
    
    • 1

    如果你定义的变量太多时,可以创建单独的文件来保存,方便管理。

    <configuration>
    
      <property file="src/main/java/resources/logback-variables.properties"/>
    
      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_HOME}/myApp.log</file>
        <encoder>
          <pattern>%msg%n</pattern>
        </encoder>
      </appender>
    
      <root level="debug">
        <appender-ref ref="FILE" />
      </root>
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    此配置会读取logback-variables.properties文件中的变量,然后在本地范围内使用。logback-variables.properties文件定义的变量如下:

    LOG_HOME=./logs
    
    • 1

    当然,也可以写成引入类路径上的资源文件的形式。

    <configuration>
    
      <property resource="logback-variables.properties"/>
    
      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_HOME}/myApp.log</file>
        <encoder>
          <pattern>%msg%n</pattern>
        </encoder>
      </appender>
    
      <root level="debug">
        <appender-ref ref="FILE" />
      </root>
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    9.2、变量作用域

    9.2.1、变量作用域

    1. Local Scope(本地作用域)
      1. 从配置文件中定义的本地变量即在本地配置文件使用。每次解析和执行配置文件时,都会重新定义本地作用域中的变量。
    2. Context Scope(上下文作用域)
      1. 一个拥有上下文作用域的变量存在于上下文中,于上下文共存,直到被清除。在所有记录事件中都可用到,包括那些通过序列化发送到远程主机的事件。
    3. System Scope(系统级作用域)
      1. 系统级作用域的变量被插入到JVM的系统属性中,生命周期和JVM一致,直到被清除。
    4. 默认是本地作用域。从操作系统环境中读取变量很容易,但是无法写入到操作系统环境中。

    在进行属性替换时,查找变量的顺序为:local scope,context scope,system

    <configuration>
    
      <property scope="context" name="LOG_HOME" value="./logs"/>
    
      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_HOME}/myApp.log</file>
        <encoder>
          <pattern>%msg%n</pattern>
        </encoder>
      </appender>
    
      <root level="debug">
        <appender-ref ref="FILE" />
      </root>
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    9.2.2、引入变量时,可能变量未定义或者值为null,我们可以使用":-"符号指定默认值。例如

    ${LOG_HOME:-./logs}。
    
    • 1

    9.2.3、支持变量嵌套,默认值和值定义都可以引用其他变量。例如:

    LOG_HOME=./logs
    FILE_NAME=myApp.log
    destination=${LOG_HOME}/${FILE_NAME}
    
    • 1
    • 2
    • 3

    9.2.4、名称嵌套

    引用变量时,变量名称可能包含对另一个变量的引用。例如

    如果为名为" userid"的变量分配了值" alice",则" $ {$ {userid} .password}"引用名称为" alice.password"的变量。
    
    
    • 1
    • 2

    9.2.5、默认值嵌套

    变量的默认值可以引用另一个变量。例如

    假设未分配变量" id",并且为变量" userid"分配了值" alice",则表达式" $ {id :- $ {userid}}"将返回" alice"。
    
    
    • 1
    • 2

    9.2.6、有条件地处理配置文件

    我们可能需要在不同的环境(例如dev,test,prod)切换不同的logback配置文件。然而这些配置文件大部分内容是一样的,极少内容是不同的。为了减少多个配置文件,可以使用条件处理标签,< if>, < then> 和 < else>,根据不同环境进行配置。不过,需要引入Janino 库。

       <!-- if-then 形式 -->
       <if condition="表达式">
        <then>
          ...
        </then>
      </if>
      
      <!-- if-then-else 形式 -->
      <if condition="表达式">
        <then>
          ...
        </then>
        <else>
          ...
        </else>    
      </if>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    condition 条件只能是上下文属性或系统属性的Java表达式。对于通过参数传递的键,可以通过 property() 或简写的 p() 方法返回属性的字符串值。例如,property(“k”) 或 p(“k”) 访问键" k"的值。如果键" k"的属性未定义,则属性方法将返回空字符串,而不是null。这能避免判断null值。

    isDefined()方法可用于检查是否定义了属性。例如,isDefined(“k”) 。
    如果需要检查属性是否为null,则可以使用 isNull() 方法。例如,isNull(“k”)。

    <configuration debug="true">
    
      <if condition='property("HOSTNAME").contains("torino")'>
        <then>
          <appender name="CON" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
              <pattern>%d %-5level %logger{35} - %msg %n</pattern>
            </encoder>
          </appender>
          <root>
            <appender-ref ref="CON" />
          </root>
        </then>
      </if>
    
      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${randomOutputDir}/conditional.log</file>
        <encoder>
          <pattern>%d %-5level %logger{35} - %msg %n</pattern>
       </encoder>
      </appender>
    
      <root level="ERROR">
         <appender-ref ref="FILE" />
      </root>
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在范围内都可以使用条件处理语句。还支持嵌套的if-then-else语句。但是,XML语法非常繁琐,为以后后续其他开发者以及自己能快速理解,尽量少用。

    9.2.7、文件包含

    Joran支持将配置文件的一部分包含在另一个文件中。这是通过声明一个 include元素来完成的,如下所示:

    可以通过标签< include>来引入另一个配置文件。

    <configuration>
      <include file="src/main/java/resources/includedConfig.xml"/>
    
      <root level="DEBUG">
        <appender-ref ref="includedConsole" />
      </root>
    
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    includedConfig.xml文件定义了被引用的内容:

    <included>
      <appender name="includedConsole" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>"%d - %m%n"</pattern>
        </encoder>
      </appender>
    </included>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    标签引入的文件可以为一个文件,一个类路径上的资源,或者一个URL。如下:

    <include file="src/main/java/resources/includedConfig.xml"/>
    
    <include resource="includedConfig.xml"/>
    
    <include url="http://xxx.com/includedConfig.xml"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    如果被引用的文件不存在,logback会打印内部的状态信息。如果包含的文件是可选的,可以通过optional属性设置为true来进制打印显示警告信息。

    <include optional="true" ..../>
    
    
    • 1
    • 2
  • 相关阅读:
    Notepad++ 和正则表达式 只保留自己想要的内容
    深入理解浏览器渲染原理
    Kubernetes之list-watch机制
    【软考软件评测师】案例专题——白盒测试
    【C语言】——三道基础程序练习
    【智能家居项目】裸机版本——网卡设备接入输入子系统 | 业务子系统 | 整体效果展示
    HDR-ISP_unpack_depwl_01_20231002
    C++ 运算符学习资料
    Linux_aarch64_head.S到main.c的环境建立
    Sharding-JDBC 基础
  • 原文地址:https://blog.csdn.net/zhou920786312/article/details/125411306