zoukankan      html  css  js  c++  java
  • Logback.xml 给变量指定默认值

    随着通用日志组件转入 Slf4j,logback 也变成了默认的日志实现,像 log4j 一样,logback.xml 中也可以使用系统属性或环境变量,如 ${catalina.home}。在 log4j.properties 中,如果变量在系统属性和环境变量中找不到的话默认为 "" 空字符串,而到了 logback.xml 中如果某个变量找不到默认就是 "变量名_IS_UNDEFINED" 了,这样就比较奇怪了。

    那如何在没有配置 catalina.home 系统属性或环境变量时设置一个默认值呢,例如,没有 catalina.home  时取值为 ".",这时值日志文件的路径就是

    ./logs/unmi-%d{yyyy-MM-dd}.log

    了,也就是生成中当前目录下的 logs 子目录中,这样算是很友好的方式。下面就来分析怎么一步步找到答案的,没耐心或是只求结果的话,直接滚屏到下面就行。

    我们的问题是,对于下面那样的 logback.xml 配置:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <?xml version="1.0" encoding="UTF-8"?>
     
    <configuration>
     
        <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
            <encoder charset="UTF-8">
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
            </encoder>
        </appender>
     
        <appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${catalina.home}/logs/unmi-%d{yyyy-MM-dd}.log</fileNamePattern>
                <maxHistory>10</maxHistory>
            </rollingPolicy>
     
            <encoder>
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
            </encoder>
        </appender>
     
        <root level="DEBUG">
            <appender-ref ref="stdout" />
            <appender-ref ref="RollingFile" />
        </root>
    </configuration>

    因为测试时直接在 Eclipse 或控制台下执行,在未定义 catalina.home 的情况下,一运行就会在当前目录下生成 catalina.home_IS_UNDEFINED 目录,其中有 logs 子目录,再才是 unmi-2014-05-19.log 这个日志文件。

    logback-variable-default-value

    搜索了网上关于默认值的解决方案,有说在 logback.xml 中写条件表达式,例如:

    1
    2
    3
    4
    5
    6
    7
    8
    <if condition="property('catalina.home')==null">
        <then>
            <fileNamePattern>logs/unmi-%d{yyyy-MM-dd}.log</fileNamePattern>
        </then>
        <else>
            <fileNamePattern>${catalina.home}/logs/unmi-%d{yyyy-MM-dd}.log</fileNamePattern>
        </else>
    </if>

    参考: http://logback.qos.ch/manual/configuration.html#conditional 和 http://stackoverflow.com/questions/15911303/how-can-i-configure-logback-conditionally-based-on-context-name

    上面的 if-then-else 是有问题的 The FileNamePattern option must be set before using TimeBasedRollingPolicy,需要把 if 的覆盖范围扩大,不过试了也不怎么爽。

    回到  IS_UNDEFINED, 它总是有来头的,搜索源代码可找到它出现在 https://github.com/qos-ch/logback/blob/master/logback-core/src/main/java/ch/qos/logback/core/util/OptionHelper.java#L103:

    final static String _IS_UNDEFINED = "_IS_UNDEFINED";

     

    还有一处未被使用,这样就有突破口了,再跟踪代码,找到 logback 是怎么取到相对应变量值的 https://github.com/qos-ch/logback/blob/master/logback-core/src/main/java/ch/qos/logback/core/subst/NodeToStringTransformer.java#L102,handleVariable 方法代码片断:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
     if (n.defaultPart == null) {
      stringBuilder.append(key + CoreConstants.UNDEFINED_PROPERTY_SUFFIX);
      cycleCheckStack.pop();
      return;
    }
     
    Node defaultPart = (Node) n.defaultPart;
    StringBuilder defaultPartBuffer = new StringBuilder();
    compileNode(defaultPart, defaultPartBuffer, cycleCheckStack);
    cycleCheckStack.pop();
    String defaultVal = defaultPartBuffer.toString();
    stringBuilder.append(defaultVal);

    注:从这个类的 lookupKey(String key) 方法中可以知道  logback 从四个地方取变量值,分别是 propertyContainer0, propertyContrainer1, System, Evn,前两不知道没关系,后两个我们明白先从 System 属性,没有再从环境变量中取。

    上面我们会想到 Node 除了有 payload 还有一个 defaultPart 用了设定默认值部分。至于默认值怎么设置,猜测试是 ${catalina.home:abc},没用,不过别急,logback  的测试用例告诉了我们表达式的写法。

    见 https://github.com/qos-ch/logback/blob/master/logback-core/src/test/java/ch/qos/logback/core/util/OptionHelperTest.java#L99, 看到这样写代默认值的表达式

    ${v2:-toto}        //格式是 ${变量名:-默认值},光有冒号还不够,再加条短线后面才是默认值

    所以学习它后,前面的日志文件名配置部分就写成

    1
    2
    <!-- 如果没有定义  catalina.home  系统属性或环境变量时,生成的日志文件在 ./logs 目录下 -->
    <fileNamePattern>${catalina.home:-.}/logs/unmi-%d{yyyy-MM-dd}.log</fileNamePattern>

    完整的 logback.xml 内容如下:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <?xml version="1.0" encoding="UTF-8"?>
     
    <configuration>
     
        <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
            <encoder charset="UTF-8">
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
            </encoder>
        </appender>
     
        <appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${catalina.home:-.}/logs/unmi-%d{yyyy-MM-dd}.log</fileNamePattern>
                <maxHistory>10</maxHistory>
            </rollingPolicy>
     
            <encoder>
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
            </encoder>
        </appender>
     
        <root level="DEBUG">
            <appender-ref ref="stdout" />
            <appender-ref ref="RollingFile" />
        </root>
    </configuration>

    多看看这 OptionHelperTest 测试用例,还能发现默认值也能用变量,如

    ${B:-${A}}

  • 相关阅读:
    vs2013如何在C++中调用Lua(二)
    用vs2013编译lua源码方法(一)
    使用Sublime Text 直接运行Quick-cocos2d-x 项目
    SubmitText 中配置lua 运行环境
    在VS2012/2013上编辑和调试Quick-cocos2d-x的Lua代码
    Cocos2d-x 开发 v3.2 建立新项目并添加库文件
    计算一段函数的执行效率
    C++中嵌入Lua脚本环境搭建
    Android开发环境配置
    cocos2d-x-3.1.1 创建项目
  • 原文地址:https://www.cnblogs.com/liuchuanfeng/p/6931030.html
Copyright © 2011-2022 走看看