Task 2-2: Active Connection Metrics
Phase: 2 Priority: Medium Module:
WawaServer,ConnectedClientDepends 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.allMachinelàpublic static ConcurrentHashMap— MicrometerGaugecần reference đến object, không phải value, nên phải truyềnallMachinemap vàMap::sizenhư function. Gauge sẽ tự querysize()mỗi khi metrics được scraped, không cần update thủ công. Counter phải đượcincrement()tại đúng thời điểm event xảy ra.
- [ ] Kiểm tra
build.gradle(hoặcpom.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 khiallMachineđượ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
gameIsStartedflag 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_connectionsendpoint trả đúng value
Verification / Acceptance Criteria
- [ ] Metric
control_server.active_connectionsphản ánh đúngWawaServer.allMachine.size()sau mỗi connect/disconnect - [ ]
control_server.game_started_totalcounter tăng đúng 1 mỗi khihandleGameStarted()được gọi - [ ]
control_server.errors_total{type="<code>"}tăng khihandleErrorReport()được gọi với error code tương ứng - [ ] Nếu dùng JMX: metrics visible trong JConsole dưới
metricsMBean domain - [ ] Nếu dùng Actuator:
GET /actuator/metrics/control_server.active_connectionstrả{"name":"...","measurements":[{"statistic":"VALUE","value":N}]} - [ ] Không có
NullPointerExceptionkhiMeterRegistryđược inject (Spring context đã configured)
Files to Modify
src/main/java/.../WawaServer.javasrc/main/java/.../ConnectedClient.javasrc/main/resources/config.properties(thêm actuator/metrics config nếu cần)build.gradlehoặcpom.xml(thêm Micrometer dependency)