En este tutorial, veremos cómo conectar y configurar un sistema de registro en un proyecto Spring Boot y enviar registros a ELK usando Filebeat . Esta guía está destinada a desarrolladores de nivel de entrada.
Registro y por qué es necesario
Cuando comencé a trabajar como programador, a uno de mis colegas senior le gustaba repetir: "Si no tienes registros, entonces no tienes nada" . De hecho, ante el primer error en los bancos de pruebas o algo peor en un entorno industrial, lo primero que necesitamos son los registros de aplicaciones y un fácil acceso a ellos. Los desarrolladores de la aplicación son los propios responsables de los registros, quienes deben asegurarse de que el comportamiento del sistema se registre de tal manera que en cualquier momento sea posible comprender qué está sucediendo con el sistema y, lo más importante, qué está mal con él.
La siguiente pregunta es la conveniencia de acceder a los registros. Por lo general, durante las pruebas locales, vemos el registro en la consola de la aplicación y en el banco de pruebas, en archivos de registro especiales en el servidor. ¿Es conveniente y seguro conectarse al soporte cada vez, buscar el directorio requerido y leer los archivos de registro desde allí? La práctica demuestra que no, y este es el segundo problema que están diseñados para resolver una serie de productos que proporcionan un acceso conveniente a los registros y buscan información importante en ellos. Hoy hablaremos muy brevemente sobre uno de los grupos de tales productos, el llamado ELK stack (Elasticsearch - Logstash - Kibana ) y con más detalle sobre Filebeat , un producto de código abierto que proporciona un mecanismo conveniente para entregar registros a ELK .
Tres líneas sobre ELK
- Logstash : recibir, modificar registros
- Elasticsearch : almacenamiento y búsqueda
- Kibana - pantalla
¿Qué tiene que ver Filebeat con eso?
Filebeat proporcionará la entrega de datos a ELK y se implementará junto a nuestra aplicación, a menudo es más conveniente que configurar Logstash para leer datos de archivos de registro u otros canales.
Un buen enfoque sería implementar un ELK común para un grupo de microservicios, y para cada microservicio, implementar su propio Filebeat (especialmente porque no es más fácil en ninguna parte), que leerá los registros del microservicio y lo enviará al ELK común .
Intentaremos implementar esta solución más adelante en el entorno local.
Práctica
Java 8
ApacheMaven3.6
Spring Boot 2.3.4.RELEASE
Docker
Spring Boot App
Spring Boot Spring Initalizr
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>6.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
- spring-boot-starter-web — ..
- logstash-logback-encoder —
- lombok — ,
Spring Boot :
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
:
@Slf4j
@Service
public class LogGenerator {
public void generate(int count) {
log.info("Start generating logs");
LongStream.range(0, count)
.forEach(i -> log.info("Log {}", i));
}
}
0 count
, :
@Slf4j
@RestController
@RequiredArgsConstructor
public class LogController {
private final LogGenerator generator;
@GetMapping("/generate")
public ResponseEntity test(@RequestParam(name = "count", defaultValue = "0") Integer count) {
log.info("Test request received with count: {}", count);
generator.generate(count);
return ResponseEntity.ok("Success!");
}
}
GET :
http://localhost:8080/generate?count=10
. resources logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d [%thread] %-5level %logger{35} - [%mdc] - %msg%n</pattern>
</encoder>
</appender>
<appender name="filebeatAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>./log/application.log</file>
<append>true</append>
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>./log/application.%d.%i.log.gz</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="consoleAppender" />
<appender-ref ref="filebeatAppender" />
</root>
</configuration>
:
- consoleAppender —
- filebeatAppender — , LogstashEncoder logstash-logback-encoder
— JSON , Logstash. Logstash .
, ./log/application.log log . . maxFileSize
Filebeat .
:
@Slf4j
@Component
public class LogFilter extends OncePerRequestFilter {
private static final String REQUEST_ID = "requestId";
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String requestId = request.getHeader(REQUEST_ID);
if (requestId == null) {
requestId = UUID.randomUUID().toString();
}
MDC.put(REQUEST_ID, requestId);
try {
log.info("Started process request with {} : {}", REQUEST_ID, requestId);
filterChain.doFilter(request, response);
} finally {
MDC.clear();
}
}
}
, ( requestId), MDC (Mapped Diagnostic Context)
MDC.put(REQUEST_ID, requestId);
finally MDC
MDC.clear();
, , . Kibana .
, , :
mvn spring-boot:run
, application.log
curl "localhost:8080/generate?count=10"
Success!, application.log :
{
"@timestamp":"2020-10-17T22:39:45.595+03:00",
"@version":"1",
"message":"Writing [\"Success!\"]",
"logger_name":"org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor",
"thread_name":"http-nio-8080-exec-3",
"level":"INFO",
"level_value":10000,
"requestId":"77abe5ac-4458-4dc3-9f4e-a7320979e3ae"
}
Filebeat
Filebeat
7.9.2 macOS
.
Filebeat filebeat.xml
, inputs output:
inputs:
- enabled: true
encoding: utf-8
exclude_files: ['\.gz$']
json:
add_error_key: true
keys_under_root: true
overwrite_keys: true
paths:
- { }/*.log
scan_frequency: 10s
type: log
, Filebeat . :
- keys_under_root — json json, Filebeat Logstash
- overwrite_keys —
- add_error_key — Filebeat error.message error.type: json json .
output:
logstash:
hosts:
- localhost:5044
ssl:
certificate_authorities:
- { }/logstash-beats.crt
, Filebeat . Logstash ( )
ssl.certificate_authorities Logstash ( ), .
Filebeat, , .. ELK .
ELK . , docker ELK sebp/elk logstash-beats.crt. certificate_authorities filebeat.xml
docker-compose :
version: '3.7'
services:
elk:
image: sebp/elk
ports:
- "5601:5601" #kibana
- "9200:9200" #elastic
- "5044:5044" #logstash
ELK Filebeat , macOS :
./filebeat -e run
? , LogstashEncoder JSON application.log, Filebeat , Logstash. Kibana.
Kibana :
http://localhost:5601/
Discover:

:

Kibana index ELK . ! Filebeat , . :
curl "localhost:8080/generate?count=100"
:

:

. requestId MDC :

Ahora, en la pestaña Descubrir de nuestro índice, puede configurar la visualización de campos y ver que todos los registros dentro de una solicitud se combinan con el mismo requestId . Puede expandir el campo JSON y ver el texto completo del mensaje recibido de Filebeat :
