I don't know if using the Jndi discriminator is safe or a good practice, but
it seems to be the way Logback solves this issue : http://logback.qos.ch/manual/loggingSeparation.html
They indicate that the performance can be better in adding this to your configuration :
<filter>
<filter-name>LoggerContextFilter</filter-name>
<filter-class>ch.qos.logback.classic.selector.servlet.LoggerContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoggerContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
On an other hand, I can share what I'm trying to do to avoid setting the system properties logback.ContextSelector=JNDI.
I use instead the MDCBasedDiscriminator which will get the discriminating value defined with MDC.put(key,value).
The MDC map is available as a thread local variable, so it must be set for every thread initiated by the web server.
For this initialisation I used a javax.servlet.Filter placed before other filters, this filter will put the correct value in MDC.
I don't think this is better than what you did, but it's an alternative to the JNDI property, the problem is that the shutting down log are in the unknown.log.
Here is some code :
public class WarLoggingFilter implements Filter {
private static final String WAR_NAME_ATTRIBUTE = "WAR_NAME";
private String warName;
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
warName = filterConfig.getInitParameter(WAR_NAME_ATTRIBUTE);
}
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws IOException, ServletException {
insertIntoMDC(warName);
chain.doFilter(request, response);
}
private void clearMDC() {
MDC.remove(WAR_NAME_ATTRIBUTE);
}
private static void insertIntoMDC(final String warName) {
MDC.put(WAR_NAME_ATTRIBUTE, warName);
}
@Override
public void destroy() {
clearMDC();
}
/**
* Register this filter in the servlet context. Adds the necessary init
* parameter.
*
* @param warName
* @param servletContext
*/
public static void registerMe(final String warName, final ServletContext servletContext) {
// MDC for the startup thread
insertIntoMDC(warName);
// MCD for next threads
final Dynamic addFilter = servletContext.addFilter(warName, WarLoggingFilter.class);
addFilter.setInitParameter(WarLoggingFilter.WAR_NAME_ATTRIBUTE, warName);
addFilter.addMappingForUrlPatterns(null, false, "/*");
}
}
And the logback file :
<appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
<discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator">
<key>WAR_NAME</key>
<defaultValue>unknown</defaultValue>
</discriminator>
<sift>
<appender name="FILE-${WAR_NAME}" class="ch.qos.logback.core.FileAppender">
<file>/tmp/${WAR_NAME}.log</file>
<encoder>
<pattern>%date{ISO8601} %-5level %logger{30}\(%line\) - %message%n</pattern>
</encoder>
</appender>
</sift>
</appender>
And the registration can be for example in a spring security initializer :
public class MySecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
/**
* Invoked before the springSecurityFilterChain is added.
*
* @param servletContext
* the {@link ServletContext}
*/
@Override
protected void beforeSpringSecurityFilterChain(final ServletContext servletContext) {
// Tell logback to log this web app events in a separate file
WarLoggingFilter.registerMe("my_webapp", servletContext);
}