Skip to content

Task 2-2: Active Connection Metrics

Phase: 2 Priority: Medium Module: WawaServer, ConnectedClient Depends on: Không có Reference: docs/BountyHunter-ControlServer/details/feature-iot-bridge/SPEC.md

Background

Hiện tại ControlServer không có observability: không biết có bao nhiêu máy đang kết nối, bao nhiêu game đang diễn ra, hay tỷ lệ error là bao nhiêu. Khi có sự cố (ví dụ: đột ngột mất 50 connections), operator không có alert hay dashboard nào để phát hiện. PLAN.md Phase 1 đề cập tích hợp Metrics. Micrometer là thư viện metrics tiêu chuẩn trong Spring ecosystem, tích hợp được với Prometheus, JMX, Datadog, v.v.

Tasks

Note: WawaServer.allMachinepublic static ConcurrentHashMap — Micrometer Gauge cần reference đến object, không phải value, nên phải truyền allMachine map và Map::size như function. Gauge sẽ tự query size() mỗi khi metrics được scraped, không cần update thủ công. Counter phải được increment() tại đúng thời điểm event xảy ra.

  • [ ] Kiểm tra build.gradle (hoặc pom.xml) xem đã có Micrometer chưa. Nếu chưa, thêm:
// build.gradle
implementation 'io.micrometer:micrometer-core:1.12.x'
// Nếu dùng JMX export:
implementation 'io.micrometer:micrometer-registry-jmx:1.12.x'
// Nếu thêm Spring Actuator (optional):
implementation 'org.springframework.boot:spring-boot-starter-actuator'
  • [ ] Expose gauge cho active connections trong WawaServer (sau khi allMachine được khởi tạo):
@Autowired
public WawaServer(MeterRegistry meterRegistry) {
    Gauge.builder("control_server.active_connections", WawaServer.allMachine, Map::size)
         .description("Number of currently connected claw machines")
         .register(meterRegistry);
}
  • [ ] Expose counter cho game started trong ConnectedClient.handleGameStarted():
// Inject MeterRegistry qua constructor:
private final Counter gameStartedCounter;

// Trong handleGameStarted():
gameStartedCounter.increment();
log.info("[{}] Game started — total games: {}", macIp, (long) gameStartedCounter.count());
  • [ ] Expose counter cho errors theo error type trong handleErrorReport():
Metrics.counter("control_server.errors",
    "machine", macIp,
    "type", String.valueOf(errorCode)
).increment();
  • [ ] Expose gauge cho in-progress games (nếu gameIsStarted flag có thể được aggregated):
Gauge.builder("control_server.active_games",
    ConnectedClient.activeGameCount,  // AtomicInteger class-level counter
    AtomicInteger::get)
     .register(meterRegistry);
  • [ ] Nếu Spring Actuator được thêm: verify /actuator/metrics/control_server.active_connections endpoint trả đúng value

Verification / Acceptance Criteria

  • [ ] Metric control_server.active_connections phản ánh đúng WawaServer.allMachine.size() sau mỗi connect/disconnect
  • [ ] control_server.game_started_total counter tăng đúng 1 mỗi khi handleGameStarted() được gọi
  • [ ] control_server.errors_total{type="<code>"} tăng khi handleErrorReport() được gọi với error code tương ứng
  • [ ] Nếu dùng JMX: metrics visible trong JConsole dưới metrics MBean domain
  • [ ] Nếu dùng Actuator: GET /actuator/metrics/control_server.active_connections trả {"name":"...","measurements":[{"statistic":"VALUE","value":N}]}
  • [ ] Không có NullPointerException khi MeterRegistry được inject (Spring context đã configured)

Files to Modify

  • src/main/java/.../WawaServer.java
  • src/main/java/.../ConnectedClient.java
  • src/main/resources/config.properties (thêm actuator/metrics config nếu cần)
  • build.gradle hoặc pom.xml (thêm Micrometer dependency)