成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spring Boot 記錄Controller接口請求日志七種方式,第六種性能極高

開發 前端
API接口記錄請求相關日志是確保系統安全性、可維護性以及性能監控的重要措施之一。通過記錄API請求的詳細信息,包括請求時間、來源IP地址、請求方法(GET、POST等)、請求參數、響應狀態碼及響應時間等,開發者能夠有效追蹤錯誤源頭、分析用戶行為模式、優化系統性能,并保障數據安全。

環境:SpringBoot3.2.5

1. 簡介

API接口記錄請求相關日志是確保系統安全性、可維護性以及性能監控的重要措施之一。通過記錄API請求的詳細信息,包括請求時間、來源IP地址、請求方法(GET、POST等)、請求參數、響應狀態碼及響應時間等,開發者能夠有效追蹤錯誤源頭、分析用戶行為模式、優化系統性能,并保障數據安全。

接下來,我將介紹七種API接口請求日志的記錄方式:

圖片圖片

準備接口

@RestController
@RequestMapping("/api")
public class ApiController {


  private final static Logger logger = LoggerFactory.getLogger(ApiController.class) ;
  
  @GetMapping("/query/{category}")
  public ResponseEntity<Object> query(@PathVariable String category, @RequestParam String keyword) {
    logger.info("查詢數據, 分類: {}, 關鍵詞: {}", category, keyword) ;
    return ResponseEntity.ok("success") ;
  }
}

接下來的示例我們都將通過該接口進行測試。

2. 實戰案例

2.1 Filter過濾

通過Filter方式可以攔截并記錄HTTP請求和響應的組件。通過Filter技術,開發人員可以在請求到達目標資源之前或響應返回客戶端之前進行日志記錄,從而實現訪問控制和請求預處理等功能。

如果你考慮使用Filter,那么非常幸運你不需要自己去實現,Spring MVC給我們提供了此功能的實現,如下類圖:

圖片圖片

這里我們可以直接注冊CommonRequestLoggingFilter過濾器。

@Bean
FilterRegistrationBean<Filter> loggingFilter() {
  FilterRegistrationBean<Filter> reg = new FilterRegistrationBean<>() ;
  CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter() ;
  // 是否記錄客戶端信息
  filter.setIncludeClientInfo(true) ;
  // 記錄請求header數據
  filter.setIncludeHeaders(true) ;
  // 記錄請求body內容
  filter.setIncludePayload(true) ;
  // 是否記錄查詢字符串
  filter.setIncludeQueryString(true) ;
  reg.setFilter(filter) ;
  reg.addUrlPatterns("/api/*") ;
  return reg ;
}

這還不夠,還需要配合下面日志級別配置:

logging:
  level:
    '[org.springframework.web.filter]': debug

接下來,訪問/api/query/book?keyword=java接口

圖片圖片

成功記錄了請求的相關數據。

2.2 HandlerInterceptor記錄日志

HandlerInterceptor用于攔截請求處理也是非常的實用。它允許開發者在請求到達控制器之前、之后或發生異常時執行特定邏輯,從而實現對請求處理的全面監控和日志記錄。

定義攔截器

@Component
public class LoggingRequestInterceptor implements HandlerInterceptor {


  private static final Logger logger = LoggerFactory.getLogger(LoggingRequestInterceptor.class);


  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    long startTime = Instant.now().toEpochMilli();
    String time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()) ;
    logger.info("Request URL::" + request.getRequestURL().toString() + ":: StartTime=" + time);
    request.setAttribute("startTime", startTime);
    return true;
  }
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    long startTime = (Long) request.getAttribute("startTime");
    logger.info("Request URL::" + request.getRequestURL().toString() + ":: TimeTaken="
        + (Instant.now().toEpochMilli() - startTime));
  }
}

注冊攔截器

@Component
public class InterceptorConfig implements WebMvcConfigurer {
  
  private final LoggingRequestInterceptor loggingRequestInterceptor ;
  public InterceptorConfig(LoggingRequestInterceptor loggingRequestInterceptor) {
    this.loggingRequestInterceptor = loggingRequestInterceptor;
  }
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(loggingRequestInterceptor).addPathPatterns("/api/**") ;
  }
}

請求API接口

圖片

2.3 使用AOP技術

通過AOP記錄日志是一種強大的技術,它允許開發者在不修改業務邏輯代碼的情況下,將日志記錄等橫切關注點與業務邏輯分離。AOP能夠自動攔截方法調用,并記錄方法執行前后的信息,為系統提供全面的日志支持。

自定義注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Log {


  /**模塊*/
  String module() default "" ;
  /**具體操作說明*/
  String desc() default "" ;
}

定義切面

@Component
@Aspect
public class LogAspect {


  @Pointcut("@annotation(log)")
  private void recordLog(Log log) {}
  
  @Around("recordLog(log)")
  public Object logAround(ProceedingJoinPoint pjp, Log log) throws Throwable {
    String module = log.module();
    String desc = log.desc();
    long uid = System.nanoTime() ;
    String threadName = Thread.currentThread().getName();
    System.err.printf("%s - 【%d】 模塊: %s, 操作: %s, 請求參數: %s%n", threadName, uid, module, desc, Arrays.toString(pjp.getArgs())) ;
    Object ret = pjp.proceed() ;
    System.err.printf("%s - 【%d】 返回值: %s%n", threadName, uid, ret) ;
    return ret ;
  }
}

修改Controller接口

@Log(module = "綜合查詢", desc = "查詢商品信息")
@GetMapping("/query/{category}")
public ResponseEntity<Object> query(@PathVariable String category, @RequestParam String keyword)

請求API接口

圖片圖片

2.4 基于Servlet請求事件機制

