From 097a163cf580257957ab32aeec5d0de87341d91b Mon Sep 17 00:00:00 2001 From: Viktor Lofgren Date: Tue, 4 Jul 2023 18:25:42 +0200 Subject: [PATCH] Getting a skeleton in place for the control service. --- .../control-service/build.gradle | 1 + .../nu/marginalia/control/ControlService.java | 22 +++++++- .../marginalia/control/EventLogService.java | 49 ++++++++++++++++++ .../control/model/EventLogEntry.java | 10 ++++ .../control/model/ServiceHeartbeat.java | 3 ++ .../main/resources/static/control/style.css | 4 ++ .../resources/templates/control/index.hdb | 14 ++++++ .../templates/control/partials/nav.hdb | 7 +++ .../resources/templates/control/services.hdb | 50 +++++++++++++++++++ 9 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 code/services-satellite/control-service/src/main/java/nu/marginalia/control/EventLogService.java create mode 100644 code/services-satellite/control-service/src/main/java/nu/marginalia/control/model/EventLogEntry.java create mode 100644 code/services-satellite/control-service/src/main/resources/static/control/style.css create mode 100644 code/services-satellite/control-service/src/main/resources/templates/control/index.hdb create mode 100644 code/services-satellite/control-service/src/main/resources/templates/control/partials/nav.hdb create mode 100644 code/services-satellite/control-service/src/main/resources/templates/control/services.hdb diff --git a/code/services-satellite/control-service/build.gradle b/code/services-satellite/control-service/build.gradle index 1bb9bfdc..f8ed32e0 100644 --- a/code/services-satellite/control-service/build.gradle +++ b/code/services-satellite/control-service/build.gradle @@ -26,6 +26,7 @@ dependencies { implementation project(':code:common:model') implementation project(':code:common:service') implementation project(':code:common:config') + implementation project(':code:common:renderer') implementation project(':code:common:service-discovery') implementation project(':code:common:service-client') implementation project(':code:api:search-api') diff --git a/code/services-satellite/control-service/src/main/java/nu/marginalia/control/ControlService.java b/code/services-satellite/control-service/src/main/java/nu/marginalia/control/ControlService.java index 952559e0..c8ded478 100644 --- a/code/services-satellite/control-service/src/main/java/nu/marginalia/control/ControlService.java +++ b/code/services-satellite/control-service/src/main/java/nu/marginalia/control/ControlService.java @@ -4,35 +4,53 @@ import com.google.gson.Gson; import com.google.inject.Inject; import nu.marginalia.client.ServiceMonitors; import nu.marginalia.model.gson.GsonFactory; +import nu.marginalia.renderer.MustacheRenderer; +import nu.marginalia.renderer.RendererFactory; import nu.marginalia.service.server.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import spark.Spark; +import java.io.IOException; +import java.util.Map; + public class ControlService extends Service { private final Logger logger = LoggerFactory.getLogger(getClass()); private final Gson gson = GsonFactory.get(); private final ServiceMonitors monitors; + private final MustacheRenderer indexRenderer; + private final MustacheRenderer> servicesRenderer; @Inject public ControlService(BaseServiceParams params, ServiceMonitors monitors, - HeartbeatService heartbeatService - ) { + HeartbeatService heartbeatService, + EventLogService eventLogService, + RendererFactory rendererFactory + ) throws IOException { super(params); this.monitors = monitors; + indexRenderer = rendererFactory.renderer("control/index"); + servicesRenderer = rendererFactory.renderer("control/services"); Spark.get("/public/heartbeats", (req, res) -> { res.type("application/json"); return heartbeatService.getHeartbeats(); }, gson::toJson); + Spark.get("/public/", (req, rsp) -> indexRenderer.render(Map.of())); + Spark.get("/public/services", (req, rsp) -> servicesRenderer.render( + Map.of("heartbeats", heartbeatService.getHeartbeats(), + "events", eventLogService.getLastEntries(100) + ))); + monitors.subscribe(this::logMonitorStateChange); + } private void logMonitorStateChange() { diff --git a/code/services-satellite/control-service/src/main/java/nu/marginalia/control/EventLogService.java b/code/services-satellite/control-service/src/main/java/nu/marginalia/control/EventLogService.java new file mode 100644 index 00000000..842fe86e --- /dev/null +++ b/code/services-satellite/control-service/src/main/java/nu/marginalia/control/EventLogService.java @@ -0,0 +1,49 @@ +package nu.marginalia.control; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.zaxxer.hikari.HikariDataSource; +import nu.marginalia.control.model.EventLogEntry; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +@Singleton +public class EventLogService { + + private final HikariDataSource dataSource; + + @Inject + public EventLogService(HikariDataSource dataSource) { + this.dataSource = dataSource; + } + + public List getLastEntries(int n) { + try (var conn = dataSource.getConnection(); + var query = conn.prepareStatement(""" + SELECT SERVICE_NAME, INSTANCE, EVENT_TIME, EVENT_TYPE, EVENT_MESSAGE + FROM PROC_SERVICE_EVENTLOG ORDER BY ID DESC LIMIT ? + """)) { + + query.setInt(1, n); + List entries = new ArrayList<>(n); + var rs = query.executeQuery(); + while (rs.next()) { + entries.add(new EventLogEntry( + rs.getString("SERVICE_NAME"), + rs.getString("INSTANCE"), + rs.getTimestamp("EVENT_TIME").toLocalDateTime().toLocalTime().toString(), + rs.getString("EVENT_TYPE"), + rs.getString("EVENT_MESSAGE") + )); + } + return entries; + } + catch (SQLException ex) { + throw new RuntimeException(ex); + } + } + + +} diff --git a/code/services-satellite/control-service/src/main/java/nu/marginalia/control/model/EventLogEntry.java b/code/services-satellite/control-service/src/main/java/nu/marginalia/control/model/EventLogEntry.java new file mode 100644 index 00000000..65de7699 --- /dev/null +++ b/code/services-satellite/control-service/src/main/java/nu/marginalia/control/model/EventLogEntry.java @@ -0,0 +1,10 @@ +package nu.marginalia.control.model; + +public record EventLogEntry( + String serviceName, + String instance, + String eventTime, + String eventType, + String eventMessage) +{ +} diff --git a/code/services-satellite/control-service/src/main/java/nu/marginalia/control/model/ServiceHeartbeat.java b/code/services-satellite/control-service/src/main/java/nu/marginalia/control/model/ServiceHeartbeat.java index cc0dcef4..dcb4d94e 100644 --- a/code/services-satellite/control-service/src/main/java/nu/marginalia/control/model/ServiceHeartbeat.java +++ b/code/services-satellite/control-service/src/main/java/nu/marginalia/control/model/ServiceHeartbeat.java @@ -7,5 +7,8 @@ public record ServiceHeartbeat( double lastSeenMillis, boolean alive ) { + public boolean isMissing() { + return lastSeenMillis > 10000; + } } diff --git a/code/services-satellite/control-service/src/main/resources/static/control/style.css b/code/services-satellite/control-service/src/main/resources/static/control/style.css new file mode 100644 index 00000000..6bd9166e --- /dev/null +++ b/code/services-satellite/control-service/src/main/resources/static/control/style.css @@ -0,0 +1,4 @@ +body { + font-family: serif; + line-height: 1.6; +} \ No newline at end of file diff --git a/code/services-satellite/control-service/src/main/resources/templates/control/index.hdb b/code/services-satellite/control-service/src/main/resources/templates/control/index.hdb new file mode 100644 index 00000000..701ed915 --- /dev/null +++ b/code/services-satellite/control-service/src/main/resources/templates/control/index.hdb @@ -0,0 +1,14 @@ + + + + Control Service + + + + + {{> control/partials/nav}} +
+

Overview

+
+ + \ No newline at end of file diff --git a/code/services-satellite/control-service/src/main/resources/templates/control/partials/nav.hdb b/code/services-satellite/control-service/src/main/resources/templates/control/partials/nav.hdb new file mode 100644 index 00000000..9b68f4b2 --- /dev/null +++ b/code/services-satellite/control-service/src/main/resources/templates/control/partials/nav.hdb @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/code/services-satellite/control-service/src/main/resources/templates/control/services.hdb b/code/services-satellite/control-service/src/main/resources/templates/control/services.hdb new file mode 100644 index 00000000..5b5febf2 --- /dev/null +++ b/code/services-satellite/control-service/src/main/resources/templates/control/services.hdb @@ -0,0 +1,50 @@ + + + + Control Service + + + + + {{> control/partials/nav}} + +
+

Services

+ + + + + + + {{#each heartbeats}} + + + + + + {{/each}} +
Service IDUUIDLast Seen (ms)
{{serviceId}}{{uuid}}{{lastSeenMillis}}
+ +

Events

+ + + + + + + + + + {{#each events}} + + + + + + + + {{/each}} +
Service NameInstanceEvent TimeTypeMessage
{{serviceName}}{{instance}}{{eventTime}}{{eventType}}{{eventMessage}}
+
+ + \ No newline at end of file