From 305983273b2aa607b84657866d02f9197b9288d1 Mon Sep 17 00:00:00 2001 From: ipatini Date: Wed, 28 Jul 2021 19:48:45 +0300 Subject: [PATCH 001/255] EMS: Control Service: Updated management settings in eu.melodic.event.control.properties file --- .../config-files/eu.melodic.event.control.properties | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/event-management/config-files/eu.melodic.event.control.properties b/event-management/config-files/eu.melodic.event.control.properties index 0a619cff1..6cd349390 100644 --- a/event-management/config-files/eu.melodic.event.control.properties +++ b/event-management/config-files/eu.melodic.event.control.properties @@ -148,26 +148,30 @@ beacon.topics.prediction.rate = 60000 beacon.topics.slo-violator = _slo_violator_info ################################################################################ -### Hawtio web console settings +### Management and Endpoint settings #management.endpoints.web.exposure.include=hawtio,jolokia #management.endpoints.web.base-path=/mgnt -#management.endpoints.web.path-mapping.hawtio=hawtio/console #management.endpoint.health.show-details=always +#management.security.enabled=false +#management.port=9001 +#management.address=127.0.0.1 +#endpoints.metrics.sensitive=false +### Hawtio web console settings +#management.endpoints.web.path-mapping.hawtio=hawtio/console hawtio.authenticationEnabled=false #hawtio.proxyWhitelist= #hawtio.realm=hawtio #hawtio.role=admin,viewer #hawtio.rolePrincipalClasses=org.apache.activemq.jaas.GroupPrincipal +### Jolokia (HTTP-JMX bridge) settings #jolokia.config.debug=false #endpoints.jolokia.sensitive = false #endpoints.jolokia.enabled=true #endpoints.jolokia.path=/jolokia #spring.jmx.enabled=true #endpoints.jmx.enabled=true -#management.port=9001 -#management.address=127.0.0.1 ################################################################################ ### Spring Boot Admin Client settings -- GitLab From 69d474e2622b9bf28ed73ecff457afd2b270dcae Mon Sep 17 00:00:00 2001 From: ipatini Date: Wed, 28 Jul 2021 21:20:45 +0300 Subject: [PATCH 002/255] EMS: Control Service: Added EMS information collection feature and plugged it into Actuator endpoints and JMX. Moved build info printing from ControlServiceApplication to ControlServiceBuildInfoEndpoint class. --- .../control/ControlServiceApplication.java | 50 +------- .../info/ControlServiceBuildInfoEndpoint.java | 108 ++++++++++++++++++ .../info/ControlServiceHealthIndicator.java | 36 ++++++ .../ControlServiceInfoEndpointExtension.java | 40 +++++++ .../control/info/ControlServiceMBean.java | 95 +++++++++++++++ .../control/info/ControlServiceMetrics.java | 45 ++++++++ .../control/info/EmsInfoServiceImpl.java | 18 +++ .../event/control/info/IEmsInfoService.java | 13 +++ 8 files changed, 358 insertions(+), 47 deletions(-) create mode 100644 event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceBuildInfoEndpoint.java create mode 100644 event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceHealthIndicator.java create mode 100644 event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java create mode 100644 event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceMBean.java create mode 100644 event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceMetrics.java create mode 100644 event-management/control-service/src/main/java/eu/melodic/event/control/info/EmsInfoServiceImpl.java create mode 100644 event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoService.java diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceApplication.java b/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceApplication.java index 3913e1cde..c94457e12 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceApplication.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceApplication.java @@ -12,10 +12,8 @@ package eu.melodic.event.control; import eu.melodic.event.control.properties.ControlServiceProperties; import eu.melodic.event.util.KeystoreUtil; import eu.melodic.event.util.PasswordUtil; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.catalina.connector.Connector; -import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.Banner; import org.springframework.boot.ExitCodeGenerator; @@ -24,23 +22,15 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration; import org.springframework.boot.context.ApplicationPidFileWriter; -import org.springframework.boot.info.BuildProperties; -import org.springframework.boot.info.InfoProperties; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.Resource; import org.springframework.scheduling.annotation.EnableAsync; -import org.springframework.util.StreamUtils; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.stream.StreamSupport; +import java.util.Timer; +import java.util.TimerTask; @SpringBootApplication( scanBasePackages = {"eu.melodic.event.baguette.server", "eu.melodic.event.baguette.client.install", @@ -50,7 +40,7 @@ import java.util.stream.StreamSupport; @EnableAsync @Configuration @Slf4j -public class ControlServiceApplication implements ApplicationContextAware { +public class ControlServiceApplication /*implements ApplicationContextAware*/ { private static ConfigurableApplicationContext applicationContext; private static Timer exitTimer; @@ -58,8 +48,6 @@ public class ControlServiceApplication implements ApplicationContextAware { private ControlServiceProperties properties; @Autowired private PasswordUtil passwordUtil; - @Autowired - private BuildProperties buildProperties;; public static void main(String[] args) { // Start EMS server @@ -111,36 +99,4 @@ public class ControlServiceApplication implements ApplicationContextAware { log.warn("ControlServiceApplication.exitApp(): Exit timer has already started: {}", exitTimer); } } - - @Override - @SneakyThrows - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - if (!properties.isPrintBuildInfo()) return; - if (!log.isInfoEnabled()) return; - - // Print build info from 'BuildProperties' - log.info("--------------------------------------------------------------------------------"); - log.info("Build Info:"); - StreamSupport.stream(Spliterators.spliteratorUnknownSize(buildProperties.iterator(), Spliterator.ORDERED), false) - .sorted(Comparator.comparing(InfoProperties.Entry::getKey)) - .forEach(e->log.info(" - {} = {}", e.getKey(), e.getValue())); - log.info("--------------------------------------------------------------------------------"); - - // Print info from bundled files - printInfoFromFile(applicationContext, "Version Info", "classpath:/version.txt"); - log.info("--------------------------------------------------------------------------------"); - printInfoFromFile(applicationContext, "Git Info", "classpath:/git.properties"); - log.info("--------------------------------------------------------------------------------"); - printInfoFromFile(applicationContext, "Build Info", "classpath:/META-INF/build-info.properties"); - log.info("--------------------------------------------------------------------------------"); - } - - protected void printInfoFromFile(ApplicationContext applicationContext, String title, String resourceStr) throws IOException { - Resource[] resources = applicationContext.getResources(resourceStr); - if (resources.length>0) { - Resource r = resources[0]; - log.info("** {} **\nFile: {}\nURL: {}\n{}\n", title, r.getFilename(), r.getURL(), - StreamUtils.copyToString(r.getInputStream(), StandardCharsets.UTF_8)); - } - } } \ No newline at end of file diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceBuildInfoEndpoint.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceBuildInfoEndpoint.java new file mode 100644 index 000000000..1675996bb --- /dev/null +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceBuildInfoEndpoint.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017-2022 Institute of Communication and Computer Systems (imu.iccs.gr) + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v2.0, unless + * Esper library is used, in which case it is subject to the terms of General Public License v2.0. + * If a copy of the MPL was not distributed with this file, you can obtain one at + * https://www.mozilla.org/en-US/MPL/2.0/ + */ + +package eu.melodic.event.control.info; + +import eu.melodic.event.control.properties.ControlServiceProperties; +import io.micrometer.core.lang.NonNullApi; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.endpoint.annotation.Selector; +import org.springframework.boot.info.BuildProperties; +import org.springframework.boot.info.InfoProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Component; +import org.springframework.util.StreamUtils; + +import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.stream.StreamSupport; + +@Slf4j +@Component +@NonNullApi +@Endpoint(id = "emsBuildInfo") +public class ControlServiceBuildInfoEndpoint implements ApplicationContextAware { + @Autowired + private ControlServiceProperties properties; + @Autowired + private BuildProperties buildProperties; + + private Map> infoMap; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.infoMap = new HashMap<>(); + collectBuildInfo(applicationContext, infoMap); + } + + @ReadOperation + public Map> infoMap() { return infoMap; } + + @ReadOperation + public Map info(@Selector String s) { return infoMap.get(s); } + + @SneakyThrows + protected void collectBuildInfo(ApplicationContext applicationContext, Map> infoMap) { + // Collect info from 'BuildProperties' + print("\n--------------------------------------------------------------------------------"); + print("Build Info:"); + final Map map = new LinkedHashMap<>(); + StreamSupport.stream(Spliterators.spliteratorUnknownSize(buildProperties.iterator(), Spliterator.ORDERED), false) + .sorted(Comparator.comparing(InfoProperties.Entry::getKey)) + .forEach(e->{ + print(" - {} = {}", e.getKey(), e.getValue()); + map.put(e.getKey(), e.getValue()); + }); + infoMap.put("buildProperties", map); + print("\n--------------------------------------------------------------------------------"); + + // Collect info from bundled files + infoMap.put("versionInfo", + collectInfoFromFile(applicationContext, "Version Info", "classpath:/version.txt")); + print("\n--------------------------------------------------------------------------------"); + infoMap.put("gitInfo", + collectInfoFromFile(applicationContext, "Git Info", "classpath:/git.properties")); + print("\n--------------------------------------------------------------------------------"); + infoMap.put("buildInfo", + collectInfoFromFile(applicationContext, "Build Info", "classpath:/META-INF/build-info.properties")); + print("\n--------------------------------------------------------------------------------"); + } + + protected Map collectInfoFromFile(ApplicationContext applicationContext, String title, String resourceStr) throws IOException { + Map map = new LinkedHashMap<>(); + Resource[] resources = applicationContext.getResources(resourceStr); + if (resources.length>0) { + Resource r = resources[0]; + String linesStr = StreamUtils.copyToString(r.getInputStream(), StandardCharsets.UTF_8); + print("** {} **\nFile: {}\nURL: {}\n\n{}\n", title, r.getFilename(), r.getURL(), linesStr); + Properties p; + try (StringReader sr = new StringReader(linesStr)) { + p = new Properties(); + p.load(sr); + } + for (final String name: p.stringPropertyNames()) + map.put(name, p.getProperty(name)); + } + return map; + } + + protected void print(String formatter, Object...args) { + if (!properties.isPrintBuildInfo()) return; + log.info(formatter, args); + } +} diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceHealthIndicator.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceHealthIndicator.java new file mode 100644 index 000000000..bb29f39b5 --- /dev/null +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceHealthIndicator.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017-2022 Institute of Communication and Computer Systems (imu.iccs.gr) + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v2.0, unless + * Esper library is used, in which case it is subject to the terms of General Public License v2.0. + * If a copy of the MPL was not distributed with this file, you can obtain one at + * https://www.mozilla.org/en-US/MPL/2.0/ + */ + +package eu.melodic.event.control.info; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; +import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +@Slf4j +@Component("EMS-control-service") +@ConditionalOnEnabledHealthIndicator("controlService") +public class ControlServiceHealthIndicator implements HealthIndicator, ApplicationContextAware { + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + } + + @Override + public Health health() { + Health.Builder status = Health.up() + .withDetail("message", "EMS Control Service is running"); + return status.build(); + } +} diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java new file mode 100644 index 000000000..01a0f87b6 --- /dev/null +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017-2022 Institute of Communication and Computer Systems (imu.iccs.gr) + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v2.0, unless + * Esper library is used, in which case it is subject to the terms of General Public License v2.0. + * If a copy of the MPL was not distributed with this file, you can obtain one at + * https://www.mozilla.org/en-US/MPL/2.0/ + */ + +package eu.melodic.event.control.info; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; +import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension; +import org.springframework.boot.actuate.info.InfoEndpoint; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Component +@RequiredArgsConstructor +@EndpointWebExtension(endpoint = InfoEndpoint.class) +public class ControlServiceInfoEndpointExtension { + + private final ApplicationContext applicationContext; + private final InfoEndpoint delegate; + + @ReadOperation + public WebEndpointResponse info() { + Map info = new HashMap<>(this.delegate.info()); + info.put("ems-build-info", applicationContext.getBean(ControlServiceBuildInfoEndpoint.class).infoMap()); + info.put("ems-live-info", "ToDo"); + return new WebEndpointResponse<>(info, 200); + } +} diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceMBean.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceMBean.java new file mode 100644 index 000000000..573afe175 --- /dev/null +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceMBean.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2017-2022 Institute of Communication and Computer Systems (imu.iccs.gr) + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v2.0, unless + * Esper library is used, in which case it is subject to the terms of General Public License v2.0. + * If a copy of the MPL was not distributed with this file, you can obtain one at + * https://www.mozilla.org/en-US/MPL/2.0/ + */ + +package eu.melodic.event.control.info; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.jmx.export.annotation.*; +import org.springframework.jmx.export.notification.NotificationPublisher; +import org.springframework.jmx.export.notification.NotificationPublisherAware; +import org.springframework.jmx.support.MetricType; +import org.springframework.stereotype.Component; + +import javax.management.Notification; +import java.util.Date; +import java.util.concurrent.atomic.AtomicLong; + +@Slf4j +@Component("emsControl") +@ManagedResource( + objectName = "eu.melodic.ems:category=EmsInfo,name=emsControl", + log = true, +// logFile = "ems_notif.txt", + description="EMS Control Service Bean") +@ManagedNotifications({ + @ManagedNotification(name = "randNumNotif", notificationTypes = { "java.lang.String", "java.lang.Double" }), + @ManagedNotification(name = "timestampNotif", notificationTypes = { "java.lang.String" }) +}) +public class ControlServiceMBean implements NotificationPublisherAware { + private NotificationPublisher notificationPublisher; + private AtomicLong notificationSequence = new AtomicLong(0); + + @ManagedOperation + public void testOk() { + log.warn("!!!!!!!!!!!!!!!!!!!!!!!! testOk"); + } + + @ManagedOperation + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "message", description = "Message param") + }) + public void test2(String mesg) { + log.warn("!!!!!!!!!!!!!!!!!!!!!!!! test2: {}", mesg); + } + + private String attrib; + + @ManagedAttribute + public String getAttrib() { + log.warn("!!!!!!!!!!!!!!!!!!!!!!!! getAttrib: {}", attrib); + return attrib; + } + @ManagedAttribute + public void setAttrib(String s) { + log.warn("!!!!!!!!!!!!!!!!!!!!!!!! setAttrib: {} -> {}", attrib, s); + attrib = new String(s); + } + + @ManagedMetric(category = "ems-metrics", description = "EMS metrics bla bla", displayName = "Curr Date", + metricType = MetricType.COUNTER, unit = "_date") + public Date getCurrDate() { + Date now = new Date(); + log.warn("!!!!!!!!!!!!!!!!!!!!!!!! getCurrDate: {}", now); + return now; + } + + @Override + public void setNotificationPublisher(NotificationPublisher notificationPublisher) { + this.notificationPublisher = notificationPublisher; + } + + @ManagedOperation + public void trigger() { + if (notificationPublisher != null) { + final Notification notification = new Notification("java.lang.String", + getClass().getName(), + notificationSequence.get(), + "A random number: "+(Math.random()*10000000000L)); + notificationPublisher.sendNotification(notification); + log.warn("!!!!!!!!!!!!!!!!!!!!!!!! trigger/1: {}", notification); + + final Notification notification2 = new Notification("java.lang.Double", + "source2", + notificationSequence.getAndIncrement(), + ""+(Math.random()*10000000000L)); + notificationPublisher.sendNotification(notification2); + log.warn("!!!!!!!!!!!!!!!!!!!!!!!! trigger/2: {}", notification2); + } + } +} diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceMetrics.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceMetrics.java new file mode 100644 index 000000000..973f4c4d6 --- /dev/null +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceMetrics.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2017-2022 Institute of Communication and Computer Systems (imu.iccs.gr) + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v2.0, unless + * Esper library is used, in which case it is subject to the terms of General Public License v2.0. + * If a copy of the MPL was not distributed with this file, you can obtain one at + * https://www.mozilla.org/en-US/MPL/2.0/ + */ + +package eu.melodic.event.control.info; + +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.lang.NonNullApi; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@NonNullApi +@RequiredArgsConstructor +public class ControlServiceMetrics implements ApplicationContextAware { + + private final MeterRegistry meterRegistry; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + Counter howmany = Counter + .builder("ems-howmany") + .description("EMS test counter metric") + .tags("ems", "test") + .register(meterRegistry); + howmany.increment(10); + Gauge freemem = Gauge + .builder("ems-freemem", () -> Runtime.getRuntime().freeMemory()) + .description("EMS test gauge metric") + .tags("ems", "test") + .register(meterRegistry); + } +} diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/EmsInfoServiceImpl.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/EmsInfoServiceImpl.java new file mode 100644 index 000000000..b43751bc4 --- /dev/null +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/EmsInfoServiceImpl.java @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2017-2022 Institute of Communication and Computer Systems (imu.iccs.gr) + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v2.0, unless + * Esper library is used, in which case it is subject to the terms of General Public License v2.0. + * If a copy of the MPL was not distributed with this file, you can obtain one at + * https://www.mozilla.org/en-US/MPL/2.0/ + */ + +package eu.melodic.event.control.info; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class EmsInfoServiceImpl implements IEmsInfoService { +} diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoService.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoService.java new file mode 100644 index 000000000..9c99519bb --- /dev/null +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoService.java @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2017-2022 Institute of Communication and Computer Systems (imu.iccs.gr) + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v2.0, unless + * Esper library is used, in which case it is subject to the terms of General Public License v2.0. + * If a copy of the MPL was not distributed with this file, you can obtain one at + * https://www.mozilla.org/en-US/MPL/2.0/ + */ + +package eu.melodic.event.control.info; + +public interface IEmsInfoService { +} -- GitLab From 3ff4c36ca4028c409e19c784b7e59641397130e8 Mon Sep 17 00:00:00 2001 From: ipatini Date: Thu, 29 Jul 2021 10:45:41 +0300 Subject: [PATCH 003/255] EMS: Control Service: Added Broker-CEP statistics in EMS info. Few more improvements in EMS info --- .../eu.melodic.event.control.properties | 2 +- .../info/ControlServiceBuildInfoEndpoint.java | 6 ++- .../info/ControlServiceHealthIndicator.java | 2 +- .../ControlServiceInfoEndpointExtension.java | 2 +- .../info/ControlServiceLiveInfoEndpoint.java | 43 +++++++++++++++++++ .../control/webconf/WebSecurityConfig.java | 3 +- 6 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceLiveInfoEndpoint.java diff --git a/event-management/config-files/eu.melodic.event.control.properties b/event-management/config-files/eu.melodic.event.control.properties index 6cd349390..4d19acdff 100644 --- a/event-management/config-files/eu.melodic.event.control.properties +++ b/event-management/config-files/eu.melodic.event.control.properties @@ -150,8 +150,8 @@ beacon.topics.slo-violator = _slo_violator_info ################################################################################ ### Management and Endpoint settings #management.endpoints.web.exposure.include=hawtio,jolokia -#management.endpoints.web.base-path=/mgnt #management.endpoint.health.show-details=always +#management.endpoints.web.base-path=/mgnt #management.security.enabled=false #management.port=9001 #management.address=127.0.0.1 diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceBuildInfoEndpoint.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceBuildInfoEndpoint.java index 1675996bb..a8ab3a208 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceBuildInfoEndpoint.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceBuildInfoEndpoint.java @@ -13,6 +13,7 @@ import eu.melodic.event.control.properties.ControlServiceProperties; import io.micrometer.core.lang.NonNullApi; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; @@ -60,7 +61,7 @@ public class ControlServiceBuildInfoEndpoint implements ApplicationContextAware protected void collectBuildInfo(ApplicationContext applicationContext, Map> infoMap) { // Collect info from 'BuildProperties' print("\n--------------------------------------------------------------------------------"); - print("Build Info:"); + print("===== Build Properties ====="); final Map map = new LinkedHashMap<>(); StreamSupport.stream(Spliterators.spliteratorUnknownSize(buildProperties.iterator(), Spliterator.ORDERED), false) .sorted(Comparator.comparing(InfoProperties.Entry::getKey)) @@ -89,7 +90,8 @@ public class ControlServiceBuildInfoEndpoint implements ApplicationContextAware if (resources.length>0) { Resource r = resources[0]; String linesStr = StreamUtils.copyToString(r.getInputStream(), StandardCharsets.UTF_8); - print("** {} **\nFile: {}\nURL: {}\n\n{}\n", title, r.getFilename(), r.getURL(), linesStr); + String s = StringUtils.repeat("=", title.length()+12); + print("\n{}\n===== {} =====\n{}\n=== File: {}\n=== URL: {}\n\n{}\n", s, title, s, r.getFilename(), r.getURL(), linesStr); Properties p; try (StringReader sr = new StringReader(linesStr)) { p = new Properties(); diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceHealthIndicator.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceHealthIndicator.java index bb29f39b5..98dff8c80 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceHealthIndicator.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceHealthIndicator.java @@ -19,7 +19,7 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Slf4j -@Component("EMS-control-service") +@Component("ems-control-service") @ConditionalOnEnabledHealthIndicator("controlService") public class ControlServiceHealthIndicator implements HealthIndicator, ApplicationContextAware { diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java index 01a0f87b6..fd283ff9c 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java @@ -34,7 +34,7 @@ public class ControlServiceInfoEndpointExtension { public WebEndpointResponse info() { Map info = new HashMap<>(this.delegate.info()); info.put("ems-build-info", applicationContext.getBean(ControlServiceBuildInfoEndpoint.class).infoMap()); - info.put("ems-live-info", "ToDo"); + info.put("ems-live-info", applicationContext.getBean(ControlServiceLiveInfoEndpoint.class).infoMap()); return new WebEndpointResponse<>(info, 200); } } diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceLiveInfoEndpoint.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceLiveInfoEndpoint.java new file mode 100644 index 000000000..dedaac643 --- /dev/null +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceLiveInfoEndpoint.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2017-2022 Institute of Communication and Computer Systems (imu.iccs.gr) + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v2.0, unless + * Esper library is used, in which case it is subject to the terms of General Public License v2.0. + * If a copy of the MPL was not distributed with this file, you can obtain one at + * https://www.mozilla.org/en-US/MPL/2.0/ + */ + +package eu.melodic.event.control.info; + +import eu.melodic.event.brokercep.BrokerCepService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.endpoint.annotation.Selector; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Component +@Endpoint(id = "emsLiveInfo") +public class ControlServiceLiveInfoEndpoint { + @Autowired + private BrokerCepService brokerCepService; + + @ReadOperation + public Map infoMap() { + Map infoMap = new HashMap<>(); + brokerCepService.getBrokerCepStatistics().forEach(infoMap::put); + return infoMap; + } + + @ReadOperation + public Map info(@Selector String s) { + if ("broker-cep".equals(s)) + return brokerCepService.getBrokerCepStatistics(); + throw new IllegalArgumentException("Unknown EMS info provider: "+s); + } +} diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/webconf/WebSecurityConfig.java b/event-management/control-service/src/main/java/eu/melodic/event/control/webconf/WebSecurityConfig.java index a6ad2df23..76806c212 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/webconf/WebSecurityConfig.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/webconf/WebSecurityConfig.java @@ -67,7 +67,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @EventListener(ApplicationReadyEvent.class) public void applicationReady() { - log.warn("====> afterPropertiesSet: Sample JWT Token: \nBearer {}", jwtService(melodicSecurityProperties).create("USER")); + String sep = "--------------------------------------------------------------------------------"; + log.warn("afterPropertiesSet: Sample JWT Token: \n{}\nBearer {}\n{}", sep, jwtService(melodicSecurityProperties).create("USER"), sep); } @Override -- GitLab From 620499defcec9c51d9fc9ab0b729bd43b11cb636 Mon Sep 17 00:00:00 2001 From: ipatini Date: Mon, 2 Aug 2021 12:44:37 +0300 Subject: [PATCH 004/255] EMS: Control Service: Minor code improvement --- .../event/control/info/ControlServiceLiveInfoEndpoint.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceLiveInfoEndpoint.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceLiveInfoEndpoint.java index dedaac643..7f7bdab54 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceLiveInfoEndpoint.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceLiveInfoEndpoint.java @@ -29,9 +29,7 @@ public class ControlServiceLiveInfoEndpoint { @ReadOperation public Map infoMap() { - Map infoMap = new HashMap<>(); - brokerCepService.getBrokerCepStatistics().forEach(infoMap::put); - return infoMap; + return new HashMap<>(brokerCepService.getBrokerCepStatistics()); } @ReadOperation -- GitLab From c242b0004d052d07aec667ce68ec58f36d5a7c2d Mon Sep 17 00:00:00 2001 From: ipatini Date: Tue, 3 Aug 2021 12:33:17 +0300 Subject: [PATCH 005/255] EMS: Control Service: Added Prometheus endpoint to the actuator --- event-management/control-service/pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/event-management/control-service/pom.xml b/event-management/control-service/pom.xml index 375638e73..9f2d681e8 100644 --- a/event-management/control-service/pom.xml +++ b/event-management/control-service/pom.xml @@ -23,6 +23,7 @@ 2.4.0 2.3.1 2.1.0 + 1.3.1 ${maven.build.timestamp} yyyy-MM-dd HH:mm:ss @@ -97,15 +98,24 @@ org.springframework.boot spring-boot-starter-security + org.springframework.boot spring-boot-starter-actuator + + + io.micrometer + micrometer-registry-prometheus + ${micrometer.registry.prometheus.version} + + de.codecentric spring-boot-admin-starter-client ${spring.boot.admin.version} + com.github.ulisesbocchio jasypt-spring-boot-starter -- GitLab From 92dbab1e2737de2042aebe22cbea630e6a611689 Mon Sep 17 00:00:00 2001 From: ipatini Date: Wed, 4 Aug 2021 15:04:03 +0300 Subject: [PATCH 006/255] EMS: Control Service: Added EMS InfoService supporting reactive streams [WIP]. Updated the index.html to display live metrics using InfoService. Few more minor changes --- .../event/brokercep/BrokerCepService.java | 6 +- event-management/control-service/pom.xml | 6 + .../melodic/event/control/ThreadConfig.java | 4 +- .../ControlServiceInfoEndpointExtension.java | 2 +- .../info/ControlServiceLiveInfoEndpoint.java | 16 +- .../control/info/EmsInfoServiceImpl.java | 98 ++++ .../event/control/info/IEmsInfoService.java | 13 + .../control/info/InfoServiceController.java | 77 +++ .../event/control/webconf/WebMvcConfig.java | 27 +- .../src/main/resources/public/index.html | 554 +++++++++++------- 10 files changed, 573 insertions(+), 230 deletions(-) create mode 100644 event-management/control-service/src/main/java/eu/melodic/event/control/info/InfoServiceController.java diff --git a/event-management/broker-cep/src/main/java/eu/melodic/event/brokercep/BrokerCepService.java b/event-management/broker-cep/src/main/java/eu/melodic/event/brokercep/BrokerCepService.java index a239eeccb..b6a7d28ff 100644 --- a/event-management/broker-cep/src/main/java/eu/melodic/event/brokercep/BrokerCepService.java +++ b/event-management/broker-cep/src/main/java/eu/melodic/event/brokercep/BrokerCepService.java @@ -399,7 +399,7 @@ public class BrokerCepService { } public Map getBrokerCepStatistics() { - Map bcepStats = new HashMap<>(); + Map bcepStats = new HashMap<>(); bcepStats.put("count-event-local-publish-success", BrokerCepStatementSubscriber.getLocalPublishSuccessCounter()); bcepStats.put("count-event-local-publish-failure", BrokerCepStatementSubscriber.getLocalPublishFailureCounter()); bcepStats.put("count-event-forwards-success", BrokerCepStatementSubscriber.getForwardSuccessCounter()); @@ -410,9 +410,7 @@ public class BrokerCepService { bcepStats.put("count-total-events-other", BrokerCepConsumer.getOtherEventCounter()); bcepStats.put("count-total-events-failures", BrokerCepConsumer.getEventFailuresCounter()); - Map statsMap = new HashMap<>(); - statsMap.put("broker-cep", bcepStats); - return statsMap; + return bcepStats; } public void clearBrokerCepStatistics() { diff --git a/event-management/control-service/pom.xml b/event-management/control-service/pom.xml index 9f2d681e8..03db50e57 100644 --- a/event-management/control-service/pom.xml +++ b/event-management/control-service/pom.xml @@ -94,10 +94,16 @@ org.springframework.boot spring-boot-starter-web + org.springframework.boot spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-webflux + org.springframework.boot diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/ThreadConfig.java b/event-management/control-service/src/main/java/eu/melodic/event/control/ThreadConfig.java index 10431248c..311860431 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/ThreadConfig.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/ThreadConfig.java @@ -16,9 +16,9 @@ import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -@Configuration -@EnableAsync @Slf4j +@EnableAsync +@Configuration public class ThreadConfig { /*@Bean diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java index fd283ff9c..c27828409 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java @@ -34,7 +34,7 @@ public class ControlServiceInfoEndpointExtension { public WebEndpointResponse info() { Map info = new HashMap<>(this.delegate.info()); info.put("ems-build-info", applicationContext.getBean(ControlServiceBuildInfoEndpoint.class).infoMap()); - info.put("ems-live-info", applicationContext.getBean(ControlServiceLiveInfoEndpoint.class).infoMap()); + info.put("ems-live-info", applicationContext.getBean(IEmsInfoService.class).getMetricValues()); return new WebEndpointResponse<>(info, 200); } } diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceLiveInfoEndpoint.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceLiveInfoEndpoint.java index 7f7bdab54..c686c8554 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceLiveInfoEndpoint.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceLiveInfoEndpoint.java @@ -9,33 +9,33 @@ package eu.melodic.event.control.info; -import eu.melodic.event.brokercep.BrokerCepService; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.Selector; import org.springframework.stereotype.Component; -import java.util.HashMap; import java.util.Map; @Slf4j @Component @Endpoint(id = "emsLiveInfo") +@RequiredArgsConstructor public class ControlServiceLiveInfoEndpoint { - @Autowired - private BrokerCepService brokerCepService; + + private final IEmsInfoService emsInfoService; @ReadOperation public Map infoMap() { - return new HashMap<>(brokerCepService.getBrokerCepStatistics()); + return emsInfoService.getMetricValues(); } @ReadOperation public Map info(@Selector String s) { - if ("broker-cep".equals(s)) - return brokerCepService.getBrokerCepStatistics(); + Map v = emsInfoService.getMetricValuesFor(s); + if (v!=null) + return v; throw new IllegalArgumentException("Unknown EMS info provider: "+s); } } diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/EmsInfoServiceImpl.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/EmsInfoServiceImpl.java index b43751bc4..ea4bd5958 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/info/EmsInfoServiceImpl.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/EmsInfoServiceImpl.java @@ -9,10 +9,108 @@ package eu.melodic.event.control.info; +import eu.melodic.event.brokercep.BrokerCepService; +import eu.melodic.event.control.properties.ControlServiceProperties; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; +import java.io.File; +import java.lang.management.*; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + @Slf4j @Service +@RequiredArgsConstructor public class EmsInfoServiceImpl implements IEmsInfoService { + + private static final long METRICS_UPDATE_INTERVAL = 1000; + + private final ApplicationContext applicationContext; + private final ControlServiceProperties properties; + private final BrokerCepService brokerCepService; + + private final AtomicLong currentMetricsVersion = new AtomicLong(0); + private final File root = new File("/"); + private Map currentMetrics; + + @Override + public Map getMetricValues() { + updateMetricValues(false); + return currentMetrics; + } + + public Map getMetricValuesFor(String key) { + return (Map) getMetricValues().get(key); + } + + protected void updateMetricValues(boolean includeStaticInfo) { + if (currentMetrics!=null) { + long timestamp = (long) currentMetrics.get(".timestamp"); + if (System.currentTimeMillis() - timestamp < METRICS_UPDATE_INTERVAL) + return; + } + + long timestamp = System.currentTimeMillis(); + + Map metrics = new LinkedHashMap<>(); + + // Collect System and JVM metrics + metrics.put(SYSTEM_INFO_PROVIDER, getSystemAndJvmMetrics()); + + // Collect EMS build info + if (includeStaticInfo) + metrics.put(EMS_INFO_PROVIDER, applicationContext.getBean(ControlServiceBuildInfoEndpoint.class).infoMap()); + + // Collect Broker-CEP metrics + metrics.put(BROKER_CEP_INFO_PROVIDER, brokerCepService.getBrokerCepStatistics()); + + synchronized (currentMetricsVersion) { + if (currentMetrics==null || (long)currentMetrics.get(".timestamp") < timestamp) { + long version = currentMetricsVersion.getAndIncrement(); + metrics.put(".version", version); + metrics.put(".timestamp", timestamp); + this.currentMetrics = metrics; + } + } + } + + protected Map getSystemAndJvmMetrics() { + Map sysInfo = new LinkedHashMap<>(); + sysInfo.put("jvm-memory-total", Runtime.getRuntime().totalMemory()); + sysInfo.put("jvm-memory-max", Runtime.getRuntime().freeMemory()); + sysInfo.put("jvm-memory-free", Runtime.getRuntime().maxMemory()); + + MemoryMXBean memBean = ManagementFactory.getMemoryMXBean() ; + String heapInfo = memBean.getHeapMemoryUsage().toString(); + String nonHeapInfo = memBean.getNonHeapMemoryUsage().toString(); + sysInfo.put("jvm-memory-heap", heapInfo); + sysInfo.put("jvm-memory-non-heap", nonHeapInfo); + + ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); + sysInfo.put("jvm-thread-count", threadBean.getThreadCount()); + sysInfo.put("jvm-thread-daemon-count", threadBean.getDaemonThreadCount()); + sysInfo.put("jvm-thread-peak-count", threadBean.getPeakThreadCount()); + sysInfo.put("jvm-thread-total-started-count", threadBean.getTotalStartedThreadCount()); + + RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); + long uptime = runtimeBean.getUptime() / 1000; + String vmInfo = String.format("%s, ver.%s, by %s", runtimeBean.getVmName(), runtimeBean.getVmVersion(), runtimeBean.getVmVendor()); + sysInfo.put("jvm-info", vmInfo); + sysInfo.put("jvm-uptime", uptime); + + OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); + String osInfo = String.format("OS %s, %s, v.%s, processors: %d, avg. load: %.02f", osBean.getName(), osBean.getArch(), osBean.getVersion(), + osBean.getAvailableProcessors(), osBean.getSystemLoadAverage()); + sysInfo.put("os-info", osInfo); + + sysInfo.put("os-disk-total", root.getTotalSpace()); + sysInfo.put("os-disk-free", root.getFreeSpace()); + sysInfo.put("os-disk-usable", root.getUsableSpace()); + + return sysInfo; + } } diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoService.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoService.java index 9c99519bb..cf70110f0 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoService.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoService.java @@ -9,5 +9,18 @@ package eu.melodic.event.control.info; +import java.util.Map; + public interface IEmsInfoService { + String SYSTEM_INFO_PROVIDER = "system-info"; + String EMS_INFO_PROVIDER = "ems-info"; + String CONTROL_INFO_PROVIDER = "control"; + String BROKER_CEP_INFO_PROVIDER = "broker-cep"; + String BAGUETTE_SERVER_INFO_PROVIDER = "baguette-server"; + String CLIENT_INSTALLER_INFO_PROVIDER = "baguette-client-installer"; + String TRANSLATOR_INFO_PROVIDER = "translator"; + String MISC_INFO_PROVIDER = "misc-info"; + + Map getMetricValues(); + Map getMetricValuesFor(String key); } diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/InfoServiceController.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/InfoServiceController.java new file mode 100644 index 000000000..1b53e65cb --- /dev/null +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/InfoServiceController.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2017-2022 Institute of Communication and Computer Systems (imu.iccs.gr) + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v2.0, unless + * Esper library is used, in which case it is subject to the terms of General Public License v2.0. + * If a copy of the MPL was not distributed with this file, you can obtain one at + * https://www.mozilla.org/en-US/MPL/2.0/ + */ + +package eu.melodic.event.control.info; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.codec.ServerSentEvent; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.QueryParam; +import java.time.Duration; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +@Slf4j +@RestController +@RequiredArgsConstructor +public class InfoServiceController { + + private static final int DEFAULT_STREAM_INTERVAL = 30; // in seconds + private static final String EVENT_STREAM_NAME = "ems-metrics-event"; + + private final IEmsInfoService emsInfoService; + + @GetMapping("/info/metrics/get") + public Mono> metricsGet(HttpServletRequest request) { + log.info("metricsGet(): --- client: {}:{}, user: {}", + request.getRemoteAddr(), request.getRemotePort(), request.getRemoteUser()); + Map message = createMetricsResult(null, -1L); + log.debug("metricsGet(): message={}", message); + return Mono.just(message); + } + + @GetMapping("/info/metrics/stream") + public Flux>> metricsStream(@QueryParam("interval") Optional interval, + HttpServletRequest request) + { + String sid = UUID.randomUUID().toString(); + log.info("metricsStream(): interval={} --- client: {}:{}, user: {}, Stream-Id: {}", + interval, request.getRemoteAddr(), request.getRemotePort(), request.getRemoteUser(), sid); + int intervalInSeconds = interval.orElse(-1); + if (intervalInSeconds<1) intervalInSeconds = DEFAULT_STREAM_INTERVAL; + log.debug("metricsStream(): effective-interval={}", intervalInSeconds); + + return Flux.interval(Duration.ofSeconds(intervalInSeconds)) + .onBackpressureDrop() + .map(sequence -> { + Map message = createMetricsResult(sid, sequence); + log.debug("metricsStream(): seq={}, id={}, message={}", sequence, sid, message); + return ServerSentEvent.> builder() + .id(String.valueOf(sequence)) + .event(EVENT_STREAM_NAME) + .data(message) + .build(); + }); + } + + public Map createMetricsResult(String sid, long sequence) { + Map metrics = emsInfoService.getMetricValues(); + metrics.put(".stream-id", sid); + metrics.put(".sequence", sequence); + log.trace("createMetricsResult: {}", metrics); + return metrics; + } +} diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/webconf/WebMvcConfig.java b/event-management/control-service/src/main/java/eu/melodic/event/control/webconf/WebMvcConfig.java index 69936cda9..82e80eb46 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/webconf/WebMvcConfig.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/webconf/WebMvcConfig.java @@ -15,20 +15,31 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ArrayUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.core.task.AsyncTaskExecutor; +import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; import org.springframework.stereotype.Component; +import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +@Slf4j @Component @ComponentScan(basePackages={"eu.melodic.security.authorization.util.properties"}) -@Slf4j public class WebMvcConfig implements WebMvcConfigurer { private final static String[] DEFAULT_PATHS_PROTECTED = { "/**" }; private final static String[] DEFAULT_PATHS_EXCLUDED = { }; @Autowired private AuthorizationServiceClientProperties authProperties; + @Autowired + private ApplicationContext applicationContext; @Value("${authorization.enabled:true}") private boolean authEnabled; @@ -59,4 +70,18 @@ public class WebMvcConfig implements WebMvcConfigurer { log.debug("WebMvcConfig.addInterceptors(): Registered Authorization interceptor"); } } + + @Override + public void configureAsyncSupport(AsyncSupportConfigurer configurer) { + configurer.setTaskExecutor(applicationContext.getBean("asyncExecutor", AsyncTaskExecutor.class)); + } + + @Bean(name="asyncExecutor") + public AsyncTaskExecutor asyncExecutor() { + ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool(); + log.debug("asyncExecutor(): ThreadPoolExecutor: core={}, max={}, size={}, active={}, keep-alive={}", + executor.getCorePoolSize(), executor.getMaximumPoolSize(), executor.getPoolSize(), + executor.getActiveCount(), executor.getKeepAliveTime(TimeUnit.SECONDS)); + return new ConcurrentTaskExecutor(executor); + } } \ No newline at end of file diff --git a/event-management/control-service/src/main/resources/public/index.html b/event-management/control-service/src/main/resources/public/index.html index 6cf1f219f..8b3f453e7 100644 --- a/event-management/control-service/src/main/resources/public/index.html +++ b/event-management/control-service/src/main/resources/public/index.html @@ -8,7 +8,7 @@ --> - + //--> + -

