Dans ce didacticiel, nous examinerons la connexion et la configuration d'un système de journalisation dans un projet Spring Boot et l'envoi de journaux à ELK à l' aide de Filebeat . Ce guide est destiné aux développeurs débutants.
Journalisation et pourquoi est-ce nécessaire
Quand j'ai commencé à travailler en tant que programmeur, un de mes collègues seniors aimait répéter: "Si vous n'avez pas de journaux, alors vous n'avez rien . " En effet, face au tout premier bug sur les bancs de test ou pire dans un environnement industriel, la première chose dont nous avons besoin, ce sont les logs applicatifs et un accès facile à ceux-ci. Les développeurs de l'application sont responsables des journaux eux-mêmes, qui doivent veiller à ce que le comportement du système soit enregistré de manière à ce qu'à tout moment, il soit possible de comprendre ce qui se passe avec le système et, surtout, ce qui ne va pas.
La question suivante est la commodité de l'accès aux journaux. Habituellement, lors des tests locaux, nous voyons le journal dans la console d'application et sur le banc de test - dans des fichiers journaux spéciaux sur le serveur. Est-il pratique et sûr de se connecter à chaque fois au stand, de rechercher le répertoire requis et de lire les fichiers journaux à partir de là? La pratique montre que non, et c'est le deuxième problème qu'un certain nombre de produits sont conçus pour résoudre qui fournissent un accès pratique aux journaux et y recherchent des informations importantes. Aujourd'hui, nous parlerons très brièvement de l'un des groupes de ces produits, la soi-disant pile ELK (Elasticsearch - Logstash - Kibana ) et plus en détail de Filebeat - un produit Open source qui fournit un mécanisme pratique pour fournir des journaux à ELK .
Trois lignes sur ELK
- Logstash — ,
- Elasticsearch —
- Kibana —
Filebeat?
Filebeat ELK , Logstash .
ELK , Filebeat ( ), ELK.
.
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 :
Désormais, dans l'onglet Découvrir de notre index, vous pouvez configurer l'affichage des champs et voir que tous les journaux d'une même requête sont combinés par le même requestId . Vous pouvez développer le champ JSON et voir le texte intégral du message reçu de Filebeat :