如何在zuul上做日誌處理

gung123發表於2020-02-19

由於zuul作為api閘道器,所有的請求都經過這裡,所以在閘道器上,可以做請求相關的日誌處理。

我的需求是這樣的,需要記錄請求的 url,ip地址,引數,請求發生的時間,整個請求的耗時,請求的響應狀態,

甚至請求響應的結果等。

很顯然,需要實現這樣的一個功能,需要寫一個ZuulFliter,它應該是在請求傳送給客戶端之前做處理,並且在

route過濾器路由之後,在預設的情況下,這個過濾器的order應該為500-1000之間。那麼如何獲取這些我需要的

日誌資訊呢?找RequestContext,在請求的生命週期裡這個物件裡,儲存了整個請求的所有資訊。

瞭解springcloud架構可以加求求:三五三六二四七二五九

現在編碼,在程式碼的註釋中,做了詳細的說明,程式碼如下:

@Component
public class LoggerFilter extends ZuulFilter {
  
    @Override
    public String filterType() {
        return FilterConstants.POST_TYPE;
    }
    @Override
    public int filterOrder() {
        return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1;
    }
    @Override
    public boolean shouldFilter() {
        return true;
    }
    @Override
    public Object run() {
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        String method = request.getMethod();//氫氣的型別,post get ..
        Map<String, String> params = HttpUtils.getParams(request);
        String paramsStr = params.toString();//請求的引數
        long statrtTime = (long) context.get("startTime");//請求的開始時間
        Throwable throwable = context.getThrowable();//請求的異常,如果有的話
        request.getRequestURI();//請求的uri
        HttpUtils.getIpAddress(request);//請求的iP地址
        context.getResponseStatusCode();//請求的狀態
        long duration=System.currentTimeMillis() - statrtTime);//請求耗時
        return null;
    }
}

現在讀者也許有疑問,如何得到的statrtTime,即請求開始的時間,其實這需要另外一個過濾器,在網路請求route之前(大部分耗時都在route這一步),在過濾器中,在RequestContext儲存一個時間即可,另寫一個過濾器,程式碼如下:

@Component
public class AccessFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return "pre";
    }
    @Override
    public int filterOrder() {
        return 0;
    }
    @Override
    public boolean shouldFilter() {
        return true;
    }
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        ctx.set("startTime",System.currentTimeMillis());
       
        return null;
    }
}

可能還有這樣的需求,我需要將響應結果,也要儲存在log中,在之前已經分析了,在route結束後,將從具體服務獲取的

響應流儲存在RequestContext中,在SendResponseFilter過濾器寫入在HttpServletResponse中,最終返回給客戶端。那麼我只需要在SendResponseFilter寫入響應流之前把響應流寫入到 log日誌中即可,那麼會引發另外一個問題,因為響應流寫入到 log後,RequestContext就沒有響應流了,在SendResponseFilter就沒有流輸入到HttpServletResponse中,導致客戶端沒有任何的返回資料,那麼解決的辦法是這樣的:

InputStream inputStream =RequestContext.getCurrentContext().getResponseDataStream();
InputStream newInputStream= copy(inputStream);
transerferTolog(inputStream);
RequestContext.getCurrentContext().setResponseDataStream(newInputStream);

從RequestContext獲取到流之後,首先將流 copy一份,將流轉化下字串,存在日誌中,再set到RequestContext中,
這樣SendResponseFilter就可以將響應返回給客戶端。這樣的做法有點影響效能,如果不是字元流,可能需要做更多的處理工作。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69952307/viewspace-2676257/,如需轉載,請註明出處,否則將追究法律責任。

相關文章