使用MDC進行日誌列印
阿新 • • 發佈:2018-12-30
在專案中,我們會使用攔截器,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方法進行獲取父執行緒存入的值,然後在獲取子執行緒的資訊。