SpringWebflux中WebClient怎么打印日志

一静尼、背景

去年高峰壓測的時候捉貌,有個服務是專門調(diào)用其它系統(tǒng)的霹菊,在測試接口http請求的時候镰官,那TPS唰唰的往下掉提前,還專門用Arthas看了一下方法執(zhí)行時間,那家伙泳唠,我sleep 2s狈网,看時間都3-4s了,所以就想著后面優(yōu)化一下笨腥。

所以拓哺,這不就到我們的主角SpringWebflux了,就想著用服務用Webflux脖母,Http請求直接用WebClient了士鸥。但是有一個問題就不得不思考了,怎么記錄請求的日志呢谆级?這個日志很重要烤礁,必須的記錄的清楚,不然不用系統(tǒng)間溝通(扯皮背鍋)著實難搞肥照。

二脚仔、怎么記錄日志?

2.1 思考記錄

打印日志舆绎,那第一步得去看看官網(wǎng)咯鲤脏?看看官網(wǎng)提供了什么解決方案

2.1.1 官網(wǎng)尋答案

打開官網(wǎng),翻到Filter這一頁,發(fā)現(xiàn)著實有可以記錄日志的猎醇,我把官網(wǎng)代碼粘貼在下圖窥突。

WebClient client = WebClient.builder()
        .filter((request, next) -> {
            ClientRequest filtered = ClientRequest.from(request)
                    .header("foo", "bar")
                    .build();

            return next.exchange(filtered);
        })
        .build();

可以看到,我們是可以拿到Request的硫嘶,這讓我一頓高興波岛,那這操作起來不簡單? 但是呢音半,凡事不能高興太早则拷。

拿到這ClientRequest去代碼一頓敲(clientRequest.xx),這個點都被我按爛了曹鸠,發(fā)現(xiàn)并沒有可以獲取RequestBody的方法煌茬,只有Headers,URI... 可惜這都不是我要的啊彻桃。沒辦法坛善,那就只有換別的方法了。

順便點了一下filter的ExchangeFilterFunction邻眷,發(fā)現(xiàn)里面有方法還能拿到Rresponse眠屎。代碼如下:

static ExchangeFilterFunction ofResponseProcessor(Function<ClientResponse, Mono<ClientResponse>> processor) {
  Assert.notNull(processor, "ClientResponse Function must not be null");
  return (request, next) -> next.exchange(request).flatMap(processor);
}

然后拿著Response又來一頓操作,可以拿到Response Body等肆饶,但是...但是...如果我們在Response里面把Response Body 使用掉改衩,就會報錯:nested exception is java.lang.IllegalStateException: The client response body can only be consumed once。如圖所示驯镊。

提前使用ResponseBody

沒有辦法葫督,查看了ClientResponse實現(xiàn)類org.springframework.web.reactive.function.client.DefaultClientResponse,這個是個包權(quán)限的類板惑,雖然很想直接用橄镜,比如:requestDescription(URL路徑),getBody, 但是是在拿不到啊~~難受

既然如此冯乘,那就只有從別的地方尋找洽胶。

2.1.2 其它方案

在官網(wǎng)上WebFlux有三種方案,分別是集成Jetty, Netty, HttpComponent5裆馒。由于我使用的是HttpComponent5姊氓,所以就直接從http這個尋找方案了。

尋尋覓覓领追,找到了了相似的方案他膳,也可以添加Interceptor。我就直接貼出代碼绒窑,如下圖棕孙。

Http添加攔截器

但是在實現(xiàn)時,發(fā)現(xiàn)了有兩個問題。

問題一

打印Request日志的時候會出現(xiàn)兩次蟀俊。

問題二

打印Response的時候也會出現(xiàn)nested exception is java.lang.IllegalStateException: The client response body can only be consumed once這個異常钦铺。

出現(xiàn)這個問題,沒有發(fā)現(xiàn)啥好用的解決方案肢预。

2.1.3 Google

后來就想著想換成Jetty和Netty矛洞,就google了一波,我直接把連接貼出來烫映,就不過多描述了沼本。 連接如下:

