用户创建的Lookup插件的log4j2评估不一致,并且在以编程方式使用时根本不起作用

时间:2017-04-24 16:37:07

标签: log4j2

我用log4j2插件观察了一些我只能解释为不一致的行为。

我试图编写一个与RollingFileAppender一起使用的插件,它允许我更改每个滚动文件的标题。我决定使用Lookup插件(称之为dynamicheader)。另一个复杂因素是RollingFileAppender及其相关的PatternLayout以编程方式创建。我观察到的问题详述如下,但总结如下:

  1. 永远不会评估PatternLayout的header属性:在PatternLayout上调用getHeader()始终返回" $ {dynamicheader:key}而不是与键关联的值。如果我替换" $ {dynamicheader:key}"用" $ {sys:key}"标头IS被评估,getHeader()返回我为"键"设置的任何值。
  2. 如果我在配置文件中配置了我的插件的FileAppender (" $ {dynamicheader:key}",请参阅下文),在相关的PatternLayout上调用getHeader()是否返回与密钥关联的值,但仅评估一次。如果我更改与键关联的值(标头),则后续调用getHeader()不会重新评估标头并返回原始密钥。但是,如果我在定义PatternLayout(" $$ {dynamicheader:key}")时使用2 $,则会在每次调用getHeader()时评估标头IS。这并不令人惊讶,因为(我收集)这是预期的行为,但是,如果我再次用SystemPropertyLookup替换我的插件,我只需要在每次调用getHeader()时评估头的$ $。
  3. 我的插件,配置文件和单元测试以演示以下行为:

    插件

    package my.custom.plugins;
    
    @Plugin(name = "dynamicheader", category = StrLookup.CATEGORY)
    public class DynamicHeader extends AbstractLookup {
      private static Map<String, String> headerByAppender = Collections.synchronizedMap(new HashMap<>());
    
      @Override
      public String lookup(final LogEvent event, final String key) {
        return get(key);
      }
    
      public void put(String key, String val) {
        headerByAppender.put(key, val);
      }
    
      public String get(String key) {
        return headerByAppender.get(key);
      }
    }
    

    请注意,我的插件与SystemPropertiesLookup插件非常相似,我希望它们的行为类似。

    配置:

    Configuration:
        name: TestConfig
        packages: "my.custom.plugins"
        Appenders:
            File:
                name: FILE
                fileName: target/surefire-reports/unit-test.log
                append: false
                PatternLayout:
                    Pattern: "%m%n%ex"
                    header: ${dynamicheader:key2}
        Loggers:
            Root:
                AppenderRef:
                    ref: FILE
    

    试验:

    public void testMyPlugin1() {
      DynamicHeader dh = new DynamicHeader();
      dh.put("key1", "val1");
      PatternLayout pl = PatternLayout.newBuilder()
                                      .withPattern("%m%n%ex")
                                      .withHeader("${dynamicheader:key1}")  // use my plugin here...
                                      .build();
      assertEquals("val1", pl.getHeader());  // <- this fails. pl.getHeader() always returns "${dynamicheader:key1}"
    }
    
    public void testSysPlugin1() {
        System.setProperty("key1", "val1");
        PatternLayout pl = PatternLayout.newBuilder()
                                        .withPattern("%m%n%ex")
                                        .withHeader("${sys:key1}")  // use sys plugin here...
                                        .build();
        assertEquals("val1", pl.getHeader());  // <- this works.
    }
    
    public void testMyPlugin2() {
        DynamicHeader dh = new DynamicHeader();
        Layout l = ((LoggerContext)LogManager.getContect(false)).getConfiguration().getAppender("FILE").getLayout();
    
        dh.put("key2", "val2"); 
        assertEquals("val2", l.getHeader());  // <- this works.
    
        dh.put("key2", "val3");
        assertEquals("val3", l.getHeader());  // <- this fails. getHeader() returns "key2"
    }
    

    但是,如果我从

    中获取共享文件
    header: ${dynamicheader:key2}

    header: $${dynamicheader:key2}

    以上测试通过。相反,如果我改变

    header: ${dynamicheader:key2}

    header: ${sys:key2}

    等效测试通过:

    public void testSysPlugin2() {
        Layout l = ((LoggerContext)LogManager.getContect(false)).getConfiguration().getAppender("FILE").getLayout();
    
        System.setProperty("key2", "val2"); 
        assertEquals("val2", l.getHeader());  // <- this works.
    
        System.setProperty("key2", "val3");
        assertEquals("val3", l.getHeader());  // <- this also works.
    }
    

    我的问题是:

    1. 为什么在以编程方式创建PatternLayout时,我的插件永远不会被评估?我做错了吗?
    2. 为什么SystemPropertyLookup的行为与用户创作的几乎相同的查找不同。
    3. 我正在使用log4j2 v2.8.2。

      提前致谢!

0 个答案:

没有答案