跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 如何优雅的在 SpringBoot 中打印 Request&Response 日志
未分類
2020 年 9 月 25 日

如何优雅的在 SpringBoot 中打印 Request&Response 日志

如何优雅的在 SpringBoot 中打印 Request&Response 日志

資深大佬 : springmarker 0

本来想写个 springboot-starter 来做 Request&Response 日志打印的,但是发现逛了一圈谷歌,发现基本都是用拦截器做的。

使用拦截器做本身没什么问题,但是 HttpServletRequest 读取过一次后,body 就不能再读取了,解决办法就是在 Filter 中自己提前包装一个可重复读的 Request,但是觉得这样做有点麻烦而且不那么优雅。

请教一下有什么优雅的办法在 SpringBoot 中打印 Request&Response 日志吗?

大佬有話說 (26)

  • 資深大佬 : MoHen9

    可以用 AOP 打印,参考一下我的实现,https://github.com/benefitj/springboot-doughnut/blob/master/aop/src/main/java/com/benefitj/spring/aop/WebRequestAspect.java

  • 資深大佬 : Kyle18Tang

    https://github.com/zalando/logbook,我们已经用了,可以各种自定义,非常适合。

  • 主 資深大佬 : springmarker

    @MoHen9 #1 AOP 早就试过了,但是 ctrl 层传入传出都是对象,打印日志还得序列化一下,感觉有点浪费

    @Kyle18Tang #2 这个在 stackoverflow 见过,还没试过,想自己写个轻量级的

  • 資深大佬 : frankly123

    /**
    * @author wangyiwen
    * @version 1.0 Created in 2020/7/14 18:36
    * 该注入是为了可以获取到包装过的 httpRequest
    */
    public class WrapperRequestFilter extends AbstractRequestLoggingFilter {

    /**
    * Concrete subclasses should implement this method to write a log message
    * <i>before</i> the request is processed.
    *
    * @param request current HTTP request
    * @param message the message to log
    */
    @Override
    protected void beforeRequest(HttpServletRequest request, String message) {
    //do nothing
    }

    /**
    * Concrete subclasses should implement this method to write a log message
    * <i>after</i> the request is processed.
    *
    * @param request current HTTP request
    * @param message the message to log
    */
    @Override
    protected void afterRequest(HttpServletRequest request, String message) {
    //do nothing
    }
    }
    —————————————————————————————————
    @Bean
    public WrapperRequestFilter wrapperRequestFilter() {
    WrapperRequestFilter wrapperRequestFilter = new WrapperRequestFilter();
    wrapperRequestFilter.setIncludeQueryString(true);
    wrapperRequestFilter.setIncludeClientInfo(true);
    wrapperRequestFilter.setIncludeHeaders(true);
    wrapperRequestFilter.setIncludePayload(true);
    wrapperRequestFilter.setMaxPayloadLength(99999);
    return wrapperRequestFilter;
    }

  • 資深大佬 : frankly123

    @frankly123 然后想在哪里读就在哪里读

  • 主 資深大佬 : springmarker

    @frankly123 #4 request 的 inputstream 只能读取一次

  • 資深大佬 : hugedata

    要么就在每个方法里手动打,要么就过滤器。
    手动打有个好处:提高你的代码量从而提高绩效考核的分数。/doge

  • 資深大佬 : letitbesqzr

    @springmarker #6 使用 org.springframework.web.util.ContentCachingRequestWrapper

  • 主 資深大佬 : springmarker

    @letitbesqzr #8 这个用过,他的 InputStream 也是只能读取一次,应该是 contentBytes 可以读取多次,但是多次读取 contentBytes 的前提又是需要先做读取 InputStream 。

  • 資深大佬 : urzz

    Spring MVC 的话,感觉可以考虑使用 RequestBodyAdvice 和 ResponseBodyAdvice 来实现,之前做参数加解密的时候用过这个。
    打印日志不想序列化可以在 RequestBodyAdvice::beforeBodyRead 中做处理,处理完了之后返回一个新的 inputMessage 出来继续后面的 convert 应该就可以。
    没试过,感觉可以尝试一下。

  • 主 資深大佬 : springmarker

    @urzz #10 这个我也试过,好像不支持 Form 表单 如何优雅的在 SpringBoot 中打印 Request&amp;Response 日志

  • 資深大佬 : frankly123

    @springmarker 看我代码,spring 帮你 wrapper 过了

  • 資深大佬 : CoderGeek

    简洁 抽象类程序入口 befor 打印 request -> 你的各种逻辑 -> after 打印 response 打印 对象都写 toString 少用 json

  • 資深大佬 : xuanbg

    最好是网关上写 Filter 打印,其次是各服务 AOP 打印。可以看: https://github.com/xuanbg/gateway

  • 資深大佬 : changdy

    打印请求日志 可以使用 CommonsRequestLoggingFilter 或者调整 org.apache.coyote.http11.Http11InputBuffer 级别 . 不过最合适的
    打印 Response 我也没找到很好的办法 网上找到一些都是获取的 pojo 类 . 插眼同蹲.
    ps 这种日志是不是在上层记录更合适?

  • 資深大佬 : cs419

    想要对 req 打印日志 打印的信息自然是要包含所有请求数据
    因此需要读取 inputstream
    那问题变成了 inputstream 能重复读取吗
    看下接口设计 默认是不支持 但实现类可以调为支持重复读
    一般 servlet inputstream 不支持重复读 想要支持就需要自己备份

    觉着自己去备份不优雅 无非是觉着亲自给服务添加了个消耗性能的东西是脏活
    最好 tomcat 中有个开关,配置下,就支持重复读了,这心里就好受了
    脏活总得有人干 说白了君子远庖厨 眼不见为净

  • 資深大佬 : tanrenye

    我的经验是用 filter,用 AOP 会有很多特定情境无法进入,日志丢失,例如参数不匹配之类的

  • 主 資深大佬 : springmarker

    @frankly123 #12 这个看了一下还是由抽象类封装为 ContentCachingRequestWrapper 的,这个类读取 InputStream 也是只能读取一次,读取 ContentBytes 有数据的前提也得是先读取 InputStream 。

    @changdy #15 打日志就是为了方便一条龙查看,而且很多服务都是内部服务,没有网关。

    @tanrenye #17 用 filter 的问题就是 Body 只能读取一次

  • 資深大佬 : aguesuka

    不要在 spring 这一层做,要在网关做,今天记 requestBody 明天就想记 url header,后天就想记 tcp packet 。

  • 主 資深大佬 : springmarker

    @aguesuka #19 内部服务之间都是直连的,基本木得 gateway

  • 資深大佬 : tiankongzhe

    哥,springboot 都有这个功能的提供的,只需要配置的开关打开就好了
    spring.http.log-request-details=true

  • 主 資深大佬 : springmarker

    @tiankongzhe #21 这个已经过时了,而且在 2.3.4 上没有生效

  • 資深大佬 : tiankongzhe

    spring boot 2.1
    logging.level.org.springframework.web=DEBUG
    spring.http.log-request-details=true

    spring boot 2.2
    logging.level.org.springframework.web=DEBUG
    spring.mvc.log-request-details=true

    配置上就好了,请求日志就有了

  • 資深大佬 : tiankongzhe

    2.3 的官网找下吧,应该有这个配置的,之前的版本我是在官网 doc 上看到的

  • 主 資深大佬 : springmarker

    @tiankongzhe #23
    这个是没有 Body 的,早就试过了。
    简略写法:logging.level.web=debug

  • 資深大佬 : tiankongzhe

    @springmarker 尝试用 javassist 吧,这到请求的总入口,加入 agent,这样比 filter 和 aop 都要简单,性能也高

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具