top of page

Monitorando um serviço com Jaeger e Open Telemetry

  • Foto do escritor: Eduardo Nepomuceno da Rocha
    Eduardo Nepomuceno da Rocha
  • 11 de abr.
  • 3 min de leitura

Em se tratando de boas práticas de desenvolvimento de software, aquelas referentes à observabilidade são cada vez mais necessárias diante das exigências de sistemas cada vez mais complexos e com maior carga de trabalho.

A arquitetura de microsserviços atualmente é a mais popular e utilizada dentro de projetos de diversas empresas. Uma única função de software pode envolver a comunicação de diversos microsserviços. Por muitas vezes torna-se necessário monitorar a cadeia de eventos nas interações de microsserviços, para que possa ser isolado um problema quando algo fora do normal acontece no sistema. O Jaeger, também chamado de Jaeger Tracing, é capaz de rastrear o caminho de uma solicitação por meio de uma série de interações desses microsserviços.

O Jaeger é capaz de monitorar transações distribuídas, analisando movimentos de dados entre os microsserviços. É uma ótima ferramenta para inspecionar o comportamento para avaliar questões de latência e identificar gargalos. Além disso, pode avaliar a dependência entre serviços e o caminho de uma solicitação. Deixarei um link para compreensão da ferramenta, pois meu objetivo aqui é ensinar como implementar e mostrar seu funcionamento em uma API. No caso, não subi uma arquitetura em microsserviços. Apresentarei a implementação em um monolito, mas obviamente a técnica se aplica a uma arquitetura dividida em muitos serviços. Apresentarei uma implementação para Spring Boot 3. Notei que existe uma carência de exemplos com essa versão do framework. O Java utilizado é 17 e a simulação é de uma aplicação executada em ambiente local, porém subindo o serviço do Jaeger e banco em container docker.


Docker-compose.yml



Arquivo docker-compose.yml
Arquivo docker-compose.yml

Neste arquivo vemos o mapeamento das portas mais essenciais do Jagger, o nome exato da imagem docker, informação sobre comunicação no environment e nome do container. Omiti as informações SQL por não ser o foco deste texto. O próximo passo é ter as dependências corretas no Pom. Aqui destacarei apenas as necessárias para subir essa aplicação com Jaeger, sem dar muita importância a outras focada em banco e migração como Flyway.


	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
			<version>3.4.2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springdoc</groupId>
			<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
			<version>2.1.0</version>
		</dependency>
		<dependency>
			<groupId>io.micrometer</groupId>
			<artifactId>micrometer-tracing-bridge-otel</artifactId>
		</dependency>
		<dependency>
			<groupId>io.opentelemetry</groupId>
			<artifactId>opentelemetry-exporter-otlp</artifactId>
		</dependency>
		<dependency>
			<groupId>io.opentracing.contrib</groupId>
			<artifactId>opentracing-jdbc</artifactId>
			<version>0.2.15</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.22</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
			<version>3.4.2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.flywaydb</groupId>
			<artifactId>flyway-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.flywaydb</groupId>
			<artifactId>flyway-mysql</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.24</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>

Há algumas dependências de bancos para o MySql, Flyway para migração de dados, JPA, Swagger, Lombok e outras práticas comuns de Spring Boot. Focando nas importantes para monitoramento, temos(olhando pelo artifactId): opentracing-jdbc, opentelemetry-exporter-otlp, micrometer-tracing-bridge-otel e também o spring-boot-starter-actuator. O primeiro é referente ao monitoramento inclusive de banco e query, os dois seguintes são necessários para estabelecer a comunicação entre Open Telemetry e Jaeger, enquanto a última já é do próprio Spring, também importante para termos o monitoramento correto. Em seguida, deve ser criado um bean de configuração para comunicação entre o serviço do Jaeger e o Open Telemetry. Veja


import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OtlpConfiguration {
    @Bean
    OtlpHttpSpanExporter otlpHttpSpanExporter(@Value("${tracing.url}") String url){
        return OtlpHttpSpanExporter.builder()
                .setEndpoint(url)
                .build();
    }
}

Veja que é bem simples. Basicamente se configura o Exporter Otlp, passando para ele o endpoint que está no application.properties da aplicação.



server.port = 8099

spring.jpa.database=MYSQL
spring.datasource.driver-class-name=io.opentracing.contrib.jdbc.TracingDriver
spring.datasource.url=jdbc:tracing:mysql://localhost/nome_base_de_dados?useTimezone=true&serverTimezone=America/Sao_Paulo
spring.datasource.username=seu usuario
spring.datasource.password=sua senha
spring.jpa.show-sql=true


########## Configuration Tracing (OpenTelemetry + Jaeger) ############
management.tracing.sampling.probability=1.0

tracing.url=http://localhost:4318/v1/traces

logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]

No caso, optei por subir a aplicação na porta 8099. Considerando que a porta 8080 eventualmente pode estar ocupada, considero uma prática mais segura. Na configuração do banco, dois pontos são importantes: A necessidade de colocar o tracing entre jdbc e seu banco, assim como o driver-class-name do TracingDriver. Na parte referente à configuração de Tracing, o sampling probability define a probabilidade de amostragem dos laços. No caso, o valor 1.0 significa que todas as requisições serão coletadas para rastreamento. O tracing url define o endpoint de exportação de traços no protocolo OTLP/HTTP. O Open Telemetry SDK do Spring Boot 3 usa esse endpoint para enviar os traços coletados. Esse endpoint (4318/v1/traces) é exposto por pelos coletores OTEL e também por algumas versões recentes do Jaeger se configurado como receptor OTLP (o seu jaegertracing/all-in-one precisa ser recente e bem configurado pra isso funcionar). A última linha personaliza o padrão de log da aplicação. inserindo os IDS de trace e span no log, o que facilita a correlação entre os logs e os dados do tracing no Jaeger. Após essas configurações, você pode subir a aplicação e monitorar pelo Jaeger. O Jaeger é acessado por padrão na porta 16686. Teste subir o serviço e enviar requisições pelo Swagger ou Postman para verificar o funcionamento do Jaeger. Veja as imagens a seguir com dados apresentados na interface gráfica exposta na porta 16686, conforme citado anteriormente.



Exemplo de monitoramento de uma requisição http do tipo POST
Exemplo de monitoramento de uma requisição http do tipo POST

Histórico de requisições ao longo do tempo
Histórico de requisições ao longo do tempo


Commentaires


bottom of page