在项目中,我们会使用拦截器,aop或者过滤器来进行请求信息的提取,打印工作,当我们获取到需要的信息之后,就需要打印出来记录到日志中,这个时候我们会把日志记录到mdc中,然后给传递参数给log的自定义配置中使用,如下:
public class LogInterceptor extends HandlerInterceptorAdapter {
private static final String USER_ID = "USER_ID";
private static final String USER_NAME = "USER_NAME";
public static final String REQUEST_REQUEST_URL = "REQ_REQUESTURL";
public static final String REQUEST_USER_AGENT_MDC_KEY = "REQ_USERAGENT";
public static final String REQUEST_X_FORWARDED_FOR = "REQ_XFORWARDEDFOR";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
insertIntoMDC(request);
return super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
clearMDC();
super.postHandle(request, response, handler, modelAndView);
}
private void insertIntoMDC(HttpServletRequest request) {
PrincipalRo ro = null;
try {
ro = ThreadObjManager.getLoginUser();
} finally {
if (ro != null) {
if (ro.getId() != null) {
MDC.put(USER_ID, ro.getId().toString());
}
if (ro.getUsername() != null && !"".equals(ro.getUsername())) {
MDC.put(USER_NAME, ro.getUsername());
}
}
StringBuffer requestURL = request.getRequestURL();
if (requestURL != null) {
String allUrl = requestURL.toString();
if (request.getQueryString() != null) {
allUrl = allUrl + "?" + request.getQueryString();
}
MDC.put(REQUEST_REQUEST_URL, allUrl);
}
MDC.put(REQUEST_USER_AGENT_MDC_KEY, request
.getHeader("User-Agent"));
MDC.put(REQUEST_X_FORWARDED_FOR, request
.getHeader("X-Forwarded-For"));
}
}
private void clearMDC() {
if (MDC.get(USER_ID) != null) {
MDC.remove(USER_ID);
}
if (MDC.get(USER_NAME) != null) {
MDC.remove(USER_NAME);
}
if (MDC.get(REQUEST_REQUEST_URL) != null) {
MDC.remove(REQUEST_REQUEST_URL);
}
MDC.remove(REQUEST_USER_AGENT_MDC_KEY);
MDC.remove(REQUEST_X_FORWARDED_FOR);
}
}
我们在代码中为mdc插入用户的信息,用户使用的ip地址user-agent等信息,然后我们在自定义日志的时候就可以使用。mdc是线程独有的,使用的是threadloaclmap,保证了各个线程的在MDC键值对的独立性.
我们在我们的logback.xml文件中就可以配置如下:
<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="APP_NAME" value="cssmanager" />
<property name="LOG_HOME" value="/data/html/logs/${APP_NAME}" />
<property name="MAX_HISTORY" value="30" />
在这个地方进行配置:
<property name="ENCODER_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %X{REQ_REQUESTURL}-%X{REQ_USERAGENT}-%X{REQ_XFORWARDEDFOR}-%X{USER_ID}-%X{USER_NAME}-%X{INSIGHT_REQUEST_ID} [%thread] ${APP_NAME}-%-5level %logger{36} - %msg%n" />
<!-- 第三方框架-->
<!-- spring-->
<appender name="spring" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/spring.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/spring-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
<!-- mybatis-->
<appender name="mybatis" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/mybatis.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/mybatis-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
<!-- zk-->
<appender name="zookeeper" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/zookeeper.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/zookeeper-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
<!-- dubbo-->
<appender name="dubbo" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/dubbo.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/dubbo-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
<!-- qccrframework-->
<appender name="qccrframework" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/qccr-framework.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/qccr-framework-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
<!-- authmanager-->
<appender name="authmanager" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/qccr-authmanager.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/qccr-authmanager-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
<!-- cssmanager自己-->
<!--error-->
<appender name="cssmanager-error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}-error.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${APP_NAME}-error-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
<!-- biz-->
<appender name="cssmanager-biz" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}-biz.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${APP_NAME}-biz-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
<!-- integ-->
<appender name="cssmanager-integ" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}-integ.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${APP_NAME}-integ-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
<!-- sql-->
<appender name="sql" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}-sql.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${APP_NAME}-sql-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
<!-- biz-->
<appender name="cssmanager-aop" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}-aop.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${APP_NAME}-biz-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
<!-- 所有日志-->
<appender name="all" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}-all.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${APP_NAME}-all.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
<!-- 第三方框架-->
<!-- Spring日志 -->
<logger name="org.springframework" additivity="false">
<level value="ERROR"/>
<appender-ref ref="spring" />
</logger>
<!-- mybatis日志 -->
<logger name="com.mybatis" additivity="false">
<level value="ERROR"/>
<appender-ref ref="mybatis" />
</logger>
<!-- zookeeper日志 -->
<logger name="org.apache.zookeeper" additivity="false">
<level value="ERROR"/>
<appender-ref ref="zookeeper" />
</logger>
<!-- dubbo -->
<logger name="com.alibaba.dubbo" additivity="false">
<level value="ERROR"/>
<appender-ref ref="dubbo" />
</logger>
<!-- qccrframework -->
<logger name="com.qccr.framework" additivity="false">
<level value="ERROR"/>
<appender-ref ref="qccrframework" />
</logger>
<!-- authoritymanager -->
<logger name="com.qccr.authoritymanager" additivity="false">
<level value="ERROR"/>
<appender-ref ref="authmanager" />
</logger>
<!-- cssmanager自己 -->
<logger name="com.qccr.cssmanager.service">
<level value="INFO"/>
<appender-ref ref="cssmanager-biz" />
</logger>
<logger name="com.qccr.cssmanager.web.aop">
<level value="INFO"/>
<appender-ref ref="cssmanager-aop" />
</logger>
<logger name="com.qccr.cssmanager.integration">
<level value="INFO"/>
<appender-ref ref="cssmanager-integ" />
</logger>
<!-- sql -->
<logger name="dao">
<level value="DEBUG"/>
<appender-ref ref="sql" />
</logger>
<root>
<level value="INFO" />
<appender-ref ref="all" />
<appender-ref ref="cssmanager-error" />
</root>
</configuration>
这样我们就可以在日志中打印出用户的信息,
另外,我们还可以加入traceId来进行分布式链路的追踪等。我们可以使用copyOnInheritThreadLocal方法进行获取父线程存入的值,然后在获取子线程的信息。