I don't believe there is a problem with ThreadContext. I created a unit test
that verifies it and then tried to run yours. However, I had to modify yours
as it contains an error. The version of BoringLoggingClass's run method below
is synchronizing on "this" which won't accomplish anything (each instance is
synchronizing on itself). I modified the run method to do
private static AtomicInteger threadCount = new AtomicInteger(0);
public void run() {
int count = threadCount.getAndIncrement();
// This is to test the inheritance of a ThreadContext.
// The third thread will inherit the id Main from the unit test.
if (count != 2) {
ThreadContext.put("id", "Thread_" + count);
}
for(int i = 0; i < 1000; i++) {
logger.error("I am logging: " + i);
}
ThreadContext.clear();
}
The code above ran and printed the expected output.
Ralph
On Dec 26, 2012, at 7:52 AM, Michael Minella wrote:
> Progress continues...
>
> Using beta-4-SNAPSHOT now generates a file per thread (as expected) which is
> great. However, I do have one other issue with the new version. The
> inheritance of ThreadContext values does not seem to be working. If I set a
> value in a parent thread and do not override it in the child, the child is
> not picking it up (this was working in the previous version). Using the
> example I previously provided, the third instance of BoringLoggingClass
> should be logging with the ThreadContext's id set to "Main". With the latest
> version of log4j, it is null.
>
> Thanks,
> Michael T Minella
>
>
> ----- Original Message -----
> From: "Ralph Goers" <[email protected]>
> To: "Log4J Users List" <[email protected]>
> Sent: Monday, December 24, 2012 12:03:43 PM
> Subject: Re: Map Lookup Question
>
> You are probably encountering
> https://issues.apache.org/jira/browse/LOG4J2-129. This has been fixed in
> trunk. If you check it out and build it and then use 2.0-beta4-SNAPSHOT as
> the version it should work.
>
> Ralph
>
>
> On Dec 24, 2012, at 7:48 AM, Michael Minella wrote:
>
>> Ralph,
>>
>> So we seem to be making progress. Using the Routing appender, I am now
>> getting a log file named after one of the values I put on the ThreadContext.
>> However, it still seems to only be evaluated once.
>>
>> What I currently have is a unit test that creates four threads. In each
>> thread, I put an id on the ThreadContext and loop a number of times logging
>> a message. The behavior I'm looking for is a log file per thread
>> (technically one per id I put on the ThreadContext) based on the id placed
>> in the ThreadContext (so for my test below, I would expect a Main.log,
>> Thread_0.log, Thread_1.log, and Thread_3.log). What I am seeing is one file
>> is created, named after one of the threads and all of the output (regardless
>> of the id) goes to that one file. Below are the classes/configuration
>> involved:
>>
>> UNIT TEST:
>> =========================================================
>> package org.somepackage.log4j;
>>
>> import org.apache.logging.log4j.ThreadContext;
>> import org.junit.Test;
>>
>> public class Log4jThreadContextTests {
>>
>> @Test
>> public void testThreadContextLogging() throws Exception {
>> ThreadContext.put("id", "Main");
>>
>> new Thread(new BoringLoggingClass()).start();
>> new Thread(new BoringLoggingClass()).start();
>> new Thread(new BoringLoggingClass()).start();
>> new Thread(new BoringLoggingClass()).start();
>>
>> //This is needed because JUnit kills all processing once this
>> method returns.
>> Thread.sleep(2000);
>> }
>> }
>>
>>
>> RUNNABLE:
>> =========================================================
>> package org.somepackage.log4j;
>>
>> import org.apache.logging.log4j.LogManager;
>> import org.apache.logging.log4j.Logger;
>> import org.apache.logging.log4j.ThreadContext;
>>
>> public class BoringLoggingClass implements Runnable {
>>
>> private Logger logger = LogManager.getLogger(BoringLoggingClass.class);
>> private static int threadCount = 0;
>>
>> public void run() {
>> synchronized (this) {
>> // This is to test the inheritance of a ThreadContext.
>> // The third thread will inherit the id Main from the
>> unit test.
>> if(threadCount != 2) {
>> ThreadContext.put("id", "Thread_" +
>> threadCount);
>> }
>> threadCount++;
>> }
>>
>> for(int i = 0; i < 1000; i++) {
>> logger.error("I am logging: " + i);
>> }
>>
>> ThreadContext.clear();
>> }
>> }
>>
>> log4j.xml:
>> =========================================================
>> <?xml version="1.0" encoding="UTF-8"?>
>> <configuration status="OFF">
>> <appenders>
>> <Console name="Console" target="SYSTEM_OUT">
>> <PatternLayout pattern="%X{id} %d{HH:mm:ss.SSS} [%t] %-5level
>> %logger{36} - %msg%n"/>
>> </Console>
>> <Routing name="Routing">
>> <Routes pattern="$${ctx:id}">
>> <Route>
>> <File name="File" fileName="/tmp/${ctx:id}.log">
>> <PatternLayout pattern="%X{id} %d{HH:mm:ss.SSS} [%t]
>> %-5level %logger{36} - %msg%n"/>
>> </File>
>> </Route>
>> </Routes>
>> </Routing>
>> <!-- <File name="File" fileName="/tmp/$${ctx:id}.log">
>> <PatternLayout pattern="%X{id} %d{HH:mm:ss.SSS} [%t] %-5level
>> %logger{36} - %msg%n"/>
>> </File>
>> --> </appenders>
>> <loggers>
>> <root level="debug">
>> <appender-ref ref="Routing"/>
>> </root>
>> </loggers>
>> </configuration>
>>
>> From the above, I end up with one file named either Main.log or Thread_X.log
>> (X being the thread number set above), however the output in that file shows
>> the results from all of the threads (via the %X{id} at the beginning of each
>> line) as shown below:
>>
>> Thread_0 09:30:52.519 [Thread-1] ERROR
>> org.somepackage.log4j.BoringLoggingClass - I am logging: 0
>> Thread_3 09:30:52.519 [Thread-4] ERROR
>> org.somepackage.log4j.BoringLoggingClass - I am logging: 0
>> Main 09:30:52.519 [Thread-3] ERROR org.somepackage.log4j.BoringLoggingClass
>> - I am logging: 0
>> Thread_1 09:30:52.519 [Thread-2] ERROR
>> org.somepackage.log4j.BoringLoggingClass - I am logging: 0
>> Thread_0 09:30:52.525 [Thread-1] ERROR
>> org.somepackage.log4j.BoringLoggingClass - I am logging: 1
>> ...
>>
>> Thanks,
>> Michael T Minella
>>
>>
>> ----- Original Message -----
>> From: "Ralph Goers" <[email protected]>
>> To: "Log4J Users List" <[email protected]>
>> Sent: Sunday, December 23, 2012 2:15:15 PM
>> Subject: Re: Map Lookup Question
>>
>> I started thinking about this and realized I have given you an incorrect
>> answer.
>>
>> The file appender is initialized when the configuration is processed and is
>> not reevaluated for every event. Thus giving it a variable with 2 '$'
>> characters doesn't make sense. Likewise, when the configuration is
>> processed it is likely that your ThreadContext.put() call hasn't taken place
>> yet and so you are getting the variable expression as the value since it
>> hasn't been defined. If you really want an appender that can write to a
>> different file based on a ThreadContext value then you would need to use the
>> RoutingAppender.
>>
>> Ralph
>>
>>
>> On Dec 21, 2012, at 4:23 PM, Michael Minella wrote:
>>
>>>
>>> I'm looking at the log4j 2 's thread specific features and had a question.
>>> In my code I set an id as follows:
>>>
>>>
>>>
>>> ThreadContext.put( "id" , "Main" );
>>>
>>>
>>> and attempt to reference it in my configuration file as shown below:
>>>
>>>
>>>
>>> < File name = "File" fileName = "/tmp/myLog.log" >
>>> < PatternLayout pattern = "%X{id} %d{HH:mm:ss.SSS} [%t] %-5level
>>> %logger{36} - %msg ${ctx:id} %n" />
>>> </ File >
>>>
>>>
>>> If I use the lookup in the pattern layout to test it, it works fine.
>>> However, if I move that lookup to the fileName attribute in the line above,
>>> the replacement doesn't occur (my file ends up being named
>>> /tmp/${ctx.id}.log for example). Is that a limitation of that lookup or am
>>> I missing something? Any insight that can be provided is appreciated.
>>> Thanks in advance!
>>>
>>> Thanks,
>>> Michael T Minella
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: [email protected]
>> For additional commands, e-mail: [email protected]
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: [email protected]
>> For additional commands, e-mail: [email protected]
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]