将动态值传递到log4j2 xml配置

j13ufse2  于 2023-11-18  发布在  其他
关注(0)|答案(2)|浏览(216)

我正在尝试使用log4j2编写一个日志模块,需要将日志以json的形式写入控制台STDOUT。
为此,我尝试使用JSON格式的PatternLayout,如下所示。
我在将值从代码动态传递到log4j2.xml配置文件以在运行时编写日志时替换它们时遇到了一些困难。
我尝试使用StructuredDataMessage和MapMessages来替换https://logging.apache.org/log4j/2.0/manual/lookups.html中提到的Map中的值。
我也试过Stringdom和ContextMaplookup,但到目前为止还没有成功。
下面是我的xml配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <Configuration status="WARN" name="App" packages="com.test.common.logging">
  3. <Properties>
  4. <Property name="filename">target/rolling1/rollingtest.log</Property>
  5. <Property name="maptype">$${map:type}</Property>
  6. </Properties>
  7. <ThresholdFilter level="debug"/>
  8. <Appenders>
  9. <Console name="Console" target="SYSTEM_OUT">
  10. <PatternLayout pattern="%highlight{{'logged time': '%d{dd MMM yyyy HH:mm:ss}',
  11. 'LEVEL' : '%level',
  12. 'CLASS' : '%c{-1}',
  13. 'Module' : '[%t]',
  14. 'message' : '%m',
  15. 'error' : '%exception',
  16. 'class' : '%C',
  17. 'threadid' : '%tid',
  18. 'threadname' : '%thread',
  19. 'whatisthis' : '${filename}',
  20. 'processid' : '%pid',
  21. 'logdir' : '$${sd:type}'
  22. 'location' : '${log4j:configLocation}'
  23. 'systemproperty' : '$${ctx:key-}'
  24. }}%n"/>
  25. </Console>
  26. </Appenders>
  27. <Loggers>
  28. <Root level="trace">
  29. <AppenderRef ref="Console"/>
  30. </Root>
  31. </Loggers>
  32. </Configuration>

字符串
下面是我的代码,我试图通过使用结构化数据消息,strlookup和mapmessage动态值

  1. public class App
  2. {
  3. public static void main( String[] args )
  4. {
  5. Logger logger = LogManager.getLogger(App.class);
  6. // ConfigurationBuilder<BuiltConfiguration> builder
  7. // = ConfigurationBuilderFactory.newConfigurationBuilder();
  8. //
  9. // LayoutComponentBuilder standard
  10. // = builder.newLayout("PatternLayout");
  11. // standard.
  12. //
  13. System.out.println( "Hello World!" );
  14. StructuredDataMessage message = new StructuredDataMessage("1", "name", "string");
  15. message.put("1", "nme");
  16. // MapMessage mapm = new MapMessage(map)
  17. MapMessage map = new MapMessage();
  18. map.put("type", "value");
  19. map.put("key", "value");
  20. map.put("name", "arun");
  21. StrLookup strlook = new StrLookup() {
  22. public String lookup(LogEvent event, String key) {
  23. // TODO Auto-generated method stub
  24. return null;
  25. }
  26. public String lookup(String key) {
  27. // TODO Auto-generated method stub
  28. return "value";
  29. }
  30. };
  31. ContextMapLookup lookup = new ContextMapLookup();
  32. System.out.println(lookup.lookup("key"));
  33. System.out.println(strlook.lookup("key"));
  34. // MapLookup.setMainArguments(args);
  35. System.setProperty("log_dir", App.class.getSimpleName());;
  36. logger.trace("trace log message");
  37. logger.debug("Debug log message");
  38. logger.info("Info log message");
  39. logger.error("Error log message");
  40. logger.fatal("Fatal log message");
  41. logger.info("Info log message[]");
  42. logger.error("null exception[]", new NullPointerException());
  43. // Lay
  44. }
  45. }