Logging Spring WebClient Calls | Baeldung 這個方案也嘗試了一波,但是效果如上锭沟。會出現(xiàn)問題一抽兆,或者在獲取Body的時候出現(xiàn)問題。

2.2 解決方案

在經(jīng)歷了好幾天Debug和測試后族淮,就選擇了妥協(xié)方案辫红,直接在webClient請求的時候打印日志。這還算是一個完美的解決方案祝辣。

我貼出一部分代碼贴妻,如下。

    /**
     * 打印全流程日志蝙斜,需要外部傳入?yún)?shù)
     */
    public static Function<ClientResponse, Mono<String>> logging(String url, String method, Object reqBody) {
        return (clientResponse -> clientResponse.bodyToMono(String.class).doOnSuccess(body -> {
            if (log.isDebugEnabled()) {
                log.info("\n" +
                                "TraceId      : {}, {}\n" +
                                "URI          : {}, \n" +
                                "Param        : {}, \n" +
                                "RespHeader   : {}, \n" +
                                "RespStatus   : {}, \n" +
                                "Response     : {}", clientResponse.logPrefix(), method, url, JsonUtils.toJson(reqBody),
                        clientResponse.headers().asHttpHeaders(), clientResponse.rawStatusCode(),
                        StringUtils.abbreviate(body, 4000));
            }
        }));
    }

在獲取到Body的時候名惩,直接轉(zhuǎn)化成String.class,如果直接轉(zhuǎn)成ParameterizedTypeReference就會失去部分原請求的數(shù)據(jù)乍炉,這樣在扯皮的時候不好找證據(jù)呀>钇(我們打印清晰的日志是為了更好的查詢問題滤馍,不是扯皮︿( ̄︶ ̄)︿ )

這樣打印出來的日志就是我們想要的了岛琼,舒服啊~ 這樣看起來才舒服。

還寫了一些其它的小工具巢株,獲取連接槐瑞,使用方式如下:

小工具使用方式

三、總結(jié)

以上是探索WebClient的打印日志的方式阁苞,還有不足困檩,歡迎大家討論,提出更好的方式那槽。謝謝悼沿!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市骚灸,隨后出現(xiàn)的幾起案子糟趾,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件义郑,死亡現(xiàn)場離奇詭異蝶柿,居然都是意外死亡,警方通過查閱死者的電腦和手機非驮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門交汤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人劫笙,你說我怎么就攤上這事芙扎。” “怎么了填大?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵纵顾,是天一觀的道長。 經(jīng)常有香客問我栋盹,道長施逾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任例获,我火速辦了婚禮汉额,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘榨汤。我一直安慰自己蠕搜,他們只是感情好,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布收壕。 她就那樣靜靜地躺著妓灌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜜宪。 梳的紋絲不亂的頭發(fā)上虫埂,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音圃验,去河邊找鬼掉伏。 笑死,一個胖子當著我的面吹牛澳窑,可吹牛的內(nèi)容都是我干的斧散。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼摊聋,長吁一口氣:“原來是場噩夢啊……” “哼鸡捐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起麻裁,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤箍镜,失蹤者是張志新(化名)和其女友劉穎瞻鹏,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鹿寨,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡新博,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了脚草。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赫悄。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖馏慨,靈堂內(nèi)的尸體忽然破棺而出埂淮,到底是詐尸還是另有隱情,我是刑警寧澤写隶,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布倔撞,位于F島的核電站,受9級特大地震影響慕趴,放射性物質(zhì)發(fā)生泄漏痪蝇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一冕房、第九天 我趴在偏房一處隱蔽的房頂上張望躏啰。 院中可真熱鬧,春花似錦耙册、人聲如沸给僵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帝际。三九已至,卻和暖如春饶辙,著一層夾襖步出監(jiān)牢的瞬間蹲诀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工畸悬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留侧甫,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓蹋宦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親咒锻。 傳聞我的和親對象是個殘疾皇子冷冗,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容