【问题标题】:Log4j2 Custom ContextDataInjector in multi-threaded mode多线程模式下的 Log4j2 自定义 ContextDataInjector
【发布时间】:2017-08-07 22:36:29
【问题描述】:

我有一个实例化多个线程的应用程序。每个服务都具有相同的 log4j2 配置,用于写入日志和套接字附加程序。 我需要在所有日志和套接字输出中获取主机信息,但使用

InetAddress addr = InetAddress.getLocalHost();
ThreadContext.put("Host", addr.getHostName());

我只在“主”线程中收到该信息。

所以,在这里解释https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/ContextDataInjector.html

在一些异步模型中,工作可能被委托给多个线程,而从概念上讲,这项工作共享相同的上下文。在此类模型中,将上下文数据存储在 ThreadLocal 变量中既不方便也不可取。用户可以配置 ContextDataInjectorFactory 以提供自定义的 ContextDataInjector 对象,以便使用来自任意上下文的上下文数据初始化日志事件。

我应该创建一个自定义的 ContextDataInjector,但我无法编写代码。 我编码了这个

List<Property> propertiesTest = new ArrayList<>();
propertiesTest.add(Property.createProperty("Host", "test"));
StringMap reusabletest = null;

ContextDataInjector prueba = ContextDataInjectorFactory.createInjector();
prueba.injectContextData(propertiesTest, reusabletest);

但它不起作用......

另一种方式是这样实现ContextDataInjector:

 public class Log4j2Manager implements ContextDataInjector
{
private static Log4j2Configuration config;
private static final String PROPERTIES_PATH = "/etc//Log4j2Manager/Log4j2Manager.properties";
private final static Logger LOG = LogManager.getLogger(Log4j2Manager.class);

private static Log4j2slave[] workers = null;

public Log4j2Manager(String configPath) throws Exception
{
    List<Property> propertiesTest = new ArrayList<>();
    propertiesTest.add(Property.createProperty("Host", "test"));
    StringMap reusableTest = null;

    injectContextData(propertiesTest, reusableTest);
    workers = new Log4j2slave[config.NumWorkers];
    for (int i = 0; i < workers.length; i++) 
    {
        workers[i] = new Log4j2slave(i);
        Thread.sleep(1000);
    }
    .... 
 } 
    ....
 @Override
 public StringMap injectContextData(List<Property> properties, StringMap reusable) 
 {
    if (properties == null || properties.isEmpty()) 
    {
        // assume context data is stored in a copy-on-write data structure
        // that is safe to pass to another thread
        return (StringMap) rawContextData();
    }
    // first copy configuration properties into the result
    ThreadContextDataInjector.copyProperties(properties, reusable);

    // then copy context data key-value pairs (may overwrite configuration
    // properties)
    reusable.putAll(rawContextData());
    return reusable;
}

@Override
public ReadOnlyStringMap rawContextData() {
    // TODO Auto-generated method stub
    return null;
}

但它返回空点异常。 请问有什么建议吗?

最好的问候

【问题讨论】:

    标签: java multithreading logging configuration log4j2


    【解决方案1】:

    最后我直接调用了这个方法,我做了一个测试。 使用

    ThreadContext.put("Host", addr.getHostName())
    

    我只能将“主机”获取到主目录,而如果我避免使用该结构,我将没有任何价值,也不会进入主目录 我不明白错误在哪里。

            InetAddress addr = InetAddress.getLocalHost();
            ThreadContext.put("Host", addr.getHostName());
    
            List<Property> properties = new ArrayList<>();
            properties.add(Property.createProperty("Host", "test"));
            StringMap reusable = null;
    
            ContextDataInjector prueba = new  ForGarbageFreeThreadContextMap();
            prueba.injectContextData(properties, reusable);
    
            Log4j2Manager Log4j2Man = new Log4j2Manager(propertiesPath);
            Log4j2Man.Start();
    

    【讨论】:

      【解决方案2】:

      您没有提供堆栈跟踪,但我怀疑 nullpointer 异常是由您的 rawContextData() 实现引起的。它不能返回null

      请查看ContextDataInjector 接口的Log4j2 built-in implementations,了解如何从该方法返回。

      要安装自定义上下文数据注入器,您需要在系统属性log4j2.ContextDataInjector 中指定实现的完全限定类。见ContextDataInjectorFactory

      【讨论】:

      • 感谢 Remko,但我不太明白。请给我一个自定义 ContextDataInjector 的代码示例好吗?
      • 使用你的例子我有一个错误 org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
      • 无法解析导入。我使用的是 2.7 版本的 log4j。
      • 该接口是2.8添加的。
      猜你喜欢
      • 1970-01-01
      • 2014-10-20
      • 2016-01-05
      • 1970-01-01
      • 1970-01-01
      • 2017-10-15
      • 1970-01-01
      • 1970-01-01
      • 2013-09-23
      相关资源
      最近更新 更多