【问题标题】:Get stack trace of Exception through spring rest template通过spring rest模板获取异常的堆栈跟踪
【发布时间】:2019-08-07 12:05:37
【问题描述】:

我有 2 个服务 - Service 1Service 2Service 1 通过 Spring Rest 模板调用一些 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();

【问题讨论】:

标签: java spring spring-boot spring-mvc resttemplate


【解决方案1】:

我需要它在服务 1 中的整个堆栈跟踪。如何获取它?

所以有办法得到它,本质上你必须实施。 您可以从 Service 2 获取您在 JSON response 中的相关异常消息/跟踪。即当Service 2结尾有exception时,我们可以配置响应发送相关异常信息。

this 的帖子中有3 个答案 解释了不同的实现方法,还有this 一个。现在开始:

堆栈跟踪是否会被 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 响应。

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    总结一种直接的方法,它只不过是将 Spring Boot 的 ZipkinSleuth 启动器添加到您的 pom.xmls 中以启用多个应用程序之间的双向日志跟踪…

    <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 在您的请求中注入的 SpanIds 和 TraceIds...

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

    您还可以将自己的进度与Openzipkin's Github account 上的运行示例进行比较。

    也许你可以试一试,向我们展示你的经验和进步!

    【讨论】:

      【解决方案3】:

      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
            }
      

      【讨论】:

        【解决方案4】:

        尝试将 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 服务块中

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

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

        【讨论】:

          【解决方案5】:

          当服务 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
          
          
                 }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2023-03-22
            • 2019-06-30
            • 2011-01-05
            • 2011-06-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多