@VisibleForTesting
    static String generateActiveLog4jXmlConfig() throws IOException {
        Map<String, String> properties = Maps.newHashMap();

        // sys log config
        if (!DEBUG_LEVELS.contains(StringUtils.upperCase(sysLogLevel))) {
            throw new IOException("sys_log_level config error");
        }
        properties.put("sys_log_dir", Config.sys_log_dir);
        properties.put("sys_roll_maxsize", String.valueOf(Config.log_roll_size_mb));
        properties.put("sys_roll_num", String.valueOf(Config.sys_log_roll_num));
        properties.put("sys_log_delete_age", String.valueOf(Config.sys_log_delete_age));
        properties.put("sys_log_level", sysLogLevel);
        properties.put("sys_file_pattern", getIntervalPattern("sys_log_roll_interval", Config.sys_log_roll_interval));

        // audit log config
        properties.put("audit_log_dir", Config.audit_log_dir);
        properties.put("audit_roll_maxsize", String.valueOf(Config.log_roll_size_mb));
        properties.put("audit_roll_num", String.valueOf(Config.audit_log_roll_num));
        properties.put("audit_log_delete_age", String.valueOf(Config.audit_log_delete_age));
        properties.put("audit_file_pattern",
                getIntervalPattern("audit_log_roll_interval", Config.audit_log_roll_interval));

        // dump log config
        properties.put("dump_log_dir", Config.dump_log_dir);
        properties.put("dump_roll_maxsize", String.valueOf(Config.log_roll_size_mb));
        properties.put("dump_roll_num", String.valueOf(Config.dump_log_roll_num));
        properties.put("dump_log_delete_age", String.valueOf(Config.dump_log_delete_age));
        properties.put("dump_file_pattern",
                getIntervalPattern("dump_log_roll_interval", Config.dump_log_roll_interval));

        // big query log config
        properties.put("big_query_log_dir", Config.big_query_log_dir);
        properties.put("big_query_roll_maxsize", String.valueOf(Config.log_roll_size_mb));
        properties.put("big_query_log_roll_num", String.valueOf(Config.big_query_log_roll_num));
        properties.put("big_query_log_delete_age", String.valueOf(Config.big_query_log_delete_age));
        properties.put("big_query_file_pattern",
                getIntervalPattern("big_query_log_roll_interval", Config.big_query_log_roll_interval));

        // profile log config
        properties.put("profile_log_dir", Config.profile_log_dir);
        properties.put("profile_log_roll_size_mb", String.valueOf(Config.profile_log_roll_size_mb));
        properties.put("profile_log_roll_num", String.valueOf(Config.profile_log_roll_num));
        properties.put("profile_log_delete_age", String.valueOf(Config.profile_log_delete_age));
        properties.put("profile_file_pattern",
                getIntervalPattern("profile_log_roll_interval", Config.profile_log_roll_interval));

        // internal log config
        properties.put("internal_log_dir", Config.internal_log_dir);
        properties.put("internal_roll_maxsize", String.valueOf(Config.log_roll_size_mb));
        properties.put("internal_log_roll_num", String.valueOf(Config.internal_log_roll_num));
        properties.put("internal_log_delete_age", String.valueOf(Config.internal_log_delete_age));
        properties.put("internal_file_pattern",
                getIntervalPattern("big_query_log_roll_interval", Config.internal_log_roll_interval));

        // appender layout
        final String jsonLoggingConfValue = "json";
        if (jsonLoggingConfValue.equalsIgnoreCase(Config.sys_log_format)) {
            // json logging
            String jsonLayout =
                    "<JsonTemplateLayout maxStringLength=\"104857600\" locationInfoEnabled=\"true\">\n" +
                            "        <EventTemplate><![CDATA[\n{\n" +
                            "   \"@timestamp\": {\n" +
                            "       \"$resolver\": \"timestamp\",\n" +
                            "       \"pattern\": {\n" +
                            "         \"format\": \"yyyy-MM-dd HH:mm:ss.SSSXXX\",\n" +
                            "         \"timeZone\": \"UTC\"\n" +
                            "        }\n" +
                            "      },\n" +
                            "      \"level\": {\n" +
                            "       \"$resolver\": \"level\",\n" +
                            "       \"field\": \"name\"\n" +
                            "      },\n" +
                            "      \"thread.name\": {\n" +
                            "       \"$resolver\": \"thread\",\n" +
                            "       \"field\": \"name\"\n" +
                            "      },\n" +
                            "      \"thread.id\": {\n" +
                            "       \"$resolver\": \"thread\",\n" +
                            "       \"field\": \"id\"\n" +
                            "      },\n" +
                            "      \"method\": {\n" +
                            "       \"$resolver\": \"logger\",\n" +
                            "       \"field\": \"name\",\n" +
                            "       \"shorten\": {\n" +
                            "         \"length\": 1,\n" +
                            "         \"strategy\": \"tail\"\n" +
                            "        }\n" +
                            "      },\n" +
                            "      \"line\": {\n" +
                            "        \"$resolver\": \"source\",\n" +
                            "        \"field\": \"lineNumber\"\n" +
                            "      },\n" +
                            "      \"message\": {\n" +
                            "        \"$resolver\": \"message\",\n" +
                            "        \"stringfield\": \"true\"\n" +
                            "      },\n" +
                            "      \"exception\": {\n" +
                            "        \"$resolver\": \"exception\",\n" +
                            "        \"field\": \"stackTrace\",\n" +
                            "        \"stackTrace\": {\n" +
                            "          \"stringified\": true,\n" +
                            "          \"full\": true\n" +
                            "        }\n" +
                            "      }" +
                            "      }\n]]></EventTemplate>\n" +
                            "</JsonTemplateLayout>";
            properties.put("syslog_default_layout", jsonLayout);
            properties.put("syslog_warning_layout", jsonLayout);
            properties.put("syslog_audit_layout", jsonLayout);
            properties.put("syslog_dump_layout", jsonLayout);
            properties.put("syslog_bigquery_layout", jsonLayout);
            properties.put("syslog_profile_layout", jsonLayout);
        } else {
            // fallback to plaintext logging
            properties.put("syslog_default_layout",
                    "<PatternLayout charset=\"UTF-8\" pattern=\"%d{yyyy-MM-dd HH:mm:ss.SSSXXX} %p (%t|%tid) [%C{1}.%M():%L] %m%n\"/>");
            properties.put("syslog_warning_layout",
                    "<PatternLayout charset=\"UTF-8\" pattern=\"%d{yyyy-MM-dd HH:mm:ss.SSSXXX} %p (%t|%tid) [%C{1}.%M():%L] %m%n %ex\"/>");
            properties.put("syslog_audit_layout",
                    "<PatternLayout charset=\"UTF-8\" pattern=\"%d{yyyy-MM-dd HH:mm:ss.SSSXXX} [%c{1}] %m%n\"/>");
            properties.put("syslog_dump_layout",
                    "<PatternLayout charset=\"UTF-8\" pattern=\"%d{yyyy-MM-dd HH:mm:ss.SSSXXX} [%c{1}] %m%n\"/>");
            properties.put("syslog_bigquery_layout",
                    "<PatternLayout charset=\"UTF-8\" pattern=\"%d{yyyy-MM-dd HH:mm:ss.SSSXXX} [%c{1}] %m%n\"/>");
            properties.put("syslog_profile_layout",
                    "<PatternLayout charset=\"UTF-8\" pattern=\"%d{yyyy-MM-dd HH:mm:ss.SSSXXX} [%c{1}] %m%n\"/>");
        }

        String xmlConfTemplate = generateXmlConfTemplate();
        strSub = new StrSubstitutor(new Interpolator(properties));
        return strSub.replace(xmlConfTemplate);
    }
@Test
    public void testJsonLoggingFormatConfig() throws IOException {
        // ${([^}]*)}
        String regStr = "\\$\\{([^\\}]*)\\}";
        String name = "";
        // default plaintext configuration
        Config.sys_log_format = "plaintext";
        {
            String xmlConfig = Log4jConfig.generateActiveLog4jXmlConfig();
            Assert.assertFalse(xmlConfig.contains("<JsonTemplateLayout"));
            Assert.assertTrue(xmlConfig.contains("<PatternLayout"));
            // no unresolved variable
            Matcher matcher = Pattern.compile(regStr, Pattern.MULTILINE).matcher(xmlConfig);
            if (matcher.find()) {
                name = matcher.group(1);
                Assert.fail(String.format("Unexpected of unresolved variables:'%s' in the final xmlConfig", name));
            }
        }
        // check the json configuration
        Config.sys_log_format = "json";
        {
            String xmlConfig = Log4jConfig.generateActiveLog4jXmlConfig();
            Assert.assertTrue(xmlConfig.contains("<JsonTemplateLayout"));
            Assert.assertFalse(xmlConfig.contains("<PatternLayout"));
            // no unresolved variable
            Matcher matcher = Pattern.compile(regStr, Pattern.MULTILINE).matcher(xmlConfig);
            if (matcher.find()) {
                name = matcher.group(1);
                Assert.fail(String.format("Unexpected of unresolved variables:'%s' in the final xmlConfig", name));
            }
        }
    }