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]

Reply via email to