簡體   English   中英

通過spring rest模板獲取Exception的堆棧跟蹤

[英]Get stack trace of Exception through spring rest template

我有2項服務 - Service 1Service 2 Service 1通過Spring Rest Template調用一些Service 2 API。 現在Service 2發生了一些異常。 我需要Service 1的整個堆棧跟蹤。 怎么弄?

Service 1  ---calls--> Service 2

堆棧跟蹤是否會被Spring傳遞給Service 1

你可以說我這樣打電話:

HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
return restTemplate.exchange("http://localhost:8080/products", HttpMethod.GET, entity, String.class).getBody();

我需要服務1中的整個堆棧跟蹤。如何獲取它?

所以有辦法實現它, 實質上你必須實現。 您可以從Service 2獲取JSON response相關異常消息/跟蹤。 也就是說,當Service 2結束時出現任何exception時,我們可以配置響應以發送相關的異常信息。

這篇文章中,有3個答案解釋了不同的實現方法,也就是這個 從今起 :

堆棧跟蹤是否會被Spring傳遞給Service 1?

通常,處理web-request時拋出的任何未處理/運行時exception都會導致服務器返回HTTP 500響應。

所以答案是spring不會將堆棧跟蹤轉移到Service 1而是使用錯誤HTTP 500和最可能的exception消息進行響應。

但是,你自己寫的任何異常可以在與被注釋@ResponseStatus注釋(支持由定義的所有HTTP狀態代碼HTTP規范)。

當從控制器方法拋出帶annotated exception而不在其他地方處理時,它將自動使用指定的狀態代碼和寫入的消息/跟蹤返回相應的HTTP response 例如,

@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="No such Account")  // 404
public class AddressNotFoundException extends RuntimeException {
    // ...
}

這是一個使用它的控制器方法:

@RequestMapping(value="/account/{id}", method=GET)
public String showOrder(@PathVariable("id") long id, Model model) {
    Account account = accountServices.findAccountById(id);

    if (account == null) throw new AddressNotFoundException(id);
    model.addAttribute(account);
    return "accountDetail";
}

如果此方法處理的URL包含未知帳戶ID,則將返回熟悉的HTTP 404響應。

希望這可以幫助。

總結一個簡單的方法,它只不過是將Spring Boot的ZipkinSleuth啟動器添加到你的pom.xml ,以便在多個應用程序之間的兩個方向上啟用日志跟蹤......

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-sleuth</artifactId>
            <version>${spring-cloud-sleuth.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-sleuth</artifactId>
    </dependency>
</dependencies>
<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

...並在application.properties配置您的日志模式,以反映Sleuth在您的請求中注入的SpanIdTraceId ...

logging.pattern.level=[%X{X-B3-TraceId}/%X{X-B3-SpanId}] %-5p [%t] %C{2} - %m%n

您還可以將自己的進度與Openzipkin的Github帳戶上的運行示例進行比較

也許你可以嘗試一下,向我們展示你的經歷和進步吧!

1)在異常之前捕獲特定的HttpServerErrorException和HttpClientErrorException,將異常對象一直傳播到服務1或資源。

try {
 //code
} catch (HttpServerErrorException | HttpClientErrorException ex) {
throw new SystemException("Http Exception", ex.getResponseBodyAsString(), 
ex);
} catch (RuntimeException ex) {
throw new SystemException("RuntimeException", ex);
} catch (Exception ex) {
throw new SystemException("default exception block", ex);
}

2)為您的系統和業務異常提供如下的異常映射器,其中可以捕獲並記錄所有錯誤消息。

   public class SystemException extends Throwable implements
        ExceptionMapper<Throwable> {

      @Override
      public Response toResponse(Throwable ex) {
         //code to handle exception
      }

嘗試將Service1中的異常轉換為字符串並將該異常字符串附加到帶有錯誤代碼的響應,嘗試在Service2中捕獲該異常通過使用以下代碼,您可以將異常轉換為字符串

import java.io.StringWriter;
import java.io.PrintWriter;

StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
String exceptionString = stringWriter.toString();
System.out.println(exceptionString); 

在你的Catch block of service1中

return ResponseEntity.badRequest()
            .body(exceptionString);

要么

return new ResponseEntity<>(
      exceptionString, 
      HttpStatus.BAD_REQUEST);

當服務2獲得異常時它將返回http 500,因此您無法看到服務1上的任何細節,因此您必須攔截@controlleradvice上的異常,創建控制器建議並設置運行時或任何具有特定http狀態和堆棧跟蹤的異常作為錯誤詳細信息把它返還 。

@ControllerAdvice
    public class RestResponseEntityExceptionHandler 
      extends ResponseEntityExceptionHandler {

        @ExceptionHandler(value 
          = { Service2Exception.class})
        protected ResponseEntity<Service2Error> handleService2Exception(
          RuntimeException ex, WebRequest request) {
            String bodyOfResponse = "This should be application specific";
             Service2Error error = new Service2Error();
              error.setStack(toStack(ex));
            return new ResponseEntity<Server2Error>(error,HttpStatus.NOT_FOUND);// what you want
        }
    }
        public static String toStack(Exception e) {
             StringWriter stringWriter = new StringWriter();
             PrintWriter printWriter = new PrintWriter(stringWriter);
             e.printStackTrace(printWriter);
             String exceptionString = stringWriter.toString();
             return exceptionString;
       }
}


      public class Service2Error {
                private String errorStack;
                private int errorCode;
                         // getter settter


       }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM