(三十八) 跟我學習SpringCloud-Spring Cloud實現Zuul自帶的Debug功能

Zuul 中自帶了一個 DebugFilter,一開始筆者也沒明白這個 DebugFilter 有什麼用,看名稱很容易理解,它是用來調試的,可是你看它的源碼幾乎沒什麼邏輯,就 set 了兩個值而已,代碼如下所示。

@Override
public Object run() {
    RequestContext ctx = RequestContext.getCurrentContext();
    ctx.setDebugRouting(true);
    ctx.setDebugRequest(true);
    return null;
}

要想讓這個過濾器執行就得研究一下它的 shouldFilter() 方法,代碼如下所示。

@Override
public boolean shouldFilter() {
    HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
    if ("true".equals(request.getParameter(DEBUG_PARAMETER.get()))) {
        return true;
    }
    return ROUTING_DEBUG.get();
}

只要滿足兩個條件中的任何一個就可以開啓這個過濾器。

第一個條件是請求參數中帶了“某個參數 =true”就可以開啓,這個參數名是通過下面的代碼獲取的,代碼如下所示。

private static final DynamicStringProperty DEBUG_PARAMETER = DynamicPropertyFactory.getInstance()
            .getStringProperty(ZuulConstants.ZUUL_DEBUG_PARAMETER, "debug");

DynamicStringProperty 是 Netflix 的配置管理框架 Archaius 提供的 API,可以從配置中心獲取配置,由於 Netflix 沒有開源 Archaius 的服務端,所以這邊用的就是默認值 debug,如果大家想動態去獲取這個值的話可以用攜程開源的 Apollo 來對接 Archaius,教程後面會給大家講解。

可以在請求地址後面追加“debug=true”來開啓這個過濾器,參數名稱 debug 也可以在配置文件中進行覆蓋,用 zuul.debug.parameter 指定,否則就是從 Archaius 中獲取,沒有對接 Archaius 那就是默認值 debug。

第二個條件的代碼,具體代碼如下所示。

private static final DynamicBooleanProperty ROUTING_DEBUG = DynamicPropertyFactory
            .getInstance().getBooleanProperty(ZuulConstants.ZUUL_DEBUG_REQUEST, false);

它是通過配置 zuul.debug.request 來決定的,可以在配置文件中配置“zuul.debug.request=true”開啓 DebugFilter 過濾器。

DebugFilter 過濾器開啓後,並沒什麼效果,在 run 方法中只是設置了 DebugRouting 和 DebugRequest 兩個值爲 true,於是繼續看源碼,發現在很多地方都有這樣一段代碼,比如 com.netflix.zuul.FilterProcessor.runFilters(String) 中,代碼如下所示。

if (RequestContext.getCurrentContext().debugRouting()) {
    Debug.addRoutingDebug("Invoking {" + sType + "} type filters");
}

當 debugRouting 爲 true 的時候就會添加一些 Debug 信息到 RequestContext 中。現在明白了 DebugFilter 中爲什麼要設置 DebugRouting 和 DebugRequest 兩個值爲 true。

到了這步後還是有些疑惑,一般我們調試信息的話肯定是用日誌輸出來的,日誌級別就是 Debug,但這個 Debug 信息只是累加起來存儲到 RequestContext 中,沒有對使用者展示。

在 org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter.addResponseHeaders() 這段代碼中我們看到了希望。具體代碼如下所示。

private void addResponseHeaders() {
    RequestContext context = RequestContext.getCurrentContext();
    HttpServletResponse servletResponse = context.getResponse();
    if (this.zuulProperties.isIncludeDebugHeader()) {
        @SuppressWarnings("unchecked")
        List<String> rd = (List<String>) context.get(ROUTING_DEBUG_KEY);
        if (rd != null) {
            StringBuilder debugHeader = new StringBuilder();
            for (String it : rd) {
                debugHeader.append("[[[" + it + "]]]");
            }
            servletResponse.addHeader(X_ZUUL_DEBUG_HEADER, debugHeader.toString());
        }
    }
}

核心代碼在於 this.zuulProperties.isIncludeDebugHeader(),只有滿足這個條件纔會把 RequestContext 中的調試信息作爲響應頭輸出,在配置文件中增加下面的配置即可:

zuul.include-debug-header=true

最後在請求的響應頭中可以看到調試內容,如圖 1 所示。

給大家推薦分佈式架構源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章