我的输出:

  1. Hello World!
  2. null
  3. value
  4. [36m{'logged time': '24 Aug 2018 12:32:51', 'LEVEL' : 'DEBUG', 'CLASS' : 'test.common.logging.App', 'Module' : '[main]', 'message' : 'Debug log message', 'error' : '', 'class' : 'com.test.common.logging.App', 'threadid' : '1', 'threadname' : 'main', 'whatisthis' : 'target/rolling1/rollingtest.log', 'processid' : 'DEBUGid', 'logdir' : '${sd:type}' 'location' : '/Users/parunkarthick/ferry-commons/common/logging/target/classes/log4j2.xml' 'systemproperty' : '${ctx:key}' [m}
  5. [32m{'logged time': '24 Aug 2018 12:32:51', 'LEVEL' : 'INFO', 'CLASS' : 'test.common.logging.App', 'Module' : '[main]', 'message' : 'Info log message', 'error' : '', 'class' : 'com.test.common.logging.App', 'threadid' : '1', 'threadname' : 'main', 'whatisthis' : 'target/rolling1/rollingtest.log', 'processid' : 'INFOid', 'logdir' : '${sd:type}' 'location' : '/Users/parunkarthick/ferry-commons/common/logging/target/classes/log4j2.xml' 'systemproperty' : '${ctx:key}' [m}
  6. [1;31m{'logged time': '24 Aug 2018 12:32:51', 'LEVEL' : 'ERROR', 'CLASS' : 'test.common.logging.App', 'Module' : '[main]', 'message' : 'Error log message', 'error' : '', 'class' : 'com.test.common.logging.App', 'threadid' : '1', 'threadname' : 'main', 'whatisthis' : 'target/rolling1/rollingtest.log', 'processid' : 'ERRORid', 'logdir' : '${sd:type}' 'location' : '/Users/parunkarthick/ferry-commons/common/logging/target/classes/log4j2.xml' 'systemproperty' : '${ctx:key}' [m}
  7. [1;31m{'logged time': '24 Aug 2018 12:32:51', 'LEVEL' : 'FATAL', 'CLASS' : 'test.common.logging.App', 'Module' : '[main]', 'message' : 'Fatal log message', 'error' : '', 'class' : 'com.test.common.logging.App', 'threadid' : '1', 'threadname' : 'main', 'whatisthis' : 'target/rolling1/rollingtest.log', 'processid' : 'FATALid', 'logdir' : '${sd:type}' 'location' : '/Users/parunkarthick/ferry-commons/common/logging/target/classes/log4j2.xml' 'systemproperty' : '${ctx:key}' [m}
  8. [32m{'logged time': '24 Aug 2018 12:32:51', 'LEVEL' : 'INFO', 'CLASS' : 'test.common.logging.App', 'Module' : '[main]', 'message' : 'Info log message[]', 'error' : '', 'class' : 'com.test.common.logging.App', 'threadid' : '1', 'threadname' : 'main', 'whatisthis' : 'target/rolling1/rollingtest.log', 'processid' : 'INFOid', 'logdir' : '${sd:type}' 'location' : '/Users/parunkarthick/ferry-commons/common/logging/target/classes/log4j2.xml' 'systemproperty' : '${ctx:key}' [m}
  9. [1;31m{'logged time': '24 Aug 2018 12:32:51', 'LEVEL' : 'ERROR', 'CLASS' : 'test.common.logging.App', 'Module' : '[main]', 'message' : 'null exception[]', 'error' : ' java.lang.NullPointerException
  10. at com.test.common.logging.App.main(App.java:69)
  11. ', 'class' : 'com.test.common.logging.App', 'threadid' : '1', 'threadname' : 'main', 'whatisthis' : 'target/rolling1/rollingtest.log', 'processid' : 'ERRORid', 'logdir' : '${sd:type}' 'location' : '/Users/parunkarthick/ferry-commons/common/logging/target/classes/log4j2.xml' 'systemproperty' : '${ctx:key}' [m}


如果您看到lastvalue系统属性没有通过从代码值替换而按预期反映。

rbpvctlc

rbpvctlc1#

我认为你对log4j 2有一些基本的误解。与其我试图列出我在你的代码中看到的所有问题,我认为最好的办法是我提供一些示例代码并解释输出。我想当你看到一些工作代码时,你会明白你错在哪里。
为了这个例子的目的,我简化了log4j 2配置文件,删除了看起来工作正常的元素,并专注于那些不工作的元素。我将PatternLayout更改为以下内容:

  1. <PatternLayout pattern="{'LEVEL' : '%level', 'typeFromStructMsg' : '${sd:type}', 'contextValue' : '${ctx:myContextKey}', 'nameFromMapMsg' : '${map:name}', 'mySysProperty' : '${sys:mySysProperty}'}%n" />

字符串
我还修改了你提供的App类:

  1. package example;
  2. import org.apache.logging.log4j.LogManager;
  3. import org.apache.logging.log4j.Logger;
  4. import org.apache.logging.log4j.ThreadContext;
  5. import org.apache.logging.log4j.message.MapMessage;
  6. import org.apache.logging.log4j.message.StringFormattedMessage;
  7. import org.apache.logging.log4j.message.StringMapMessage;
  8. import org.apache.logging.log4j.message.StructuredDataMessage;
  9. public class App {
  10. private static final Logger logger = LogManager.getLogger();
  11. public static void main( String[] args )
  12. {
  13. ThreadContext.put("myContextKey", "myContextValue");
  14. StructuredDataMessage structMsg = new StructuredDataMessage("1", "name", "string");
  15. StringMapMessage mapMsg = new StringMapMessage();
  16. mapMsg.put("name", "arun");
  17. System.setProperty("mySysProperty", "sys prop value");
  18. logger.info(mapMsg);
  19. logger.warn(structMsg);
  20. logger.error("Error log message");
  21. }
  22. }


运行App类时,将生成以下控制台输出:

  1. {'LEVEL' : 'INFO', 'typeFromStructMsg' : '${sd:type}', 'contextValue' : 'myContextValue', 'nameFromMapMsg' : 'arun', 'mySysProperty' : 'sys prop value'}
  2. {'LEVEL' : 'WARN', 'typeFromStructMsg' : 'string', 'contextValue' : 'myContextValue', 'nameFromMapMsg' : '${map:name}', 'mySysProperty' : 'sys prop value'}
  3. {'LEVEL' : 'ERROR', 'typeFromStructMsg' : '${sd:type}', 'contextValue' : 'myContextValue', 'nameFromMapMsg' : '${map:name}', 'mySysProperty' : 'sys prop value'}


请注意,在输出的第一行中,我们看到的是:'nameFromMapMsg' : 'arun',而在其他行中,我们看到的是:'nameFromMapMsg' : '${map:name}'
输出的第一行是由这行代码生成的:logger.info(mapMsg);,它将一个名为mapMsgMapMessage的示例传递给info方法。由于消息是MapMessage的示例,并且它包含一个名为name的键,因此map查找将用它在这就是为什么只有第一行输出显示'nameFromMapMsg' : 'arun'-其他输出行是从不是MapMessage示例的消息生成的。
类似地,请注意在输出的第二行中,我们看到了'typeFromStructMsg' : 'string'。这是因为日志是从StructuredDataMessage生成的,StructuredDataMessage定义为“string”类型:
StructuredDataMessage structMsg = new StructuredDataMessage("1", "name", "string");
在输出的其他行中,我们没有传递StructuredDataMessage,所以在这些行中,我们看到'typeFromStructMsg' : '${sd:type}'是因为log4j 2找不到该类型的值。
最后,请注意在所有输出行中我们都看到了这个:'mySysProperty' : 'sys prop value'。这是因为系统属性mySysProperty不依赖于传递给记录器的消息的类型。这个查找总是能够找到系统属性mySysProperty的值,因为我们定义了它:

  1. System.setProperty("mySysProperty", "sys prop value");


并且,正如我之前所说的,系统属性独立于消息(它们不存储在消息中)。
'contextValue' : 'myContextValue'也是如此-ThreadContext独立于消息,因为我们为这个键定义了一个值:

  1. ThreadContext.put("myContextKey", "myContextValue");


无论发送到记录器的消息的种类如何,查找总是能够找到该值。
我希望这个示例代码有助于说明如何使用一些查找以及如何设计log4j 2的架构。祝你好运!

展开查看全部
mpbci0fu

mpbci0fu2#

在xml文件中编辑PatternLayout本身是不可行的,如果值是静态的并且保持不变,那么它就可以工作,否则你需要通过扩展内置方法来实现自定义模式,然后相应地格式化你的消息。下面的链接将让你知道同样的事情。
https://blog.10pines.com/2020/03/02/log-custom-json-with-log4j2/

相关问题