1. 程式人生 > >使用MDC進行日誌列印

使用MDC進行日誌列印

在專案中,我們會使用攔截器,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方法進行獲取父執行緒存入的值,然後在獲取子執行緒的資訊。