Dalam tutorial ini, kita akan melihat cara menghubungkan dan mengkonfigurasi sistem logging dalam proyek Spring Boot dan mengirim log ke ELK menggunakan Filebeat . Panduan ini ditujukan untuk pengembang tingkat pemula.
Logging dan mengapa itu dibutuhkan
Ketika saya pertama kali mulai bekerja sebagai programmer, salah satu rekan senior saya suka mengulangi: "Jika Anda tidak memiliki log, maka Anda tidak punya apa-apa . " Memang, ketika dihadapkan dengan bug pertama di bangku pengujian atau lebih buruk lagi di lingkungan industri, hal pertama yang kita butuhkan adalah log aplikasi dan akses mudah ke sana. Pengembang aplikasi bertanggung jawab atas log itu sendiri, yang harus memastikan bahwa perilaku sistem dicatat sedemikian rupa sehingga setiap saat dimungkinkan untuk memahami apa yang terjadi dengan sistem dan, yang terpenting, apa yang salah dengannya.
Pertanyaan berikutnya adalah kenyamanan akses ke log. Biasanya, selama pengujian lokal, kami melihat log di konsol aplikasi, dan di bangku pengujian - di file log khusus di server. Apakah nyaman dan aman untuk terhubung ke stand setiap saat, mencari direktori yang diperlukan dan membaca file log dari sana? Praktik menunjukkan bahwa tidak, dan ini adalah masalah kedua yang dirancang untuk diselesaikan oleh sejumlah produk yang menyediakan akses mudah ke log dan mencari informasi penting di dalamnya. Hari ini kita akan berbicara secara singkat tentang salah satu grup produk tersebut, yang disebut tumpukan ELK (Elasticsearch - Logstash - Kibana ) dan lebih detail tentang Filebeat - produk sumber terbuka yang menyediakan mekanisme yang nyaman untuk mengirimkan log ke ELK .
Tiga baris tentang 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 :

Sekarang, di tab Temukan untuk indeks kami, Anda dapat mengonfigurasi tampilan bidang dan melihat bahwa semua log dalam satu permintaan digabungkan dengan requestId yang sama . Anda dapat memperluas bidang JSON dan melihat teks lengkap dari pesan yang diterima dari Filebeat :
