We use MDC feature of slf4j/log4j to automatically log the details about user/client that is making the request so we can trace the things happening in the thread.
public static void setRequestId(String requestId) {
if (requestId != null) {
MDC.put("MDC_REQUEST_ID", requestId);
} else {
MDC.put("MDC_REQUEST_ID", "");
}
}
public static void setUserInContext(long userId) {
MDC.put("MDC_USER_ID", String.valueOf(userId));
}
and the log4j appender users
<appender name="RFA_ROOT" class="org.apache.log4j.rolling.RollingFileAppender">
<rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
<param name="FileNamePattern" value="${catalina.base}/logs/kp.log.%d{yyyy-MM-dd-HH}"/>
<param name="ActiveFileName" value="${catalina.base}/logs/kp.log"/>
</rollingPolicy>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%p %d{ISO8601} %t D-%X{MDC_DOMAIN} U-%X{MDC_USER_ID} S-%X{MDC_SYNC_CID} R-%X{MDC_REQUEST_ID} %c - %m%n"/>
</layout>
</appender>
This will automatically print User and request Id but when you want to get the user requests funnel through some threadpool to avoid thundering herd problem then the log4j context is not carried over and this breaks traceability. To solve this problem the easy solution is to just create your own Callable and use that in thread pool.
public abstract class MyCallable implements Callable {
private Map contextMap = AppLogger.getCopyOfContextMap();
@Override
public T call() throws Exception {
MDC.setContextMap(contextMap);
try {
return internalCall();
} finally {
MDC.clear();
}
}
protected abstract T internalCall() throws Exception;
}
MyCallable task = new MyCallable() {
@Override
public String internalCall() throws Exception {
...
}
};
and use
SpringBeanLocator.getRestRequestHelper().getRestRequestExecutors().submit(task);
This way your context would be carried over to background threads.
public static void setRequestId(String requestId) {
if (requestId != null) {
MDC.put("MDC_REQUEST_ID", requestId);
} else {
MDC.put("MDC_REQUEST_ID", "");
}
}
public static void setUserInContext(long userId) {
MDC.put("MDC_USER_ID", String.valueOf(userId));
}
and the log4j appender users
<appender name="RFA_ROOT" class="org.apache.log4j.rolling.RollingFileAppender">
<rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
<param name="FileNamePattern" value="${catalina.base}/logs/kp.log.%d{yyyy-MM-dd-HH}"/>
<param name="ActiveFileName" value="${catalina.base}/logs/kp.log"/>
</rollingPolicy>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%p %d{ISO8601} %t D-%X{MDC_DOMAIN} U-%X{MDC_USER_ID} S-%X{MDC_SYNC_CID} R-%X{MDC_REQUEST_ID} %c - %m%n"/>
</layout>
</appender>
This will automatically print User and request Id but when you want to get the user requests funnel through some threadpool to avoid thundering herd problem then the log4j context is not carried over and this breaks traceability. To solve this problem the easy solution is to just create your own Callable and use that in thread pool.
public abstract class MyCallable
private Map contextMap = AppLogger.getCopyOfContextMap();
@Override
public T call() throws Exception {
MDC.setContextMap(contextMap);
try {
return internalCall();
} finally {
MDC.clear();
}
}
protected abstract T internalCall() throws Exception;
}
MyCallable
@Override
public String internalCall() throws Exception {
...
}
};
and use
SpringBeanLocator.getRestRequestHelper().getRestRequestExecutors().submit(task);
This way your context would be carried over to background threads.
Comments
Post a Comment