[Java Backend Zero to Hello] [Phase 6] BÀI 6.10: LOGGING & MONITORING
📚 Series: Java Backend Zero to Hello 📂 Phân đoạn: Phase 6: REST API & Best Practices 📖 Nội dung: BÀI 6.10: LOGGING & MONITORING 💡 Khóa học lập trình Backend Java & Spring Boot chuẩn doanh nghiệp từ con số 0.
BÀI 6.10: LOGGING & MONITORING
Mục tiêu
- Structured logging
- Tích hợp ELK stack
- Distributed tracing
- APM tools
1. STRUCTURED LOGGING
Log dạng JSON để dễ parse và search.
1.1 Logback JSON Encoder
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.4</version>
</dependency>
1.2 logback.xml
<appender name="JSON" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeMdcKeyName>requestId</includeMdcKeyName>
<includeMdcKeyName>userId</includeMdcKeyName>
<customFields>{"app":"myapp","env":"prod"}</customFields>
</encoder>
</appender>
1.3 Output
{
"@timestamp": "2024-01-15T10:30:00.000Z",
"level": "INFO",
"logger_name": "com.example.UserService",
"message": "User created",
"thread_name": "http-nio-8080-exec-1",
"requestId": "abc-123",
"userId": "user-001",
"app": "myapp",
"env": "prod"
}
2. MDC (MAPPED DIAGNOSTIC CONTEXT)
Thêm context cho log.
2.1 Filter
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class RequestLoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String requestId = req.getHeader("X-Request-Id");
if (requestId == null) {
requestId = UUID.randomUUID().toString();
}
MDC.put("requestId", requestId);
MDC.put("method", req.getMethod());
MDC.put("path", req.getRequestURI());
try {
chain.doFilter(request, response);
} finally {
MDC.clear();
}
}
}
2.2 Sử dụng
log.info("Processing request"); // Tự động có requestId, method, path
3. ELK STACK
3.1 Kiến trúc
App → Logstash → Elasticsearch → Kibana
3.2 Docker Compose
version: '3'
services:
elasticsearch:
image: elasticsearch:8.11.0
environment:
- discovery.type=single-node
ports:
- "9200:9200"
logstash:
image: logstash:8.11.0
volumes:
- ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
ports:
- "5044:5044"
depends_on:
- elasticsearch
kibana:
image: kibana:8.11.0
ports:
- "5601:5601"
depends_on:
- elasticsearch
3.3 logstash.conf
input {
tcp {
port => 5044
codec => json_lines
}
}
filter {
date {
match => [ "@timestamp", "ISO8601" ]
}
}
output {
elasticsearch {
hosts => ["elasticsearch:9200"]
index => "app-logs-%{+YYYY.MM.dd}"
}
}
3.4 Spring Boot
logging:
config: classpath:logback-spring.xml
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>localhost:5044</destination>
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
4. DISTRIBUTED TRACING
4.1 Micrometer Tracing
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
4.2 Cấu hình
management:
tracing:
sampling:
probability: 1.0
zipkin:
tracing:
endpoint: http://localhost:9411/api/v2/spans
4.3 Sử dụng
@Service
@RequiredArgsConstructor
public class OrderService {
private final Tracer tracer;
public Order createOrder(OrderRequest request) {
// Tự động tạo span
log.info("Creating order");
// ...
}
}
5. APM (APPLICATION PERFORMANCE MONITORING)
5.1 Elastic APM
<dependency>
<groupId>co.elastic.apm</groupId>
<artifactId>apm-agent-attach</artifactId>
<version>1.45.0</version>
</dependency>
elastic.apm:
service.name: my-app
server.url: http://localhost:8200
application_packages: com.example
5.2 New Relic
<dependency>
<groupId>com.newrelic.agent.java</groupId>
<artifactId>newrelic-agent</artifactId>
<version>8.0.0</version>
</dependency>
5.3 Datadog
datadog:
apm:
enabled: true
tags:
env: production
6. CUSTOM METRICS
@Service
@RequiredArgsConstructor
public class OrderService {
private final MeterRegistry registry;
private final Counter orderCounter;
private final Timer orderTimer;
public OrderService(MeterRegistry registry) {
this.registry = registry;
this.orderCounter = Counter.builder("orders.created")
.description("Total orders created")
.register(registry);
this.orderTimer = Timer.builder("orders.create.time")
.description("Time to create order")
.register(registry);
}
public Order createOrder(OrderRequest request) {
Timer.Sample sample = Timer.start(registry);
try {
Order order = // ...
orderCounter.increment();
return order;
} finally {
sample.stop(orderTimer);
}
}
}
7. ALERTING
7.1 Với Prometheus AlertManager
groups:
- name: app-alerts
rules:
- alert: HighErrorRate
expr: rate(http_server_requests_seconds_count{status="500"}[5m]) > 0.1
for: 5m
labels:
severity: critical
annotations:
summary: "High error rate detected"
7.2 Với Grafana
- Tạo alert rule
- Gửi notification qua Slack, Email, PagerDuty
8. HEALTH CHECK NÂNG CAO
@Component
public class DatabaseHealthIndicator implements HealthIndicator {
@Autowired
private DataSource dataSource;
@Override
public Health health() {
try (Connection conn = dataSource.getConnection()) {
if (conn.isValid(1)) {
return Health.up()
.withDetail("database", "MySQL")
.withDetail("validationQuery", "SELECT 1")
.build();
}
} catch (SQLException e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
return Health.down().build();
}
}
9. BÀI TẬP THỰC HÀNH
Bài 1: Structured Logging
Cấu hình JSON logging với MDC.
Bài 2: ELK Stack
Setup ELK với Docker và kết nối Spring Boot.
Bài 3: Custom Metrics
Tạo metrics cho business logic.
10. TÓM TẮT
| Khái niệm | Mô tả |
|---|---|
| Structured Logging | Log JSON |
| MDC | Context cho log |
| ELK | Elasticsearch, Logstash, Kibana |
| Distributed Tracing | Theo dõi request xuyên qua service |
| APM | Application Performance Monitoring |
| Metrics | Số liệu ứng dụng |
| Alerting | Cảnh báo khi có vấn đề |
Hoàn thành Phase 6! Tiếp tục với Phase 7: Testing & DevOps
🧭 Điều hướng bài học
- ⬅️ Bài trước: BÀI 6.9: EMAIL & NOTIFICATION
- ➡️ Bài tiếp theo: BÀI 7.1: UNIT TEST VỚI JUNIT 5
- 📑 Toàn bộ lộ trình: Java Backend Zero to Hello
⭐ Hãy bookmark (clip) lại series để tiện theo dõi các bài học tiếp theo nhé!
All rights reserved