• 聊聊logback的UNDEFINED_PROPERTY


    本文主要研究一下logback的UNDEFINED_PROPERTY

    substVars

    ch/qos/logback/core/util/OptionHelper.java

        public static String substVars(String input, PropertyContainer pc0, PropertyContainer pc1) {
            try {
                return NodeToStringTransformer.substituteVariable(input, pc0, pc1);
            } catch (ScanException e) {
                throw new IllegalArgumentException("Failed to parse input [" + input + "]", e);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    OptionHelper提供了substVars方法,它执行NodeToStringTransformer的substituteVariable方法

    substituteVariable

    ch/qos/logback/core/subst/NodeToStringTransformer.java

        public static String substituteVariable(String input, PropertyContainer pc0, PropertyContainer pc1) throws ScanException {
            Node node = tokenizeAndParseString(input);
            NodeToStringTransformer nodeToStringTransformer = new NodeToStringTransformer(node, pc0, pc1);
            return nodeToStringTransformer.transform();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    substituteVariable方法则先根据input解析node,再创建NodeToStringTransformer,执行其transform方法

    transform

    ch/qos/logback/core/subst/NodeToStringTransformer.java

        public String transform() throws ScanException {
            StringBuilder stringBuilder = new StringBuilder();
            compileNode(node, stringBuilder, new Stack());
            return stringBuilder.toString();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    transform方法主要是执行compileNode,通过stringBuilder来收集变量值

    compileNode

    ch/qos/logback/core/subst/NodeToStringTransformer.java

        private void compileNode(Node inputNode, StringBuilder stringBuilder, Stack cycleCheckStack) throws ScanException {
            Node n = inputNode;
            while (n != null) {
                switch (n.type) {
                case LITERAL:
                    handleLiteral(n, stringBuilder);
                    break;
                case VARIABLE:
                    handleVariable(n, stringBuilder, cycleCheckStack);
                    break;
                }
                n = n.next;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    compileNode方法针对VARIABLE类型的执行handleVariable方法

    handleVariable

    ch/qos/logback/core/subst/NodeToStringTransformer.java

        private void handleVariable(Node n, StringBuilder stringBuilder, Stack cycleCheckStack) throws ScanException {
    
            // Check for recursion
            if (haveVisitedNodeAlready(n, cycleCheckStack)) {
                cycleCheckStack.push(n);
                String error = constructRecursionErrorMessage(cycleCheckStack);
                throw new IllegalArgumentException(error);
            }
            cycleCheckStack.push(n);
    
            StringBuilder keyBuffer = new StringBuilder();
            Node payload = (Node) n.payload;
            compileNode(payload, keyBuffer, cycleCheckStack);
            String key = keyBuffer.toString();
            String value = lookupKey(key);
    
            // empty values are considered valid
            if (value != null) {
                Node innerNode = tokenizeAndParseString(value);
                compileNode(innerNode, stringBuilder, cycleCheckStack);
                cycleCheckStack.pop();
                return;
            }
    
            // empty default literal is a valid value
            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);
        }   
    
    • 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
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    handleVariable方法对于value为null,且defaultValue也为null的设置了默认值key + CoreConstants.UNDEFINED_PROPERTY_SUFFIX)

    UNDEFINED_PROPERTY_SUFFIX

    public class CoreConstants {
    	//......
    
    	public static final String UNDEFINED_PROPERTY_SUFFIX = "_IS_UNDEFINED";
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    UNDEFINED_PROPERTY_SUFFIX的值为_IS_UNDEFINED

    小结

    logback通过NodeToStringTransformer的handleVariable来获取变量值,若该value为null,且defaultValue也为null的设置了默认值为key + CoreConstants.UNDEFINED_PROPERTY_SUFFIX),即key_IS_UNDEFINED,注意这里如果defaultValue不为null则不走IS_UNDEFINED的逻辑,即空字符串也是可以的。对于自定义appender需要注意一下appender属性的value处理逻辑。

  • 相关阅读:
    VR全景创业如何开拓市场?如何让创业之路更加顺畅?
    [公派访问学者]申请方法分享
    使用Kali Linux Metasploit 对WEB应用进行攻击 以DVWA为例
    【Java学习】JDK安装及第一个java程序
    《nlp入门+实战:第五章:使用pytorch中的API实现线性回归》
    FreeRTOS(以STM32F1系列为例子)
    在用cmake编译时,遇到opencv报错runtime library
    1) 数字信号及其基本运算
    计算机毕业设计(附源码)python校园疫情管理系统
    dpdk 多进程模型对 pmd 驱动实现的要求
  • 原文地址:https://blog.csdn.net/hello_ejb3/article/details/134232075