Reputation: 101
I have an application that instantiates several threads. Each service has the same log4j2 configuration which writes to logs and to socket appender. I need to get the Host information in all logs and socket output, but using the
InetAddress addr = InetAddress.getLocalHost();
ThreadContext.put("Host", addr.getHostName());
I receive that information only in the "main" thread.
So, as explain here https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/ContextDataInjector.html
In some asynchronous models, work may be delegated to several threads, while conceptually this work shares the same context. In such models, storing context data in ThreadLocal variables is not convenient or desirable. Users can configure the ContextDataInjectorFactory to provide custom ContextDataInjector objects, in order to initialize log events with context data from any arbitrary context.
I should create a custom ContextDataInjector, but I cannot code it. I coded this
List<Property> propertiesTest = new ArrayList<>();
propertiesTest.add(Property.createProperty("Host", "test"));
StringMap reusabletest = null;
ContextDataInjector prueba = ContextDataInjectorFactory.createInjector();
prueba.injectContextData(propertiesTest, reusabletest);
but It doesn't work...
The other way is implements the ContextDataInjector in this way:
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;
}
But it returns null point exception. Any suggestions please?
Best Regards
Upvotes: 0
Views: 2204
Reputation: 101
Finally I called directly the method and I've made a test. Using the
ThreadContext.put("Host", addr.getHostName())
I can get the "Host" only to the main, while if I avoid that structure, I haven't any value, neither into the main I don't understand where is the error.
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();
Upvotes: 0
Reputation: 36754
You don't provide a stack trace but I suspect the nullpointer exception is caused by your implementation of rawContextData()
. It must not return null
.
Please see the Log4j2 built-in implementations of the ContextDataInjector
interface for ideas on what to return from this method.
To install a custom context data injector, you need to specify the fully qualified class of your implementation in system property log4j2.ContextDataInjector
. See ContextDataInjectorFactory.
Upvotes: 2