EMS - Event Generation and Publish

- - - - - -

Settings

- - - - -
Base URL:
- - +

EMS - Event Generation and Publish

-

Send Commands to Clients - [List] - [Map]

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ClientCommandActionsResult
- - + + + + + + + - - - -

Settings

+ + + + + + +
Base URL:
+ +

Event Publishing

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SesnorClientValueActionsResult
- - - -

Event Generation

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SesnorClientIntervalLower ValueUpper ValueActionsResult
- -
- -
- -
- -
- -
- - + +

Send Commands to Clients

+ + + +

[List] + [Map]

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClientCommandActionsResult
+ +
+ +
+ +
+ +
+ +
+ + + + + +

Event Publishing

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SesnorClientValueActionsResult
+ +
+ +
+ +
+ +
+ +
+ + + + + +

Event Generation

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SensorClientIntervalLower ValueUpper ValueActionsResult
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + + + +

Live Metrics:

+ + + + + + +
+ + + + + + +

Statistics:

+ + + + + + -

Downloads:

- - - + +

Downloads:

+ + + + + + + -

Statistics:

- - - - - \ No newline at end of file -- GitLab From 5b4de1b302819bd5f72a2e173731a01f5d2e36cc Mon Sep 17 00:00:00 2001 From: ipatini Date: Wed, 4 Aug 2021 17:04:24 +0300 Subject: [PATCH 007/255] EMS: Control Service: Moved EMS statistics endpoints from ControlServiceController and ControlServiceCoordinator to InfoServiceController --- .../control/ControlServiceController.java | 37 +-------------- .../control/ControlServiceCoordinator.java | 47 ------------------- 2 files changed, 2 insertions(+), 82 deletions(-) diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceController.java b/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceController.java index 87d88092a..cdd495a43 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceController.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceController.java @@ -11,7 +11,8 @@ package eu.melodic.event.control; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import eu.melodic.event.baguette.client.install.*; +import eu.melodic.event.baguette.client.install.ClientInstallationTask; +import eu.melodic.event.baguette.client.install.ClientInstaller; import eu.melodic.event.baguette.client.install.helper.InstallationHelperFactory; import eu.melodic.event.baguette.client.install.instruction.InstallationInstructions; import eu.melodic.event.baguette.server.BaguetteServer; @@ -460,40 +461,6 @@ public class ControlServiceController { return "{}"; } - @RequestMapping(value = "/ems/stats", method = {GET, POST}, - produces = MediaType.APPLICATION_JSON_UTF8_VALUE) - public Map emsServerStatistics() { - log.debug("ControlServiceController.emsServerStatistics(): BEGIN"); - Map statsMap = coordinator.emsServerStatistics(); - log.debug("ControlServiceController.emsServerStatistics(): END: {}", statsMap); - return statsMap; - } - - @RequestMapping(value = "/ems/stats/overall", method = {GET, POST}, - produces = MediaType.APPLICATION_JSON_UTF8_VALUE) - public Map emsOverallStatistics() { - log.debug("ControlServiceController.emsOverallStatistics(): BEGIN"); - Map statsMap = coordinator.emsOverallStatistics(); - log.debug("ControlServiceController.emsOverallStatistics(): END: {}", statsMap); - return statsMap; - } - - @RequestMapping(value = "/ems/stats/clear", method = {GET, POST}) - public String emsServerStatisticsClear() { - log.debug("ControlServiceController.emsServerStatisticsClear(): BEGIN"); - coordinator.emsServerStatisticsClear(); - log.debug("ControlServiceController.emsServerStatisticsClear(): END"); - return "OK"; - } - - @RequestMapping(value = "/ems/stats/overall/clear", method = {GET, POST}) - public String emsOverallStatisticsClear() { - log.debug("ControlServiceController.emsOverallStatisticsClear(): BEGIN"); - coordinator.emsOverallStatisticsClear(); - log.debug("ControlServiceController.emsOverallStatisticsClear(): END"); - return "OK"; - } - // ------------------------------------------------------------------------------------------------------------ @RequestMapping(value = "/health", method = GET) diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceCoordinator.java b/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceCoordinator.java index 3fa702d22..fbad17e66 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceCoordinator.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceCoordinator.java @@ -952,51 +952,4 @@ public class ControlServiceCoordinator { } // ------------------------------------------------------------------------------------------------------------ - - public Map emsServerStatistics() { - log.debug("ControlServiceCoordinator.emsServerStatistics(): BEGIN"); - Map statsMap = brokerCep.getBrokerCepStatistics(); - log.debug("ControlServiceCoordinator.emsServerStatistics(): END: {}", statsMap); - return statsMap; - } - - public Map emsOverallStatistics() { - log.debug("ControlServiceCoordinator.emsOverallStatistics(): BEGIN"); - - // Collecting EMS server statistics - Map serverStats = emsServerStatistics(); - Map statsMap = new HashMap<>(); - statsMap.put("server", serverStats); - - // Collecting EMS clients' statistics - log.trace("ControlServiceCoordinator.emsOverallStatistics(): clients: {}", clientList()); - for (String clientId : clientList().stream().map(s->s.split(" ")[0]).collect(Collectors.toList())) { - log.trace("ControlServiceCoordinator.emsOverallStatistics(): Requesting statistics from client: {}", clientId); - Object o = baguette.readFromClient(clientId, "SHOW-STATS"); - log.trace("ControlServiceCoordinator.emsOverallStatistics(): Statistics from client: {}, stats: {}", clientId, o); - if (o instanceof Map) { - statsMap.put(clientId, o); - } - } - - log.debug("ControlServiceCoordinator.emsOverallStatistics(): END: {}", statsMap); - return statsMap; - } - - public void emsServerStatisticsClear() { - log.debug("ControlServiceCoordinator.emsServerStatisticsClear(): BEGIN"); - brokerCep.clearBrokerCepStatistics(); - log.info("ControlServiceCoordinator.emsServerStatisticsClear(): EMS server statistics cleared"); - log.debug("ControlServiceCoordinator.emsServerStatisticsClear(): END"); - } - - public void emsOverallStatisticsClear() { - log.debug("ControlServiceCoordinator.emsOverallStatisticsClear(): BEGIN"); - emsServerStatisticsClear(); - clientCommandSend("*", "CLEAR-STATS"); - log.info("ControlServiceCoordinator.emsOverallStatisticsClear(): All EMS statistics cleared"); - log.debug("ControlServiceCoordinator.emsOverallStatisticsClear(): END"); - } - - // ------------------------------------------------------------------------------------------------------------ } -- GitLab From 753ad90f194c6dedc0973f3e34ad57434c64af3c Mon Sep 17 00:00:00 2001 From: ipatini Date: Wed, 4 Aug 2021 21:57:49 +0300 Subject: [PATCH 008/255] EMS: Control Service: Added IEmsInfoProvider interface. Moved EMS info collection code to InfoProviders (except Broker-CEP). Added metrics collection from baguette clients [WIP] --- .../control/ControlServiceCoordinator.java | 4 +- .../event/control/info/BuildInfoProvider.java | 103 +++++++++++++++ .../info/ControlServiceBuildInfoEndpoint.java | 85 +----------- .../ControlServiceInfoEndpointExtension.java | 2 +- .../control/info/EmsInfoServiceImpl.java | 121 +++++++++++------- .../event/control/info/IEmsInfoProvider.java | 22 ++++ .../event/control/info/IEmsInfoService.java | 8 +- .../control/info/InfoServiceController.java | 66 +++++++--- .../control/info/SystemInfoProvider.java | 64 +++++++++ .../properties/ControlServiceProperties.java | 10 ++ .../event/control/util/TopicBeacon.java | 2 +- .../src/main/resources/public/index.html | 5 +- 12 files changed, 347 insertions(+), 145 deletions(-) create mode 100644 event-management/control-service/src/main/java/eu/melodic/event/control/info/BuildInfoProvider.java create mode 100644 event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoProvider.java create mode 100644 event-management/control-service/src/main/java/eu/melodic/event/control/info/SystemInfoProvider.java diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceCoordinator.java b/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceCoordinator.java index fbad17e66..a9d9d7c68 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceCoordinator.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/ControlServiceCoordinator.java @@ -938,12 +938,12 @@ public class ControlServiceCoordinator { public List clientList() { log.debug("ControlServiceCoordinator.clientList(): BEGIN:"); - return baguette.getActiveClients(); + return baguette.isServerRunning() ? baguette.getActiveClients() : Collections.emptyList(); } public Map> clientMap() { log.debug("ControlServiceCoordinator.clientMap(): BEGIN:"); - return baguette.getActiveClientsMap(); + return baguette.isServerRunning() ? baguette.getActiveClientsMap() : Collections.emptyMap(); } public String clientCommandSend(String clientId, String command) { diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/BuildInfoProvider.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/BuildInfoProvider.java new file mode 100644 index 000000000..e8b3ac592 --- /dev/null +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/BuildInfoProvider.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2017-2022 Institute of Communication and Computer Systems (imu.iccs.gr) + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v2.0, unless + * Esper library is used, in which case it is subject to the terms of General Public License v2.0. + * If a copy of the MPL was not distributed with this file, you can obtain one at + * https://www.mozilla.org/en-US/MPL/2.0/ + */ + +package eu.melodic.event.control.info; + +import eu.melodic.event.control.properties.ControlServiceProperties; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.endpoint.annotation.Selector; +import org.springframework.boot.info.BuildProperties; +import org.springframework.boot.info.InfoProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Component; +import org.springframework.util.StreamUtils; + +import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.stream.StreamSupport; + +@Slf4j +@Component +public class BuildInfoProvider implements ApplicationContextAware, IEmsInfoProvider { + @Autowired + private ControlServiceProperties properties; + @Autowired + private BuildProperties buildProperties; + + private Map infoMap; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.infoMap = new HashMap<>(); + collectBuildInfo(applicationContext, infoMap); + } + + @Override + public Map getMetricValues() { return infoMap; } + + @SneakyThrows + protected void collectBuildInfo(ApplicationContext applicationContext, Map infoMap) { + // Collect info from 'BuildProperties' + print("\n--------------------------------------------------------------------------------"); + print("===== Build Properties ====="); + final Map map = new LinkedHashMap<>(); + StreamSupport.stream(Spliterators.spliteratorUnknownSize(buildProperties.iterator(), Spliterator.ORDERED), false) + .sorted(Comparator.comparing(InfoProperties.Entry::getKey)) + .forEach(e->{ + print(" - {} = {}", e.getKey(), e.getValue()); + map.put(e.getKey(), e.getValue()); + }); + infoMap.put("buildProperties", map); + print("\n--------------------------------------------------------------------------------"); + + // Collect info from bundled files + infoMap.put("versionInfo", + collectInfoFromFile(applicationContext, "Version Info", "classpath:/version.txt")); + print("\n--------------------------------------------------------------------------------"); + infoMap.put("gitInfo", + collectInfoFromFile(applicationContext, "Git Info", "classpath:/git.properties")); + print("\n--------------------------------------------------------------------------------"); + infoMap.put("buildInfo", + collectInfoFromFile(applicationContext, "Build Info", "classpath:/META-INF/build-info.properties")); + print("\n--------------------------------------------------------------------------------"); + } + + protected Map collectInfoFromFile(ApplicationContext applicationContext, String title, String resourceStr) throws IOException { + Map map = new LinkedHashMap<>(); + Resource[] resources = applicationContext.getResources(resourceStr); + if (resources.length>0) { + Resource r = resources[0]; + String linesStr = StreamUtils.copyToString(r.getInputStream(), StandardCharsets.UTF_8); + String s = StringUtils.repeat("=", title.length()+12); + print("\n{}\n===== {} =====\n{}\n=== File: {}\n=== URL: {}\n\n{}\n", s, title, s, r.getFilename(), r.getURL(), linesStr); + Properties p; + try (StringReader sr = new StringReader(linesStr)) { + p = new Properties(); + p.load(sr); + } + for (final String name: p.stringPropertyNames()) + map.put(name, p.getProperty(name)); + } + return map; + } + + protected void print(String formatter, Object...args) { + if (!properties.isPrintBuildInfo()) return; + log.info(formatter, args); + } +} diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceBuildInfoEndpoint.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceBuildInfoEndpoint.java index a8ab3a208..2559ce366 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceBuildInfoEndpoint.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceBuildInfoEndpoint.java @@ -9,102 +9,27 @@ package eu.melodic.event.control.info; -import eu.melodic.event.control.properties.ControlServiceProperties; import io.micrometer.core.lang.NonNullApi; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.Selector; -import org.springframework.boot.info.BuildProperties; -import org.springframework.boot.info.InfoProperties; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.core.io.Resource; import org.springframework.stereotype.Component; -import org.springframework.util.StreamUtils; -import java.io.IOException; -import java.io.StringReader; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.stream.StreamSupport; +import java.util.Map; @Slf4j @Component @NonNullApi @Endpoint(id = "emsBuildInfo") -public class ControlServiceBuildInfoEndpoint implements ApplicationContextAware { +public class ControlServiceBuildInfoEndpoint { @Autowired - private ControlServiceProperties properties; - @Autowired - private BuildProperties buildProperties; - - private Map> infoMap; - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.infoMap = new HashMap<>(); - collectBuildInfo(applicationContext, infoMap); - } + private BuildInfoProvider buildInfoProvider; @ReadOperation - public Map> infoMap() { return infoMap; } + public Map infoMap() { return buildInfoProvider.getMetricValues(); } @ReadOperation - public Map info(@Selector String s) { return infoMap.get(s); } - - @SneakyThrows - protected void collectBuildInfo(ApplicationContext applicationContext, Map> infoMap) { - // Collect info from 'BuildProperties' - print("\n--------------------------------------------------------------------------------"); - print("===== Build Properties ====="); - final Map map = new LinkedHashMap<>(); - StreamSupport.stream(Spliterators.spliteratorUnknownSize(buildProperties.iterator(), Spliterator.ORDERED), false) - .sorted(Comparator.comparing(InfoProperties.Entry::getKey)) - .forEach(e->{ - print(" - {} = {}", e.getKey(), e.getValue()); - map.put(e.getKey(), e.getValue()); - }); - infoMap.put("buildProperties", map); - print("\n--------------------------------------------------------------------------------"); - - // Collect info from bundled files - infoMap.put("versionInfo", - collectInfoFromFile(applicationContext, "Version Info", "classpath:/version.txt")); - print("\n--------------------------------------------------------------------------------"); - infoMap.put("gitInfo", - collectInfoFromFile(applicationContext, "Git Info", "classpath:/git.properties")); - print("\n--------------------------------------------------------------------------------"); - infoMap.put("buildInfo", - collectInfoFromFile(applicationContext, "Build Info", "classpath:/META-INF/build-info.properties")); - print("\n--------------------------------------------------------------------------------"); - } - - protected Map collectInfoFromFile(ApplicationContext applicationContext, String title, String resourceStr) throws IOException { - Map map = new LinkedHashMap<>(); - Resource[] resources = applicationContext.getResources(resourceStr); - if (resources.length>0) { - Resource r = resources[0]; - String linesStr = StreamUtils.copyToString(r.getInputStream(), StandardCharsets.UTF_8); - String s = StringUtils.repeat("=", title.length()+12); - print("\n{}\n===== {} =====\n{}\n=== File: {}\n=== URL: {}\n\n{}\n", s, title, s, r.getFilename(), r.getURL(), linesStr); - Properties p; - try (StringReader sr = new StringReader(linesStr)) { - p = new Properties(); - p.load(sr); - } - for (final String name: p.stringPropertyNames()) - map.put(name, p.getProperty(name)); - } - return map; - } - - protected void print(String formatter, Object...args) { - if (!properties.isPrintBuildInfo()) return; - log.info(formatter, args); - } + public Map info(@Selector String s) { return buildInfoProvider.getMetricValuesFor(s); } } diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java index c27828409..00a8daf99 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/ControlServiceInfoEndpointExtension.java @@ -33,7 +33,7 @@ public class ControlServiceInfoEndpointExtension { @ReadOperation public WebEndpointResponse info() { Map info = new HashMap<>(this.delegate.info()); - info.put("ems-build-info", applicationContext.getBean(ControlServiceBuildInfoEndpoint.class).infoMap()); + info.put("ems-build-info", applicationContext.getBean(BuildInfoProvider.class).getMetricValues()); info.put("ems-live-info", applicationContext.getBean(IEmsInfoService.class).getMetricValues()); return new WebEndpointResponse<>(info, 200); } diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/EmsInfoServiceImpl.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/EmsInfoServiceImpl.java index ea4bd5958..fef107d52 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/info/EmsInfoServiceImpl.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/EmsInfoServiceImpl.java @@ -9,33 +9,57 @@ package eu.melodic.event.control.info; +import eu.melodic.event.baguette.server.BaguetteServer; import eu.melodic.event.brokercep.BrokerCepService; +import eu.melodic.event.control.ControlServiceCoordinator; import eu.melodic.event.control.properties.ControlServiceProperties; +import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; -import java.io.File; -import java.lang.management.*; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor public class EmsInfoServiceImpl implements IEmsInfoService { - private static final long METRICS_UPDATE_INTERVAL = 1000; + private final AtomicLong currentMetricsVersion = new AtomicLong(0); + private final AtomicLong currentClientMetricsVersion = new AtomicLong(0); + private Map currentMetrics; + private Map currentClientMetrics; private final ApplicationContext applicationContext; private final ControlServiceProperties properties; + private final ControlServiceCoordinator controlServiceCoordinator; + private final BaguetteServer baguetteServer; + + private final BuildInfoProvider buildInfoProvider; + private final SystemInfoProvider systemInfoProvider; private final BrokerCepService brokerCepService; - private final AtomicLong currentMetricsVersion = new AtomicLong(0); - private final File root = new File("/"); - private Map currentMetrics; + @Override + public synchronized void clearMetricValues() { + log.debug("clearMetricValues(): BEGIN"); + systemInfoProvider.clearMetricValues(); + brokerCepService.clearBrokerCepStatistics(); + currentMetrics = null; + log.debug("clearMetricValues(): END"); + } + + @Override + public synchronized void clearClientMetricValues() { + log.debug("clearClientMetricValues(): BEGIN"); + currentClientMetrics = null; + controlServiceCoordinator.clientCommandSend("*", "CLEAR-STATS"); + log.debug("clearClientMetricValues(): END"); + } @Override public Map getMetricValues() { @@ -47,10 +71,23 @@ public class EmsInfoServiceImpl implements IEmsInfoService { return (Map) getMetricValues().get(key); } + @Override + public Map getClientMetricValues() { + updateClientMetricValues(); + return currentClientMetrics; + } + + @Override + public Map getClientMetricValues(@NonNull String clientId) { + return (Map) getClientMetricValues().get(clientId); + } + + // ------------------------------------------------------------------------ + protected void updateMetricValues(boolean includeStaticInfo) { if (currentMetrics!=null) { long timestamp = (long) currentMetrics.get(".timestamp"); - if (System.currentTimeMillis() - timestamp < METRICS_UPDATE_INTERVAL) + if (System.currentTimeMillis() - timestamp < properties.getMetricsUpdateInterval()) return; } @@ -59,11 +96,11 @@ public class EmsInfoServiceImpl implements IEmsInfoService { Map metrics = new LinkedHashMap<>(); // Collect System and JVM metrics - metrics.put(SYSTEM_INFO_PROVIDER, getSystemAndJvmMetrics()); + metrics.put(SYSTEM_INFO_PROVIDER, systemInfoProvider.getMetricValues()); // Collect EMS build info if (includeStaticInfo) - metrics.put(EMS_INFO_PROVIDER, applicationContext.getBean(ControlServiceBuildInfoEndpoint.class).infoMap()); + metrics.put(BUILD_INFO_PROVIDER, buildInfoProvider.getMetricValues()); // Collect Broker-CEP metrics metrics.put(BROKER_CEP_INFO_PROVIDER, brokerCepService.getBrokerCepStatistics()); @@ -78,39 +115,37 @@ public class EmsInfoServiceImpl implements IEmsInfoService { } } - protected Map getSystemAndJvmMetrics() { - Map sysInfo = new LinkedHashMap<>(); - sysInfo.put("jvm-memory-total", Runtime.getRuntime().totalMemory()); - sysInfo.put("jvm-memory-max", Runtime.getRuntime().freeMemory()); - sysInfo.put("jvm-memory-free", Runtime.getRuntime().maxMemory()); - - MemoryMXBean memBean = ManagementFactory.getMemoryMXBean() ; - String heapInfo = memBean.getHeapMemoryUsage().toString(); - String nonHeapInfo = memBean.getNonHeapMemoryUsage().toString(); - sysInfo.put("jvm-memory-heap", heapInfo); - sysInfo.put("jvm-memory-non-heap", nonHeapInfo); - - ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); - sysInfo.put("jvm-thread-count", threadBean.getThreadCount()); - sysInfo.put("jvm-thread-daemon-count", threadBean.getDaemonThreadCount()); - sysInfo.put("jvm-thread-peak-count", threadBean.getPeakThreadCount()); - sysInfo.put("jvm-thread-total-started-count", threadBean.getTotalStartedThreadCount()); - - RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); - long uptime = runtimeBean.getUptime() / 1000; - String vmInfo = String.format("%s, ver.%s, by %s", runtimeBean.getVmName(), runtimeBean.getVmVersion(), runtimeBean.getVmVendor()); - sysInfo.put("jvm-info", vmInfo); - sysInfo.put("jvm-uptime", uptime); - - OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); - String osInfo = String.format("OS %s, %s, v.%s, processors: %d, avg. load: %.02f", osBean.getName(), osBean.getArch(), osBean.getVersion(), - osBean.getAvailableProcessors(), osBean.getSystemLoadAverage()); - sysInfo.put("os-info", osInfo); - - sysInfo.put("os-disk-total", root.getTotalSpace()); - sysInfo.put("os-disk-free", root.getFreeSpace()); - sysInfo.put("os-disk-usable", root.getUsableSpace()); - - return sysInfo; + protected void updateClientMetricValues() { + if (currentClientMetrics!=null) { + long timestamp = (long) currentClientMetrics.get(".timestamp"); + if (System.currentTimeMillis() - timestamp < properties.getMetricsClientUpdateInterval()) + return; + } + + long timestamp = System.currentTimeMillis(); + + Map clientMetrics = new LinkedHashMap<>(); + + // Collecting EMS clients' metrics + List clientIds = controlServiceCoordinator.clientList(); + log.trace("updateClientMetricValues(): active-baguette-clients: {}", clientIds); + for (String clientId : clientIds.stream().map(s->s.split(" ")[0]).collect(Collectors.toList())) { + log.trace("updateClientMetricValues(): Requesting metrics from client: {}", clientId); + Object o = baguetteServer.readFromClient(clientId, "SHOW-STATS"); + log.trace("updateClientMetricValues(): Metrics from client: {}, metrics: {}", clientId, o); + if (o instanceof Map) { + clientMetrics.put(clientId, o); + } + } + log.debug("updateClientMetricValues(): client-metrics: {}", clientIds); + + synchronized (currentClientMetricsVersion) { + if (currentClientMetrics==null || (long)currentClientMetrics.get(".timestamp") < timestamp) { + long version = currentClientMetricsVersion.getAndIncrement(); + clientMetrics.put(".version", version); + clientMetrics.put(".timestamp", timestamp); + this.currentClientMetrics = clientMetrics; + } + } } } diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoProvider.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoProvider.java new file mode 100644 index 000000000..dea7e839c --- /dev/null +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoProvider.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2017-2022 Institute of Communication and Computer Systems (imu.iccs.gr) + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v2.0, unless + * Esper library is used, in which case it is subject to the terms of General Public License v2.0. + * If a copy of the MPL was not distributed with this file, you can obtain one at + * https://www.mozilla.org/en-US/MPL/2.0/ + */ + +package eu.melodic.event.control.info; + +import java.util.Map; + +public interface IEmsInfoProvider { + default void clearMetricValues() { } + + default Map getMetricValues() { return null; } + + default Map getMetricValuesFor(String key) { + return (Map) getMetricValues().get(key); + } +} diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoService.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoService.java index cf70110f0..044ab7b38 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoService.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/IEmsInfoService.java @@ -9,11 +9,13 @@ package eu.melodic.event.control.info; +import lombok.NonNull; + import java.util.Map; public interface IEmsInfoService { String SYSTEM_INFO_PROVIDER = "system-info"; - String EMS_INFO_PROVIDER = "ems-info"; + String BUILD_INFO_PROVIDER = "build-info"; String CONTROL_INFO_PROVIDER = "control"; String BROKER_CEP_INFO_PROVIDER = "broker-cep"; String BAGUETTE_SERVER_INFO_PROVIDER = "baguette-server"; @@ -21,6 +23,10 @@ public interface IEmsInfoService { String TRANSLATOR_INFO_PROVIDER = "translator"; String MISC_INFO_PROVIDER = "misc-info"; + void clearMetricValues(); + void clearClientMetricValues(); Map getMetricValues(); Map getMetricValuesFor(String key); + Map getClientMetricValues(); + Map getClientMetricValues(@NonNull String clientId); } diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/InfoServiceController.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/InfoServiceController.java index 1b53e65cb..6025a7939 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/info/InfoServiceController.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/InfoServiceController.java @@ -9,10 +9,14 @@ package eu.melodic.event.control.info; +import eu.melodic.event.control.properties.ControlServiceProperties; +import lombok.Data; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; import org.springframework.http.codec.ServerSentEvent; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -20,58 +24,90 @@ import reactor.core.publisher.Mono; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.QueryParam; import java.time.Duration; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; +import java.util.stream.Collectors; @Slf4j @RestController @RequiredArgsConstructor public class InfoServiceController { - private static final int DEFAULT_STREAM_INTERVAL = 30; // in seconds - private static final String EVENT_STREAM_NAME = "ems-metrics-event"; - + private final ControlServiceProperties properties; private final IEmsInfoService emsInfoService; @GetMapping("/info/metrics/get") - public Mono> metricsGet(HttpServletRequest request) { - log.info("metricsGet(): --- client: {}:{}, user: {}", - request.getRemoteAddr(), request.getRemotePort(), request.getRemoteUser()); - Map message = createMetricsResult(null, -1L); + public Mono> metricsGet( + @RequestParam(name="clients", required=false) List clientIds, HttpServletRequest request) { + log.info("metricsGet(): baguette-client-ids={} --- client: {}:{}", clientIds, request.getRemoteAddr(), request.getRemotePort()); + Map message = getMetricValues(clientIds); log.debug("metricsGet(): message={}", message); return Mono.just(message); } + public Map getMetricValues(List clientIds) { + return createMetricsResult(null, -1L, clientIds); + } + @GetMapping("/info/metrics/stream") - public Flux>> metricsStream(@QueryParam("interval") Optional interval, - HttpServletRequest request) + public Flux>> metricsStream( + @QueryParam("interval") Optional interval, + @RequestParam(name="clients", required=false) List clientIds, + HttpServletRequest request) { String sid = UUID.randomUUID().toString(); - log.info("metricsStream(): interval={} --- client: {}:{}, user: {}, Stream-Id: {}", - interval, request.getRemoteAddr(), request.getRemotePort(), request.getRemoteUser(), sid); + log.info("metricsStream(): interval={}, baguette-client-ids={} --- client: {}:{}, Stream-Id: {}", + interval, clientIds, request.getRemoteAddr(), request.getRemotePort(), sid); int intervalInSeconds = interval.orElse(-1); - if (intervalInSeconds<1) intervalInSeconds = DEFAULT_STREAM_INTERVAL; + if (intervalInSeconds<1) intervalInSeconds = properties.getMetricsStreamUpdateInterval(); log.debug("metricsStream(): effective-interval={}", intervalInSeconds); return Flux.interval(Duration.ofSeconds(intervalInSeconds)) .onBackpressureDrop() .map(sequence -> { - Map message = createMetricsResult(sid, sequence); + Map message = createMetricsResult(sid, sequence, clientIds); log.debug("metricsStream(): seq={}, id={}, message={}", sequence, sid, message); return ServerSentEvent.> builder() .id(String.valueOf(sequence)) - .event(EVENT_STREAM_NAME) + .event(properties.getMetricsStreamEventName()) .data(message) .build(); }); } - public Map createMetricsResult(String sid, long sequence) { + @GetMapping("/info/metrics/clear") + public String metricsClear( + @RequestParam(name="clients", required=false) List clientIds, + HttpServletRequest request) { + log.info("metricsClear(): baguette-client-ids={} --- client: {}:{}", + clientIds, request.getRemoteAddr(), request.getRemotePort()); + emsInfoService.clearMetricValues(); + emsInfoService.clearClientMetricValues(); + return "CLEARED"; + } + + public Map createMetricsResult(String sid, long sequence, List clientIds) { Map metrics = emsInfoService.getMetricValues(); + Map> clientMetrics = null; + if (clientIds!=null && clientIds.size()>0) { + clientMetrics = clientIds.stream() + .filter(StringUtils::isNotBlank) + .map(id -> new Pair<>(id, emsInfoService.getClientMetricValues(id))) + .filter(p -> p.getValue() != null) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); + metrics.put("client-metrics", clientMetrics); + } metrics.put(".stream-id", sid); metrics.put(".sequence", sequence); log.trace("createMetricsResult: {}", metrics); return metrics; } + + @Data + private static class Pair { + private final T key; + private final U value; + } } diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/info/SystemInfoProvider.java b/event-management/control-service/src/main/java/eu/melodic/event/control/info/SystemInfoProvider.java new file mode 100644 index 000000000..9d7b25e41 --- /dev/null +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/info/SystemInfoProvider.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2017-2022 Institute of Communication and Computer Systems (imu.iccs.gr) + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v2.0, unless + * Esper library is used, in which case it is subject to the terms of General Public License v2.0. + * If a copy of the MPL was not distributed with this file, you can obtain one at + * https://www.mozilla.org/en-US/MPL/2.0/ + */ + +package eu.melodic.event.control.info; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.lang.management.*; +import java.util.LinkedHashMap; +import java.util.Map; + +@Slf4j +@Service +@RequiredArgsConstructor +public class SystemInfoProvider implements IEmsInfoProvider { + + private final File root = new File("/"); + + @Override + public Map getMetricValues() { + Map sysInfo = new LinkedHashMap<>(); + sysInfo.put("jvm-memory-total", Runtime.getRuntime().totalMemory()); + sysInfo.put("jvm-memory-max", Runtime.getRuntime().freeMemory()); + sysInfo.put("jvm-memory-free", Runtime.getRuntime().maxMemory()); + + MemoryMXBean memBean = ManagementFactory.getMemoryMXBean() ; + String heapInfo = memBean.getHeapMemoryUsage().toString(); + String nonHeapInfo = memBean.getNonHeapMemoryUsage().toString(); + sysInfo.put("jvm-memory-heap", heapInfo); + sysInfo.put("jvm-memory-non-heap", nonHeapInfo); + + ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); + sysInfo.put("jvm-thread-count", threadBean.getThreadCount()); + sysInfo.put("jvm-thread-daemon-count", threadBean.getDaemonThreadCount()); + sysInfo.put("jvm-thread-peak-count", threadBean.getPeakThreadCount()); + sysInfo.put("jvm-thread-total-started-count", threadBean.getTotalStartedThreadCount()); + + RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); + long uptime = runtimeBean.getUptime() / 1000; + String vmInfo = String.format("%s, ver.%s, by %s", runtimeBean.getVmName(), runtimeBean.getVmVersion(), runtimeBean.getVmVendor()); + sysInfo.put("jvm-info", vmInfo); + sysInfo.put("jvm-uptime", uptime); + + OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); + String osInfo = String.format("OS %s, %s, v.%s, processors: %d, avg. load: %.02f", osBean.getName(), osBean.getArch(), osBean.getVersion(), + osBean.getAvailableProcessors(), osBean.getSystemLoadAverage()); + sysInfo.put("os-info", osInfo); + + sysInfo.put("os-disk-total", root.getTotalSpace()); + sysInfo.put("os-disk-free", root.getFreeSpace()); + sysInfo.put("os-disk-usable", root.getUsableSpace()); + + return sysInfo; + } +} diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/properties/ControlServiceProperties.java b/event-management/control-service/src/main/java/eu/melodic/event/control/properties/ControlServiceProperties.java index 32fc35571..513e7de8a 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/properties/ControlServiceProperties.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/properties/ControlServiceProperties.java @@ -19,6 +19,7 @@ import org.springframework.context.annotation.PropertySource; import org.springframework.validation.annotation.Validated; import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; @Data @Validated @@ -98,6 +99,15 @@ public class ControlServiceProperties { @Value("${password-encoder-class}") private String passwordEncoderClass; + @Value("${info.metrics.update.interval:1000}") @Min(1) + private long metricsUpdateInterval; + @Value("${info.client.metrics.update.interval:10000}") @Min(1) + private long metricsClientUpdateInterval; + @Value("${info.metrics.stream.update.interval:10}") @Min(1) + private int metricsStreamUpdateInterval; // in seconds + @Value("${info.metrics.stream.event.name:ems-metrics-event}") @NotBlank + private String metricsStreamEventName; + // control.ssl.** settings private KeystoreAndCertificateProperties ssl; } diff --git a/event-management/control-service/src/main/java/eu/melodic/event/control/util/TopicBeacon.java b/event-management/control-service/src/main/java/eu/melodic/event/control/util/TopicBeacon.java index 45261cc2f..0cdf6200c 100644 --- a/event-management/control-service/src/main/java/eu/melodic/event/control/util/TopicBeacon.java +++ b/event-management/control-service/src/main/java/eu/melodic/event/control/util/TopicBeacon.java @@ -32,9 +32,9 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; +@Slf4j @Service @EnableScheduling -@Slf4j public class TopicBeacon implements InitializingBean { // Topic Beacon settings @Value("${beacon.enable:true}") diff --git a/event-management/control-service/src/main/resources/public/index.html b/event-management/control-service/src/main/resources/public/index.html index 8b3f453e7..230f4a02a 100644 --- a/event-management/control-service/src/main/resources/public/index.html +++ b/event-management/control-service/src/main/resources/public/index.html @@ -350,10 +350,11 @@