默認情況下,當一個請求到達后,Spring MVC底層會發布一個事件ServletRequestHandledEvent,我們只需要監聽該事件也是可以獲取到詳細的請求/響應信息。

自定義事件監聽器

@Component
public class RequestEventListener implements ApplicationListener<ServletRequestHandledEvent> {


  private static final Logger logger = LoggerFactory.getLogger(RequestEventListener.class) ;
  @Override
  public void onApplicationEvent(ServletRequestHandledEvent event) {
    logger.info("請求信息: {}", event) ;
  } 
}

請求API接口

圖片圖片

你可以通過ServletRequestHandledEvent事件對象獲取具體的明細信息

圖片圖片

2.5 使用第三方Logbook組件

Logbook是一個可擴展的Java庫,能夠為不同的客戶端和服務器端技術實現完整的請求和響應日志記錄。它允許開發者記錄應用程序接收或發送的任何HTTP流量。

引入依賴

<dependency>
  <groupId>org.zalando</groupId>
  <artifactId>logbook-spring-boot-starter</artifactId>
  <version>3.10.0</version>
</dependency>

配置文件

logging:
  level:
    '[org.zalando.logbook.Logbook]': TRACE

請求API接口

圖片圖片

2.6 自定義HandlerMethod

如果你僅僅是針對Controller接口進行日志記錄處理,那么強烈推薦此種方式。

2.7 三方API接口調用

通常我們會使用RestTemplate/RestClient進行第三方接口的調用;如果要記錄此種情況的日志信息,那么我們需要自定義ClientHttpRequestInterceptor攔截器。

public class LoggingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {


  private final Logger log = LoggerFactory.getLogger(this.getClass());
  @Override
  public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
      throws IOException {
    logRequest(request, body) ;
    ClientHttpResponse response = execution.execute(request, body);
    logResponse(response);
    return response;
  }
  private void logRequest(HttpRequest request, byte[] body) throws IOException {
    if (log.isDebugEnabled()) {
      log.debug("===========================request begin================================================");
      log.debug("URI         : {}", request.getURI());
      log.debug("Method      : {}", request.getMethod());
      log.debug("Headers     : {}", request.getHeaders());
      log.debug("Request body: {}", new String(body, "UTF-8"));
      log.debug("==========================request end================================================");
    }
  }
  private void logResponse(ClientHttpResponse response) throws IOException {
    if (log.isDebugEnabled()) {
      log.debug("============================response begin==========================================");
      log.debug("Status code  : {}", response.getStatusCode());
      log.debug("Status text  : {}", response.getStatusText());
      log.debug("Headers      : {}", response.getHeaders());
      log.debug("Response body: {}", StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()));
      log.debug("=======================response end=================================================");
    }
  }
}

RestTemplate配置攔截器

@Bean
RestTemplate restTemplate(RestTemplateBuilder builder) {
  RestTemplate restTemplate = builder
    .additionalInterceptors(
      new LoggingClientHttpRequestInterceptor())
  .build() ;
  return restTemplate ;
}

日志打印情況如下:

圖片圖片

如果使用的RestClient,那么可以同一個攔截器,配置如下:

@Bean
RestClient restClient() {
  return RestClient
      .builder()
      .requestInterceptor(
        new LoggingClientHttpRequestInterceptor())
      .build() ;
}
責任編輯:武曉燕 來源: Spring全家桶實戰案例源碼
相關推薦

2024-05-30 08:51:28

Spring數據分布式

2024-08-30 11:11:01

2009-02-11 09:46:00

ASON網絡演進

2024-10-12 08:18:21

Spring接口組件

2017-06-26 10:35:58

前端JavaScript繼承方式

2025-01-21 08:00:00

限流微服務算法

2025-06-17 07:37:53

2025-02-27 00:00:30

SpringJava方式

2018-06-10 16:31:12

2024-01-04 12:48:00

Spring

2017-06-14 16:44:15

JavaScript原型模式對象

2025-01-08 09:35:55

Spring性能監控

2022-03-18 14:33:22

限流算法微服務

2023-03-08 16:54:28

MySQL數據庫

2021-01-08 10:52:22

物聯網萬物互聯IoT,Interne

2022-03-23 12:55:50

農業物聯網

2023-05-10 13:58:13

服務限流系統

2024-12-18 16:19:51

2019-05-16 13:00:18

異步編程JavaScript回調函數

2022-07-01 08:00:44

異步編程FutureTask
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产成人精品一区二区三区网站观看 | 免费看国产精品视频 | 性欧美xxxx| 一区二区三区免费在线观看 | 欧美日韩国产免费 | 成人精品视频在线观看 | 国产中文字幕在线观看 | 不卡一区 | a免费视频| 中文字幕一区二区三区四区五区 | 四虎伊人| 一区二区三区在线看 | 日本在线播放一区二区 | 精品国产精品三级精品av网址 | 亚洲淫视频 | 亚洲欧美成人 | 亚洲 欧美 精品 | 成人福利视频 | 国产激情视频在线免费观看 | 正在播放国产精品 | 日本特黄a级高清免费大片 成年人黄色小视频 | 精品中文在线 | 99精品亚洲国产精品久久不卡 | 国产欧美一区二区三区久久人妖 | 亚洲福利网| 91精品国产综合久久婷婷香蕉 | 91久久精品国产 | 成人精品网 | 精品久久久久久 | 欧美日韩国产精品一区二区 | 一区二区三区四区不卡视频 | 中文字幕在线欧美 | 综合久久综合久久 | a国产一区二区免费入口 | 久草新在线 | 色综合欧美 | 精品色 | 精品毛片在线观看 | 91欧美 | 精品一级毛片 | 欧美中文字幕一区二区三区亚洲 |