0

[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

⭐ 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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí