Chuyển đến nội dung chính

レッスン 20: アクチュエーター、マイクロメーター、可観測性

Spring Boot Actuator — ヘルスチェック、メトリクス、情報エンドポイント。アプリケーションメトリクス用のマイクロメーター。構造化されたロギング。トレース、メトリクス、ログによる可観測性。

💻 プログラミング — レッスン 19 レッスン 20: アクチュエーター、マイクロメーター、 可観測性

Spring Boot 4: 基本から上級まで

パート 5: テストとコードの品質

xdev.asia

はじめに

可観測性には、ログ、メトリクス、トレースの 3 つの柱があります。 Spring Boot 4 には、ヘルスチェック用の Actuator、メトリクス用の Micrometer、分散トレーシング用の Micrometer Tracing が組み込まれており、運用環境でのアプリケーションの監視とデバッグに役立ちます。


1. スプリングブーツアクチュエーター

1.1 セットアップ

// build.gradle.kts
implementation("org.springframework.boot:spring-boot-starter-actuator")

1.2 エンドポイントの構成

# application.yml
management:
  endpoints:
    web:
      exposure:
        include: health, info, metrics, prometheus, env, loggers
      base-path: /actuator
  endpoint:
    health:
      show-details: when_authorized
      show-components: always
  info:
    env:
      enabled: true

1.3 重要なエンドポイント

エンドポイント説明
/アクチュエーター/健康ヘルスチェック — 上/下
/アクチュエーター/情報アプリケーション情報
/アクチュエーター/メトリクスメトリクスのリスト
/actuator/metrics/{名前}特定のメトリクスの詳細
/アクチュエーター/プロメテウスメトリクス Prometheus 形式
/アクチュエーター/ロガーログ レベル ランタイムの表示と変更

1.4 カスタムヘルスインジケーター

@Component
public class DatabaseHealthIndicator implements HealthIndicator {

    private final DataSource dataSource;

    public DatabaseHealthIndicator(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public Health health() {
        try (Connection conn = dataSource.getConnection()) {
            if (conn.isValid(2)) {
                return Health.up()
                    .withDetail("database", "PostgreSQL")
                    .withDetail("connection", "valid")
                    .build();
            }
        } catch (SQLException e) {
            return Health.down()
                .withDetail("error", e.getMessage())
                .build();
        }
        return Health.down().build();
    }
}

1.5 ログレベルのランタイムの変更

# Xem log level hiện tại
curl http://localhost:8080/actuator/loggers/com.example.myapp

# Thay đổi log level (không cần restart)
curl -X POST http://localhost:8080/actuator/loggers/com.example.myapp \
  -H "Content-Type: application/json" \
  -d '{"configuredLevel": "DEBUG"}'

2. マイクロメーターの測定基準

2.1 カスタムメトリクス

@Service
public class OrderService {

    private final Counter orderCounter;
    private final Timer orderProcessingTimer;
    private final AtomicInteger activeOrders;

    public OrderService(MeterRegistry registry) {
        this.orderCounter = Counter.builder("orders.created")
            .description("Total orders created")
            .tag("type", "web")
            .register(registry);

        this.orderProcessingTimer = Timer.builder("orders.processing.time")
            .description("Order processing duration")
            .register(registry);

        this.activeOrders = registry.gauge("orders.active",
            new AtomicInteger(0));
    }

    public OrderResponse createOrder(CreateOrderRequest request) {
        return orderProcessingTimer.record(() -> {
            activeOrders.incrementAndGet();
            try {
                OrderResponse result = processOrder(request);
                orderCounter.increment();
                return result;
            } finally {
                activeOrders.decrementAndGet();
            }
        });
    }
}

2.2 @Timed アノテーション

@RestController
@RequestMapping("/api/v1/products")
public class ProductController {

