Configuração de aplicação Spring Boot com Stack ELK para centralização de logs
Abstract
Este tutorial detalha a configuração de uma aplicação Spring Boot para centralizar logs utilizando a stack ELK, composta por Elasticsearch (armazenamento e busca), Logstash (processamento de logs) e Kibana (visualização).
1. Introdução
Note
Recomendo a leitura do texto ”Introdução a stack ELK” antes de seguir com este tutorial.
2. Estrutura do Projeto
Antes de começar, precisamos criar um projeto Spring Boot com as dependências necessárias.
2.1. Criando o Projeto
Use o Spring Initializr (https://start.spring.io/) ou sua IDE para criar um projeto Spring Boot com as seguintes dependências:
- Spring Web: Para criar uma API REST simples.
- Spring Data JPA: Para persistência de dados (usaremos o banco H2 para testes).
- Spring Boot Starter Logging: Inclui o Logback como framework de logging padrão.
- Logstash Logback Encoder: Para formatar logs em JSON e enviá-los ao Logstash.
Note
Qual a diferença entre as implementações Logback e Log4j da interface SLF4J API (Simple Logging Facade for Java)?
Logback é uma implementação nativa da interface SLF4J, enquanto Log4j requer uma camada de adaptação para funcionar com SLF4J e oferece recursos mais avançados de configuração e desempenho. Veja mais em Comparativo entre Logback e Log4j
O arquivo pom.xml
deve incluir:
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- H2 Database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Logstash Logback Encoder -->
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>8.0</version>
</dependency>
</dependencies>
Logback
É o framework de logging padrão do Spring Boot, configurável via XML ou Groovy. Ele suporta appenders (destinos de logs, como console ou arquivos) e encoders (formatadores de logs).
Logstash Logback Encoder
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>8.0</version>
</dependency>
Uma biblioteca que converte logs do Logback em formato JSON estruturado, compatível com o Logstash.
Necessária para garantir que os logs estejam no formato correto para serem processados na stack ELK.
3. Configuração da Aplicação Spring Boot
Nesta etapa, configuramos as propriedades básicas da aplicação no arquivo application.yml
, que define o nome da aplicação, o banco de dados e a porta do servidor.
3.1. Configuração do application.yml
Crie o arquivo src/main/resources/application.yml
com o seguinte conteúdo:
spring:
application:
name: customer-service
datasource:
url: jdbc:h2:mem:testdb
username: sa
password:
driver-class-name: org.h2.Driver
h2:
console:
enabled: true
server:
port: 8081
Note
spring.application.name
Define o nome da aplicação (ex.:
customer-service
) e também o nome do arquivo de log (ex.:customer-service.log
), sendo a forma de identificar a origem dos dados no Kibana.
4. Configuração do Logback
O Logback é configurado para formatar e enviar logs para o Logstash e, opcionalmente, exibi-los no console.
4.1. Configuração do logback-spring.xml
Crie o arquivo src/main/resources/logback-spring.xml
com o seguinte conteúdo:
<configuration>
<!-- Appender para Logstash -->
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>localhost:5044</destination>
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
<!-- Appender para Console -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Configuração do nível de log -->
<root level="INFO">
<appender-ref ref="LOGSTASH" />
<appender-ref ref="CONSOLE" />
</root>
</configuration>
LogstashTcpSocketAppender
- Define um appender que envia logs para o Logstash via TCP.
<destination>localhost:5044</destination>
: Especifica o host e a porta onde o Logstash está escutando. Neste caso,localhost:5044
será configurado no Logstash mais adiante.<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
: Formata os logs em JSON, incluindo metadados como timestamp, nível de log, mensagem e nome da aplicação.
ConsoleAppender
-
Exibe logs no console para depuração local.
-
<pattern>
: Define o formato dos logs no console, incluindo data, nível de log (ex.: INFO, ERROR), nome do logger e mensagem. -
<root level="INFO">
: Configura o nível mínimo de log comoINFO
. Logs de nível inferior (ex.:DEBUG
) não serão processados, a menos que o nível seja alterado. -
<appender-ref>
: Associa os appendersLOGSTASH
eCONSOLE
ao logger raiz, garantindo que todos os logs sejam enviados para ambos os destinos.
4.3. Conceitos Importantes
-
Níveis de Log: O Logback suporta níveis como
TRACE
,DEBUG
,INFO
,WARN
eERROR
. Escolha o nível adequado para evitar sobrecarga no sistema (ex.:DEBUG
gera muitos logs e pode impactar o desempenho). -
Formato JSON: O
LogstashEncoder
estrutura os logs em JSON, incluindo campos como@timestamp
,level
,message
elogger_name
. Isso facilita a indexação no Elasticsearch e a busca no Kibana. -
Appender Assíncrono: Para melhorar a performance, considere configurar o
LogstashTcpSocketAppender
como assíncrono (ex.: usandoAsyncAppender
) em produção, para evitar bloqueios na aplicação.
5. Configuração do Logstash
O Logstash recebe os logs da aplicação, os processa e os envia para o Elasticsearch. Esta etapa configura o pipeline de processamento.
5.1. Configuração do logstash.conf
Crie uma pasta logstash/pipeline
no diretório raiz do projeto e adicione o arquivo logstash.conf
:
input {
tcp {
port => 5044
codec => json
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "logs-%{+YYYY.MM.dd}"
}
}
Pipeline do Logstash: O Logstash processa dados em três estágios: input (coleta), filter (transformação, opcional) e output (envio). Neste tutorial, não usamos filtros, mas eles podem ser adicionados para parsear logs ou enriquecer dados.
Input
tcp { port => 5044, codec => json }
Configura o Logstash para escutar na porta 5044
e interpretar os dados recebidos como JSON. Isso corresponde ao destino configurado no logback-spring.xml
.
Codec JSON
Garante que o Logstash interprete corretamente o formato JSON gerado pelo
LogstashEncoder
.
Filter (opcional)
Adicione filtros para processar logs complexos, como extrair campos específicos ou correlacionar eventos.
Exemplo:
filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:message}" }
}
}
Output
elasticsearch { hosts => ["http://elasticsearch:9200"], index => "logs-%{+YYYY.MM.dd}" }
Envia os logs processados para o Elasticsearch, que está rodando no host elasticsearch
na porta 9200
. O índice logs-%{+YYYY.MM.dd}
cria índices diários (ex.: logs-2025.04.13
), facilitando a gestão de logs ao longo do tempo.
Índices Diários
O padrão
logs-%{+YYYY.MM.dd}
cria um novo índice por dia, o que melhora a performance e facilita a exclusão de logs antigos.
6. Configuração do Docker Compose
O Docker Compose orquestra os serviços ELK (Elasticsearch, Logstash e Kibana) em containers, simplificando a implantação.
6.1. Configuração do docker-compose.yml
Crie o arquivo docker-compose.yml
na raiz do projeto:
services:
elasticsearch:
image: elasticsearch:8.17.3
environment:
- xpack.security.enabled=false
- ES_JAVA_OPTS=-Xmx256m -Xms256m
- discovery.type=single-node
ports:
- '9200:9200'
volumes:
- elastic_data:/usr/share/elasticsearch/data/
logstash:
image: logstash:8.17.3
volumes:
- ./logstash/:/logstash_dir
command: logstash -f /logstash_dir/pipeline/logstash.conf
ports:
- '5044:5044'
environment:
- LS_JAVA_OPTS=-Xmx256m -Xms256m
depends_on:
- elasticsearch
kibana:
image: kibana:8.17.3
ports:
- '5601:5601'
environment:
- ELASTICSEARCH_URL=http://elasticsearch:9200
depends_on:
- elasticsearch
volumes:
elastic_data:
Elasticsearch
elasticsearch:
image: elasticsearch:8.17.3
environment:
- xpack.security.enabled=false
- ES_JAVA_OPTS=-Xmx256m -Xms256m
- discovery.type=single-node
ports:
- '9200:9200'
volumes:
- elastic_data:/usr/share/elasticsearch/data/
-
image: elasticsearch:8.17.3
: Usa a versão 8.17.3 do Elasticsearch. -
environment
:xpack.security.enabled=false
: Desativa a segurança para simplificar o tutorial. Em produção, habilite autenticação e configure credenciais.ES_JAVA_OPTS=-Xmx256m -Xms256m
: Limita a memória do JVM a 256 MB para testes.discovery.type=single-node
: Executa o Elasticsearch como um nó único, adequado para desenvolvimento.
-
ports: ['9200:9200']
: Expõe a porta9200
para comunicação com Logstash e Kibana. -
volumes: elastic_data
: Persiste os dados do Elasticsearch em um volume nomeado.
Logstash
logstash:
image: logstash:8.17.3
volumes:
- ./logstash/:/logstash_dir
command: logstash -f /logstash_dir/pipeline/logstash.conf
ports:
- '5044:5044'
environment:
- LS_JAVA_OPTS=-Xmx256m -Xms256m
depends_on:
- elasticsearch
-
image: logstash:8.17.3
: Usa a mesma versão para compatibilidade. -
volumes: ['./logstash/:/logstash_dir']
: Monta a pasta locallogstash
no container para acessar ologstash.conf
. -
command: logstash -f /logstash_dir/pipeline/logstash.conf
: Executa o Logstash com o arquivo de configuração especificado. -
ports: ['5044:5044']
: Expõe a porta5044
para receber logs da aplicação. -
depends_on: [elasticsearch]
: Garante que o Elasticsearch esteja ativo antes do Logstash.
Kibana
kibana:
image: kibana:8.17.3
ports:
- '5601:5601'
environment:
- ELASTICSEARCH_URL=http://elasticsearch:9200
depends_on:
- elasticsearch
-
image: kibana:8.17.3
: Usa a versão compatível com o Elasticsearch. -
ports: ['5601:5601']
: Expõe a porta5601
para acessar a interface web. -
environment: ELASTICSEARCH_URL
: Configura a conexão com o Elasticsearch. -
depends_on: [elasticsearch]
: Garante que o Elasticsearch esteja ativo.
7. Dockerfile para a Aplicação
Para executar a aplicação Spring Boot em um container, criamos um Dockerfile.
7.1. Configuração do Dockerfile
Crie o arquivo Dockerfile
na raiz do projeto:
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
8. Passos para Execução
Siga estas etapas para executar a aplicação e a stack ELK.
8.1. Compile o Projeto
mvn clean package
- Gera o arquivo JAR em
target/customer-service-0.0.1-SNAPSHOT.jar
.
8.2. Inicie a Stack ELK
docker-compose up -d
- Inicia os containers do Elasticsearch, Logstash e Kibana em segundo plano (
-d
).
8.3. Execute a Aplicação Spring Boot
Se não estiver usando Docker para a aplicação:
java -jar target/customer-service-0.0.1-SNAPSHOT.jar
Se usar o Dockerfile, construa e execute:
docker build -t customer-service .
docker run -d -p 8081:8081 --network=host customer-service
- Nota: O uso de
--network=host
simplifica a comunicação com o Logstash emlocalhost:5044
. Em produção, configure uma rede Docker personalizada.
8.4. Acesse o Kibana
- Abra
http://localhost:5601
no navegador. - Configure um index pattern:
- Vá para Stack Management > Index Patterns.
- Crie um padrão para
logs-*
. - Selecione
@timestamp
como campo de tempo.
- Explore os logs em Discover ou crie visualizações em Dashboards.
Referências
https://youtu.be/AM5r1fXhTJQ?si=JQtt6WBa10NU-w4n
https://github.com/Aprendendo-programacao/spring-elk-docker-setup