使用pax记录的log4j2:无法使用来自StructuredDataMessage的值

我正在使用pax-logging-api和pax-logging-log4j2从OSGi捆绑包中进行日志记录。我想利用Log4J2的StructuredDataMessage(使用EventLogger)将一些消息写入数据库。但是,使用Pax日志记录时,我无法从附加程序读取我放入StructuredDataMessage中的值。

以下可直接使用Log4J2库在非OSGi项目中工作

log4j2.properties:

appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %m%n

appender.event.type = Console
appender.event.name = event
appender.event.layout.type = PatternLayout
appender.event.layout.pattern = %marker ${sd:id} ${sd:testKey} %n    %m%n

rootLogger.level = debug
rootLogger.appenderRef.console.ref = STDOUT

logger.event.name = EventLogger
logger.event.level = debug
logger.event.appenderRef.console.ref = event
logger.event.additivity = false

Test.java:

public class Test {

    private static final Logger LOGGER = LogManager.getLogger(Test.class);

    public static void main(String[] args) {
        StructuredDataMessage msg = new StructuredDataMessage("1","message","event");
        msg.put("testKey","testvalue");

        LOGGER.info(msg);
        EventLogger.logEvent(msg);
    }
}

输出:

 1 testvalue event [1 testKey="testvalue"] message
EVENT 1 testvalue 
    event [1 testKey="testvalue"] message

请注意,event附加程序已正确地从StructuredDataMessage解引用了sd键。

但是,以下在带有pax日志记录的OSGi中不起作用

org.ops4j.pax.logging.cfg:

log4j2.appender.console.type = Console
log4j2.appender.console.name = STDOUT
log4j2.appender.console.layout.type = PatternLayout
log4j2.appender.console.layout.pattern = %m%n

log4j2.appender.event.type = Console
log4j2.appender.event.name = event
log4j2.appender.event.layout.type = PatternLayout
log4j2.appender.event.layout.pattern = %marker \$\\\{sd:id\} \$\\\{sd:testKey\} %n    %m%n

log4j2.rootLogger.level = debug
log4j2.rootLogger.appenderRef.console.ref = STDOUT

log4j2.logger.event.name = EventLogger
log4j2.logger.event.level = debug
log4j2.logger.event.appenderRef.console.ref = event
log4j2.logger.event.additivity = false

Test.java:

public class Test implements Bundleactivator {

    private static final Logger LOGGER = LogManager.getLogger(Test.class);

    @Override
    public void start(BundleContext context) throws Exception {
        StructuredDataMessage msg = new StructuredDataMessage("1","testvalue");

        LOGGER.info(msg);
        EventLogger.logEvent(msg,Level.INFO);
    }

    @Override
    public void stop(BundleContext context) throws Exception {
    }
}

输出:

event [1 testKey="testvalue"] message
EVENT ${sd:id} ${sd:testKey}
    event [1 testKey="testvalue"] message

是否有使它在pax日志记录中起作用的技巧?如果适用,我可以使用\$\\\{ctx:key\}从MDC访问值,因此我假设语法相似。我也尝试过在RoutingAppender,FileAppender等模式中使用查找无效。

谢谢!

编辑:我正在使用最新版本的pax-logging-api和pax-logging-log4j2(1.11.3)

cuterose 回答:使用pax记录的log4j2:无法使用来自StructuredDataMessage的值

好的,这还不是一个明确的答案-只是评论太短而无法描述发生的事情。

调用的堆栈跟踪为:

"pipe-restart 238@10666" prio=5 tid=0xc3 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at org.ops4j.pax.logging.log4j2.internal.PaxLoggerImpl.doLog0(PaxLoggerImpl.java:354)
      at org.ops4j.pax.logging.log4j2.internal.PaxLoggerImpl.doLog(PaxLoggerImpl.java:337)
      at org.ops4j.pax.logging.log4j2.internal.PaxLoggerImpl.inform(PaxLoggerImpl.java:233)
      at org.ops4j.pax.logging.internal.TrackingLogger.inform(TrackingLogger.java:209)
      at org.ops4j.pax.logging.log4jv2.Log4jv2Logger.logMessage(Log4jv2Logger.java:162)
      at org.apache.logging.log4j.spi.AbstractLogger.log(AbstractLogger.java:2102)
      at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2190)
      at org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2144)
      at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2127)
      at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1828)
      at org.apache.logging.log4j.EventLogger.logEvent(EventLogger.java:56)
      at grgr.test.ActivatorLogging.start(ActivatorLogging.java:39)
...

org.ops4j.pax.logging.log4jv2.Log4jv2Logger.logMessage()记录外观记录后端之间的桥梁。

请记住-通过pax记录,您可以说将Commons Logging facade 与Log4J1 后端或Log4j2 facade 一起使用(这就是您正在做什么),例如Logback backend

这就是org.ops4j.pax.logging.log4jv2.Log4jv2Logger.logMessage()这样做的原因:

} else if (level.intLevel() >= Level.INFO.intLevel()) {
    m_delegate.inform(paxMarker,message.getFormattedMessage(),t,fqcn);

,您的结构化消息将更改为字符串event [1 testKey="testValue"] message

然后仅调用已配置的附加程序-具有用于提取结构化数据的布局的附加程序找不到它,因为结构化消息已转换为纯字符串。

这3行:

  at org.ops4j.pax.logging.log4j2.internal.PaxLoggerImpl.inform(PaxLoggerImpl.java:233)
  at org.ops4j.pax.logging.internal.TrackingLogger.inform(TrackingLogger.java:209)
  at org.ops4j.pax.logging.log4jv2.Log4jv2Logger.logMessage(Log4jv2Logger.java:162)

从pax-logging-api(正面)通过TrackingLogger(网桥)到pax-logging-log4j2(后端)进行穿越,这之间丢失了结构化信息。

我已经创建了https://ops4j1.jira.com/browse/PAXLOGGING-302,希望很快能对此有所帮助。

EDIT1

关键是在org.apache.logging.log4j.core.lookup.StructuredDataLookup#lookup()中,此条件成立:

if (event == null || !(event.getMessage() instanceof StructuredDataMessage)) {
    return null;
}

EDIT2

我刚刚修复了https://ops4j1.jira.com/browse/PAXLOGGING-302,该测试证明了它的有效性:

Logger logger = LogManager.getLogger("my.logger");

logger.info(new StructuredDataMessage("1","hello!","typeX").with("key1","sd1"));
logger.info(new StringMapMessage().with("key1","map1"));

List<String> lines = readLines();
assertTrue(lines.contains("my.logger/org.ops4j.pax.logging.it.Log4J2MessagesIntegrationTest typeX/sd1 [INFO] typeX [1 key1=\"sd1\"] hello!"));
assertTrue(lines.contains("my.logger/org.ops4j.pax.logging.it.Log4J2MessagesIntegrationTest ${sd:type}/map1 [INFO] key1=\"map1\""));

配置为:

log4j2.appender.console.type = Console
log4j2.appender.console.name = console
log4j2.appender.console.layout.type = PatternLayout
log4j2.appender.console.layout.pattern = %c/%C ${sd:type}/${map:key1} [%p] %m%n
log4j2.rootLogger.level = info
log4j2.rootLogger.appenderRef.file.ref = console

(如果通过Karaf中的etc/org.ops4j.pax.logging.cfg进行配置,则必须使用已使用的转义序列)。

本文链接:https://www.f2er.com/3100536.html

大家都在问