    @Timed(value = "api.products.get",
           description = "Time to get product",
           percentiles = {0.5, 0.95, 0.99})
    @GetMapping("/{id}")
    public ResponseEntity<ProductResponse> getProduct(@PathVariable Long id) {
        return ResponseEntity.ok(productService.getProduct(id));
    }
}

2.3 プロメテウスの統合

// build.gradle.kts
implementation("io.micrometer:micrometer-registry-prometheus")
# application.yml
management:
  prometheus:
    metrics:
      export:
        enabled: true

アクセス http://localhost:8080/actuator/prometheus → プロメテウスのメトリクス:

# HELP orders_created_total Total orders created
# TYPE orders_created_total counter
orders_created_total{type="web"} 142.0

# HELP orders_processing_time_seconds Order processing duration
orders_processing_time_seconds_count 142
orders_processing_time_seconds_sum 28.456

3. 構造化されたロギング

3.1 JSON ログの構成

# application.yml
logging:
  structured:
    format:
      console: ecs  # Elastic Common Schema
  level:
    com.example: DEBUG
    org.springframework.web: INFO

3.2 コンテキストログ

@Service
public class OrderService {

    private static final Logger log = LoggerFactory.getLogger(OrderService.class);

    public OrderResponse createOrder(CreateOrderRequest request) {
        log.info("Creating order for user: {}, items: {}",
            request.userId(), request.items().size());

        try {
            Order order = processOrder(request);
            log.info("Order created successfully: orderId={}, total={}",
                order.getId(), order.getTotalAmount());
            return OrderResponse.from(order);
        } catch (Exception e) {
            log.error("Failed to create order for user: {}",
                request.userId(), e);
            throw e;
        }
    }
}

4. 分散トレーシング

4.1 マイクロメータートレースのセットアップ

// build.gradle.kts
implementation("io.micrometer:micrometer-tracing-bridge-otel")
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
# application.yml
management:
  tracing:
    sampling:
      probability: 1.0  # 100% sampling (dev), production: 0.1
  otlp:
    tracing:
      endpoint: http://localhost:4318/v1/traces

4.2 カスタムスパン

@Service
public class PaymentService {

    private final ObservationRegistry observationRegistry;

    public PaymentService(ObservationRegistry observationRegistry) {
        this.observationRegistry = observationRegistry;
    }

    public PaymentResult processPayment(PaymentRequest request) {
        return Observation.createNotStarted("payment.process", observationRegistry)
            .lowCardinalityKeyValue("payment.method", request.method())
            .observe(() -> {
                // Logic xử lý payment
                return doProcessPayment(request);
            });
    }
}

4.3 可観測性アーキテクチャ

┌─────────────────────────────────────────────┐
│           Spring Boot Application            │
│  ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│  │  Logs    │ │ Metrics  │ │   Traces     │ │
│  │ Logback  │ │Micrometer│ │  OTel/Brave  │ │
│  └────┬─────┘ └────┬─────┘ └──────┬───────┘ │
└───────┼────────────┼───────────────┼─────────┘
        │            │               │
        ▼            ▼               ▼
   ┌────────┐  ┌──────────┐  ┌───────────┐
   │  Loki  │  │Prometheus│  │   Tempo   │
   └───┬────┘  └────┬─────┘  └─────┬─────┘
       │            │               │
       └────────────┼───────────────┘
                    ▼
              ┌──────────┐
              │ Grafana  │  ← Dashboard tổng hợp
              └──────────┘

5. 実稼働環境におけるアクチュエータのセキュリティ

@Bean
public SecurityFilterChain actuatorSecurity(HttpSecurity http) throws Exception {
    http
        .securityMatcher("/actuator/**")
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/actuator/health").permitAll()
            .requestMatchers("/actuator/info").permitAll()
            .requestMatchers("/actuator/**").hasRole("ADMIN"))
        .httpBasic(Customizer.withDefaults());
    return http.build();
}

概要

  • アクチュエーターはヘルスチェック、メトリクス、ロガーエンドポイントを提供します - 再起動せずにランタイムログレベルを変更できます
  • マイクロメーター: カスタムメトリクスのカウンター、タイマー、ゲージ、Prometheus へのエクスポート
  • 構造化ロギング (JSON/ECS 形式) + 分散トレーシング (OpenTelemetry) により、完全な可観測性スタックが作成されます
  • 本番環境の Secure Actuator エンドポイント: ヘルス/情報のみを公開し、残りは ADMIN ロールを必要とします。

演習

  1. Actuator の構成: ヘルス、メトリクス、Prometheus エンドポイントを公開します。外部 API 依存関係のカスタム状態インジケーターを作成する
  2. カスタムメトリクスの実装: 注文のカウント、タイマーによるリクエストの処理時間の測定、ゲージによるアクティブユーザーの表示
  3. 構造化ログと分散トレースをセットアップします: Prometheus + Grafana に接続します (docker-compose)