繁体   English   中英

"程序化自定义 Json 布局 Log4j2"

[英]Programmatic Custom Json Layout Log4j2

我有使用Log4j2 framework.<\/code>的Java<\/code>桌面客户端应用程序。 使用自定义参数记录异常或信息时使用 JSON 结构。 出于这个原因,我正在尝试以编程方式配置 Log4j2。 我知道建议使用基于文件的配置,但似乎最好为我的案例以编程方式初始化框架。

这是我正在尝试构建的结构。

  • 自定义 Json 布局<\/li>
  • HttpAppender<\/code>将通过 HTTP 发送日志<\/li>
  • 如果 HttpAppender 失败,它将使用JdbcAppender<\/code>写入数据库<\/li>
  • 如果 JdbcAppender 失败,它将使用FileAppender<\/code>写入日志文件<\/li><\/ul>

    我能够生成JsonLayout<\/code>但我无法添加自定义字段并从默认结构中删除现有字段。 我可能已经检查了 50 多篇文章\/问题,但没有一个对我有用。 这是我拥有的当前代码。

    此代码打印到控制台并将 Json 格式的日志记录写入文件。 自定义值不会添加到 Json。 我尝试通过其builder<\/code>创建 JsonLayout,但我无法将其添加到构建器本身。

    我需要添加到 Json 的参数是动态的,我不知道自定义节点的键和值。 在这个阶段,我试图在将其写入文件时创建一个自定义 Json 布局。

    我可能做错了,所以请指教! 我愿意接受建议。 谢谢。

通过调用LayoutComponentBuilderaddComponent方法,可以将自定义值作为键值对添加为组件。 以下代码片段显示了一个示例:

ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
        AppenderComponentBuilder console =
                builder.newAppender("stdout", "Console")
                        .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
        LayoutComponentBuilder jsonLayout
                = builder.newLayout("JsonLayout")
                .addAttribute("complete", false)
                .addAttribute("compact", false)
                .addComponent(builder.newKeyValuePair("key1", "value1"))
                .addComponent(builder.newKeyValuePair("key2", "value2"));
        console.add(jsonLayout);
        builder.add(console);
        RootLoggerComponentBuilder rootLogger
                = builder.newRootLogger(Level.INFO);
        rootLogger.add(builder.newAppenderRef("stdout"));
        builder.add(rootLogger);
        builder.writeXmlConfiguration(System.out);
        return builder;

这是相应的 xml 输出:

<?xml version='1.0' encoding='UTF-8'?>
<Configuration>
    <Appenders>
        <Console name="stdout" target="SYSTEM_OUT">
            <JsonLayout complete="false" compact="false">
                <KeyValuePair key="key1" value="value1"/>
                <KeyValuePair key="key2" value="value2"/>
            </JsonLayout>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="stdout"/>
        </Root>
    </Loggers>
</Configuration>

使用 log4j 2.17.1 测试

您可以使用以下类从日志中减去您想要的类中的任何属性。

     import com.fanap.midhco.applicationUtil.JsonUtil;
     import com.fasterxml.jackson.core.util.MinimalPrettyPrinter;
     import com.fasterxml.jackson.databind.ObjectWriter;
     import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
     import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
     import org.apache.logging.log4j.core.Layout;
     import org.apache.logging.log4j.core.LogEvent;
     import org.apache.logging.log4j.core.config.Node;
     import org.apache.logging.log4j.core.config.plugins.Plugin;
     import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
     import org.apache.logging.log4j.core.config.plugins.PluginFactory;
     import org.apache.logging.log4j.core.impl.Log4jLogEvent;
     import org.apache.logging.log4j.core.jackson.JsonConstants;
     import org.apache.logging.log4j.core.jackson.Log4jJsonObjectMapper;
     import org.apache.logging.log4j.core.layout.AbstractStringLayout;
     import org.apache.logging.log4j.core.util.StringBuilderWriter;
     import org.apache.logging.log4j.util.Strings;
     
     import java.io.IOException;
     import java.nio.charset.StandardCharsets;
     import java.util.HashSet;
     import java.util.Set;
     
     @Plugin(name = "MineCustLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
     public class MineCustLayout extends AbstractStringLayout {
     
         private final ObjectWriter objectWriter;
     
         @PluginFactory
         public static MineCustLayout createLayout(
                 @PluginAttribute(value = "locationInfo", defaultBoolean = false) final boolean locationInfo, @PluginAttribute(value = "eventEol", defaultBoolean = true) final boolean eventEol
         ) {
             final SimpleFilterProvider filters = new SimpleFilterProvider();
             final Set<String> except = new HashSet<>();
             if (!locationInfo) {
                 except.add(JsonConstants.ELT_SOURCE);
             }
             except.add("loggerFqcn");
             except.add("level");
             except.add("timeMillis");
             except.add("instant");
             except.add("thread");
             except.add("loggerName");
             except.add("threadId");
             except.add("threadPriority");
             except.add("contextMap");
             except.add("endOfBatch");
             except.add(JsonConstants.ELT_NANO_TIME);
             filters.addFilter(Log4jLogEvent.class.getName(), SimpleBeanPropertyFilter.serializeAllExcept(except));
             final ObjectWriter writer = new Log4jJsonObjectMapper().writer(new MinimalPrettyPrinter());
             return new MineCustLayout(writer.with(filters));
         }
     
         public MineCustLayout(ObjectWriter objectWriter) {
             super(StandardCharsets.UTF_8, null, null);
             this.objectWriter = objectWriter;
         }
     
     
         @Override
         public String toSerializable(LogEvent event) {
             final StringBuilderWriter writer = new StringBuilderWriter();
             try {
                 objectWriter.writeValue(writer, event);
     //            writer.write('\n');
                 return JsonUtil.getJsonObject(writer.toString()).get("message").toString() + '\n';
             } catch (final IOException e) {
                 LOGGER.error(e);
                 return Strings.EMPTY;
             }
         }
     }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM