Thanks hveiga for following up and posting your solution, it was helpful. I wanted to say you can avoid your filter solution by adding a second 'route' that routes all messages with no value for your routing key as explained here: http://logging.apache.org/log4j/2.x/faq.html#separate_log_files
So your updated log4j config would look like this.
<appenders>
<appender name="applicationAppender" type="RollingFile" fileName="${logFileName}" filePattern="${logFileNamePattern}" bufferedIO="true" immediateFlush="true" append="true">
<layout type="PatternLayout" pattern="${logPattern}" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="${logFileSize}" />
</Policies>
<DefaultRolloverStrategy max="${logFileCount}" />
</appender>
<Routing name="contextSpecificAppender">
<Routes pattern="$${ctx:contextId}">
<Route>
<appender name="Rolling-${ctx:contextId}" type="RollingFile" fileName="logs/${ctx:contextId}.log" filePattern="${logFileNamePattern}" bufferedIO="true" immediateFlush="true" append="true">
<layout type="PatternLayout" pattern="${logPattern}" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="${logFileSize}" />
</Policies>
<DefaultRolloverStrategy max="${logFileCount}" />
</appender>
</Route>
<Route ref="applicationAppender" key="$${ctx:contextId}">
</Route>
</Routes>
</Routing>
</appenders>
<loggers>
<root level="info">
<appender-ref ref="contextSpecificAppender"/>
</root>
</loggers>
And in your application, you can just set the ThreadContext by calling ThreadContext.put("contextId", "something") and clear it when you are done by calling ThreadContext.clear() OR ThreadContext.remove("contextId")
Lastly, I used the
<RollingFile>
element (like the examples linked above) instead of
<appender type="RollingFile">
element you used. I believe this is preferred when you migrate to log4j2 from log4j.