Actuator cho bạn nhìn vào bên trong ứng dụng đang chạy. Bài này về những gì nó cho, và những gì không nên cho ai thấy.

Bật

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Mặc định chỉ /actuator/health được mở ra HTTP. Mọi endpoint khác phải khai tường minh:

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,loggers

Mặc định chặt này là đúng, và bài này sẽ cho thấy vì sao.

/health

  {"status":"UP","components":{"diskSpace":{"status":"UP","details":{"total":994662584320,...

Đây là endpoint quan trọng nhất. Kubernetes và load balancer dùng nó để biết pod có sẵn sàng nhận request không.

Spring Boot tự thêm health indicator cho mọi thứ nó phát hiện: đĩa, DataSource, Redis, RabbitMQ. Có một thành phần DOWN là tổng thể DOWN.

Hai endpoint riêng cho Kubernetes:

management:
  endpoint:
    health:
      probes:
        enabled: true

/actuator/health/liveness — ứng dụng còn sống không? DOWN thì Kubernetes khởi động lại pod.

/actuator/health/readiness — sẵn sàng nhận request chưa? DOWN thì nó gỡ khỏi load balancer nhưng không giết.

Phân biệt hai cái này quan trọng: mất kết nối CSDL nên làm readiness DOWN (ngừng nhận request) chứ không nên làm liveness DOWN — khởi động lại không sửa được CSDL, và nó gây vòng lặp restart.

Tự viết indicator:

@Component
class KiemTraCongThanhToan implements HealthIndicator {
    public Health health() {
        return ping() ? Health.up().build()
                      : Health.down().withDetail("ly-do", "không kết nối được").build();
    }
}

Chú ý show-details: always lộ chi tiết nội bộ — chỉ bật khi endpoint đã được bảo vệ.

/metrics

  số metric: 53

Năm mươi ba chỉ số có sẵn cho một ứng dụng tối giản: JVM (heap, GC, luồng, nạp lớp), HTTP (số request, độ trễ theo phân vị), Tomcat, hệ thống.

curl localhost:8080/actuator/metrics/http.server.requests

Trong sản xuất, bạn không gọi endpoint này bằng tay mà xuất sang Prometheus:

<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

rồi mở /actuator/prometheus. Bài 57 sẽ nói kỹ.

/loggers: đổi mức log lúc chạy

Đây là endpoint tôi thấy hữu ích nhất mà ít người dùng.

  GET  /actuator/loggers/vd.demo  -> {"effectiveLevel":"INFO"}

  POST /actuator/loggers/vd.demo  {"configuredLevel":"DEBUG"}

  GET  /actuator/loggers/vd.demo  -> {"configuredLevel":"DEBUG","effectiveLevel":"DEBUG"}

Bật DEBUG cho một package, trên một pod, không khởi động lại. Điều tra xong thì đặt về null để trả về mặc định.

Đây là câu trả lời cho vấn đề "cấu hình đổi lúc chạy" ở bài 7: với đa số thứ thì khởi động lại là đủ, nhưng mức log là ngoại lệ đáng có.

/mappings/beans

  mappings : /don /xin-chao

/mappings liệt kê mọi URL và handler tương ứng — hữu ích khi một endpoint trả 404 mà bạn chắc chắn đã viết nó.

/beans liệt kê 266 bean ở bài 1 kèm phụ thuộc của từng cái.

/conditions là báo cáo auto-configuration ở bài 8, dưới dạng JSON.

Ba endpoint này rất hữu ích lúc phát triển và không nên mở trong sản xuất.

/env lộ nhiều hơn bạn nghĩ

  curl /actuator/env/java.class.path
  {"property":{"source":"systemProperties","value":"******"},...

Spring Boot có che giá trị — dấu ****** ở trên. Nhưng cơ chế che dựa vào tên thuộc tính chứa password, secret, key, token, credentials.

Nghĩa là app.mat-khau hay cty.api-token-v2 viết bằng tiếng Việt hoặc tên lạ sẽ không được che.

Đừng mở /env, /configprops, /beans, /heapdump, /threaddump ra ngoài. /heapdump tải về toàn bộ heap — trong đó có mọi mật khẩu, token và dữ liệu người dùng đang nằm trong bộ nhớ.

Khoá lại cho sản xuất

Ba lớp bảo vệ, nên dùng cả ba:

Chỉ mở endpoint cần thiết:

management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus
  endpoint:
    health:
      show-details: when-authorized

Đổi sang cổng riêng, không mở ra Internet:

management:
  server:
    port: 9090
    address: 127.0.0.1

Cổng 8080 phục vụ người dùng, cổng 9090 chỉ mạng nội bộ truy cập được.

Yêu cầu xác thực cho các endpoint ngoài health:

http.authorizeHttpRequests(a -> a
    .requestMatchers(EndpointRequest.to("health", "info")).permitAll()
    .requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ADMIN"));

EndpointRequest là matcher riêng của Actuator — dùng nó thay vì gõ đường dẫn bằng tay, vì base path có thể đổi.

/info

  info : {}

Rỗng theo mặc định. Điền bằng cấu hình:

info:
  app:
    ten: dịch vụ đơn hàng
management:
  info:
    git:
      enabled: true
    build:
      enabled: true

Với git-commit-id-maven-plugin, endpoint này trả về commit đang chạy — đúng thứ bài 54 sê-ri Go nói là câu hỏi đầu tiên khi có sự cố.

Thử ba mươi giây

curl -s localhost:8080/actuator | grep -oE '"[a-z-]+":\{' | tr -d '"{:'

Liệt kê mọi endpoint đang mở. Nếu bạn thấy env, beans, heapdump hay threaddump trong danh sách của môi trường sản xuất, hãy đóng chúng lại hôm nay.

Ngày mai bắt đầu chặng web: Spring MVC bên trong và đường đi của một request.