Registrando solicitações HTTP com rastreamento HTTP do Spring Boot Actuator
1. Introdução
Quando trabalhamos com microsserviços ou serviços da web em geral, é muito útil saber como nossos usuários interagem com nossos serviços. Isso pode ser conseguido rastreando todas as solicitações que atingem nossos serviços e coletando essas informações para analisá-las posteriormente.
Existem alguns sistemas disponíveis que podem nos ajudar com isso e podem ser facilmente integrados ao Spring, comoZipkin. No entanto,Spring Boot Actuator has this functionality built-ine pode ser usado por meio de seu endpointhttpTrace, que rastreia todas as solicitações HTTP. Neste tutorial, mostraremos como usá-lo e personalizá-lo para se ajustar melhor aos nossos requisitos.
2. HttpTrace Configuração do endpoint
Para fins deste tutorial, usaremosa Maven Spring Boot project.
A primeira coisa que precisamos fazer é adicionarthe Spring Boot Actuator dependency ao nosso projeto:
org.springframework.boot
spring-boot-starter-actuator
Depois disso, teremos que habilitar o endpointhttpTrace em nosso aplicativo.
Para fazer isso, precisamos apenasmodify our application.properties file to include the httpTrace endpoint:
management.endpoints.web.exposure.include=httptrace
No caso de precisarmos de mais endpoints, podemos apenas concatená-los separados por vírgulas ou podemos incluir todos eles usando o curinga*.
Agora, nosso endpointhttpTrace deve aparecer na lista de endpoints do atuador de nosso aplicativo:
{
"_links": {
"self": {
"href": "http://localhost:8080/actuator",
"templated": false
},
"httptrace": {
"href": "http://localhost:8080/actuator/httptrace",
"templated": false
}
}
}
Observe que podemos listar todos os endpoints do atuador habilitados indo para o endpoint/actuator do nosso serviço web.
3. Analisando os traços
Vamos analisar agora os traços que o ponto final do atuadorhttpTrace retorna.
Vamos fazer algumas solicitações ao nosso serviço, chamar o endpoint/actuator/httptrace e obter um dos rastreamentos retornados:
{
"traces": [
{
"timestamp": "2019-08-05T19:28:36.353Z",
"principal": null,
"session": null,
"request": {
"method": "GET",
"uri": "http://localhost:8080/echo?msg=test",
"headers": {
"accept-language": [
"en-GB,en-US;q=0.9,en;q=0.8"
],
"upgrade-insecure-requests": [
"1"
],
"host": [
"localhost:8080"
],
"connection": [
"keep-alive"
],
"accept-encoding": [
"gzip, deflate, br"
],
"accept": [
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
],
"user-agent": [
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 OPR/62.0.3331.66"
]
},
"remoteAddress": null
},
"response": {
"status": 200,
"headers": {
"Content-Length": [
"12"
],
"Date": [
"Mon, 05 Aug 2019 19:28:36 GMT"
],
"Content-Type": [
"text/html;charset=UTF-8"
]
}
},
"timeTaken": 82
}
]
}
Como podemos ver, a resposta é dividida em vários nós:
-
timestamp: a hora em que a solicitação foi recebida
-
principal: o usuário autenticado que fez a solicitação, se aplicável
-
session: qualquer sessão associada ao pedido
-
request: informações sobre a solicitação, como o método, URI completo ou cabeçalhos
-
response: informações sobre a resposta, como o status ou os cabeçalhos
-
timeTaken: o tempo gasto para lidar com a solicitação
Podemos adaptar essa resposta às nossas necessidades se acharmos que é muito prolixo. Podemos dizer ao Spring quais campos queremos que sejam retornados porspecifying them in the management.trace.http.include property de nossoapplication.properties:
management.trace.http.include=RESPONSE_HEADERS
Nesse caso, especificamos que queremos apenas os cabeçalhos de resposta. Portanto, podemos ver que os campos que foram incluídos anteriormente, como os cabeçalhos da solicitação ou o tempo gasto, não estão presentes na resposta agora:
{
"traces": [
{
"timestamp": "2019-08-05T20:23:01.397Z",
"principal": null,
"session": null,
"request": {
"method": "GET",
"uri": "http://localhost:8080/echo?msg=test",
"headers": {},
"remoteAddress": null
},
"response": {
"status": 200,
"headers": {
"Content-Length": [
"12"
],
"Date": [
"Mon, 05 Aug 2019 20:23:01 GMT"
],
"Content-Type": [
"text/html;charset=UTF-8"
]
}
},
"timeTaken": null
}
]
}
Todos os valores possíveis que podem ser incluídos podem ser encontrados emsource code, bem como os valores padrão.
4. Personalizando oHttpTraceRepository
By default, the httpTrace endpoint only returns the last 100 requests and it stores them in memory. A boa notícia é que também podemos personalizar isso criando nosso próprioHttpTraceRepository.
Vamos agora criar nosso repositório. A interfaceHttpTraceRepository é muito simples e só precisamos implementar dois métodos:findAll() to recupera todos os traços; eadd() para adicionar um rastreamento ao repositório.
Para simplificar, nosso repositório também armazenará os rastros na memória e armazenaremos apenas a última solicitação GET que atingir nosso serviço:
@Repository
public class CustomTraceRepository implements HttpTraceRepository {
AtomicReference lastTrace = new AtomicReference<>();
@Override
public List findAll() {
return Collections.singletonList(lastTrace.get());
}
@Override
public void add(HttpTrace trace) {
if ("GET".equals(trace.getRequest().getMethod())) {
lastTrace.set(trace);
}
}
}
Embora esse exemplo simples possa não parecer muito útil, podemos ver o quão poderoso isso pode ser e como podemos armazenar nossos logs em qualquer lugar.
5. Filtrando os caminhos a serem rastreados
A última coisa que vamos cobrir é como filtrar os caminhos que queremos rastrear, para que possamos ignorar algumas solicitações nas quais não estamos interessados.
Se brincarmos com o endpointhttpTrace um pouco depois de fazer algumas solicitações ao nosso serviço, podemos ver que também obtemos rastros para as solicitações do atuador:
{
"traces": [
{
"timestamp": "2019-07-28T13:56:36.998Z",
"principal": null,
"session": null,
"request": {
"method": "GET",
"uri": "http://localhost:8080/actuator/",
// ...
}
Podemos não achar esses rastros úteis para nós e preferimos excluí-los. Nesse caso, precisamos apenascreate our own HttpTraceFiltere especificar quais caminhos queremosignore in the shouldNotFilter method:
@Component
public class TraceRequestFilter extends HttpTraceFilter {
public TraceRequestFilter(HttpTraceRepository repository, HttpExchangeTracer tracer) {
super(repository, tracer);
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return request.getServletPath().contains("actuator");
}
}
Observe que oHttpTraceFilter é apenas um filtro regular do Spring, mas com algumas funcionalidades específicas de rastreamento.
6. Conclusão
Neste tutorial, apresentamos o endpointhttpTrace Spring Boot Actuator e mostramos seus principais recursos. Também cavamos um pouco mais fundo e explicamos como alterar alguns comportamentos padrão para atender melhor às nossas necessidades específicas.
Como sempre, o código-fonte completo dos exemplos está disponívelover on GitHub.