From ddb8e38e08c49577c721fcf054aa175f0d96f0d4 Mon Sep 17 00:00:00 2001 From: Sascha Doemer Date: Wed, 4 Sep 2024 08:45:37 +0200 Subject: [PATCH] Add HeartBeatService and HeartBeatController (#244) --- pom.xml | 16 ++++--- .../fivegla/business/HeartBeatService.java | 41 +++++++++++++++++ .../fivegla/controller/api/BaseMappings.java | 1 + .../global/HeartBeatController.java | 46 +++++++++++++++++++ 4 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 src/main/java/de/app/fivegla/business/HeartBeatService.java create mode 100644 src/main/java/de/app/fivegla/controller/global/HeartBeatController.java diff --git a/pom.xml b/pom.xml index 939fab7..4d3db9b 100644 --- a/pom.xml +++ b/pom.xml @@ -127,12 +127,6 @@ 2.10.1 - - - io.micrometer - micrometer-registry-prometheus - - jakarta.xml.bind @@ -164,6 +158,16 @@ 8.5.10 + + + io.micrometer + micrometer-core + + + io.micrometer + micrometer-registry-prometheus + + diff --git a/src/main/java/de/app/fivegla/business/HeartBeatService.java b/src/main/java/de/app/fivegla/business/HeartBeatService.java new file mode 100644 index 0000000..d042990 --- /dev/null +++ b/src/main/java/de/app/fivegla/business/HeartBeatService.java @@ -0,0 +1,41 @@ +package de.app.fivegla.business; + +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +/** + * The HeartBeatService class provides functionality to register heartbeats. + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class HeartBeatService { + + private final MeterRegistry meterRegistry; + private final ConcurrentHashMap lastHeartbeatTimestamps = new ConcurrentHashMap<>(); + + /** + * Register a heartbeat using Micrometer. + */ + public void registerHeartBeat(String id) { + log.info("Registering heartbeat using Micrometer for sensor id: {}", id); + var counter = meterRegistry.counter("heartbeat", "id", id); + counter.increment(); + + lastHeartbeatTimestamps.computeIfAbsent(id, key -> { + AtomicLong timestamp = new AtomicLong(); + Gauge.builder("heartbeat.lastTimestamp", timestamp, AtomicLong::get) + .description("The timestamp of the last heartbeat for sensor id: " + id) + .tags("sensorId", id) + .register(meterRegistry); + return timestamp; + }).set(System.currentTimeMillis()); + } + +} diff --git a/src/main/java/de/app/fivegla/controller/api/BaseMappings.java b/src/main/java/de/app/fivegla/controller/api/BaseMappings.java index f0bbc87..53fae14 100644 --- a/src/main/java/de/app/fivegla/controller/api/BaseMappings.java +++ b/src/main/java/de/app/fivegla/controller/api/BaseMappings.java @@ -23,6 +23,7 @@ public class BaseMappings { public static final String MAINTENANCE = SECURED_BY_API_KEY + "/maintenance"; public static final String INFO = SECURED_BY_API_KEY + "/info"; public static final String TENANT = SECURED_BY_API_KEY + "/tenant"; + public static final String HEARTBEAT = SECURED_BY_API_KEY + "/heartbeat"; // SECURED_BY_TENANT diff --git a/src/main/java/de/app/fivegla/controller/global/HeartBeatController.java b/src/main/java/de/app/fivegla/controller/global/HeartBeatController.java new file mode 100644 index 0000000..13e2c38 --- /dev/null +++ b/src/main/java/de/app/fivegla/controller/global/HeartBeatController.java @@ -0,0 +1,46 @@ +package de.app.fivegla.controller.global; + +import de.app.fivegla.business.HeartBeatService; +import de.app.fivegla.config.security.marker.ApiKeyApiAccess; +import de.app.fivegla.controller.api.BaseMappings; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * The HeartBeatController class handles heartbeat-related operations. + * It provides a method to register a heartbeat. + *

+ * This controller is mapped to the /heartbeat endpoint. + */ +@Slf4j +@RestController +@RequestMapping(BaseMappings.HEARTBEAT) +@RequiredArgsConstructor +public class HeartBeatController implements ApiKeyApiAccess { + + private final HeartBeatService heartBeatService; + + @Operation( + operationId = "heartbeat", + description = "Heartbeat endpoint.", + tags = BaseMappings.HEARTBEAT + ) + @ApiResponse( + responseCode = "200", + description = "The heartbeat was successful." + ) + @PostMapping("/{id}") + public ResponseEntity heartBeat(@PathVariable @Schema(description = "The ID") String id) { + heartBeatService.registerHeartBeat(id); + return ResponseEntity.ok().build(); + } + +}