Получить трассировку стека Exception с помощью шаблона rest - PullRequest
5 голосов
/ 16 марта 2019

У меня есть 2 услуги - Service 1 и Service 2. Service 1 вызывает некоторые API Service 2 через Spring Rest Template. Некоторое исключение произошло в Service 2. Мне нужна вся трассировка стека в Service 1. Как это получить?

Service 1  ---calls--> Service 2

Трассировка стека даже передается в Service 1 Spring?

Вы можете сказать, что я звоню так:

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();

Ответы [ 5 ]

5 голосов
/ 16 марта 2019

Мне нужна вся трассировка стека в Сервисе 1. Как его получить?

Итак, есть способы получить его, по сути, вы должны реализовать. Вы можете получить соответствующее сообщение об исключении / трассировку в JSON response из Service 2.То есть, когда есть какой-либо exception в Service 2 конце, мы можем настроить ответ для отправки соответствующей информации об исключении.

В этой записи есть 3 ответа объясняющий различные способы достижения, также этот один.Теперь о:

Передается ли трассировка стека даже в службу 1 Spring?

Обычно любые необработанные / во время выполнения exception броски при обработке web-request вызываютсервер возвращает HTTP 500 ответ.

Таким образом, ответ является пружиной, не передает трассировку стека в 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";
}

Знакомый ответ HTTP 404 будет возвращен, если URL-адрес, обрабатываемый этим методом, содержит неизвестную учетную записьid.

Надеюсь, это поможет.

3 голосов
/ 16 марта 2019

К Подводя итог , простой подход - это не намного больше, чем добавление Zipkin и Sleuth запуска Spring Boot в ваши pom.xml s, чтобы включить трассировку журнала в обоих направлениях между несколькими приложениями…

<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, чтобы отразить SpanId s и TraceId s, которые Сутут ввел в ваших запросах…

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

Вы можететакже сравните свой собственный прогресс с работающим примером на учетной записи Openzipkin's Github .

Может быть, вы могли бы попробовать и показать нам свой опыт и прогресс с ним!

1 голос
/ 25 марта 2019

когда служба 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


       }
1 голос
/ 21 марта 2019

Попробуйте преобразовать это исключение в 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 блоке сервиса1

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

или

return new ResponseEntity<>(
      exceptionString, 
      HttpStatus.BAD_REQUEST);
1 голос
/ 20 марта 2019

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) Имейте Exception mapper как ниже для вашей системы и бизнес-исключений где все сообщения об ошибках могут быть перехвачены и зарегистрированы.

   public class SystemException extends Throwable implements
        ExceptionMapper<Throwable> {

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