Spring Boot y Filebeat localmente sin registro y sms

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 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 — ,


pom.xml



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_rootjson json, Filebeat Logstash
  • overwrite_keys
  • add_error_keyFilebeat 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 :






All Articles