From afbf506749542acbf668f7684405d26a7456551f Mon Sep 17 00:00:00 2001 From: Mark Nellemann Date: Sat, 1 May 2021 14:44:55 +0200 Subject: [PATCH] Testing plugin framework. --- agent/build.gradle | 20 +- .../java/org/sysmon/agent/Application.java | 81 ++++++- .../org/sysmon/agent/MetricProcessor.java | 26 --- .../java/org/sysmon/agent/MyRouteBuilder.java | 56 ----- .../org/sysmon/agent/SysmonPluginManager.java | 30 +++ .../agent/SysmonPluginStatusProvider.java | 57 +++++ .../java/org/sysmon/agent/beans/DiskBean.java | 206 ------------------ .../agent/beans/ProcessorBeanLinux.java | 188 ---------------- .../src/main/resources/application.properties | 45 ---- .../main/resources/simplelogger.properties | 6 + build.gradle | 14 ++ gradle.properties | 2 + plugins/.gitignore | 1 + plugins/build.gradle | 32 +++ plugins/sysmon-aix/build.gradle | 10 + plugins/sysmon-aix/gradle.properties | 6 + .../plugins/sysmon_aix/AixDiskExtension.java | 25 +++ .../sysmon/plugins/sysmon_aix/AixPlugin.java | 36 +++ .../sysmon_aix/AixProcessorExtension.java | 22 +- plugins/sysmon-linux/build.gradle | 10 + plugins/sysmon-linux/gradle.properties | 7 + .../sysmon_linux/LinuxDiskExtension.java | 96 ++++++++ .../plugins/sysmon_linux/LinuxDiskStat.java | 117 ++++++++++ .../sysmon_linux/LinuxMemoryExtension.java | 38 ++-- .../plugins/sysmon_linux/LinuxPlugin.java | 35 +++ .../sysmon_linux/LinuxProcessorExtension.java | 97 +++++++++ .../sysmon_linux/LinuxProcessorStat.java | 95 ++++++++ settings.gradle | 10 +- shared/build.gradle | 9 +- .../java/org/sysmon/shared/AixPlugin.java | 5 + .../java/org/sysmon/shared/MetricBean.java | 2 + .../org/sysmon/shared/MetricExtension.java | 11 + .../java/org/sysmon/shared/MetricResult.java | 2 +- .../java/org/sysmon/shared/SysmonPlugin.java | 24 ++ 34 files changed, 851 insertions(+), 570 deletions(-) delete mode 100644 agent/src/main/java/org/sysmon/agent/MetricProcessor.java delete mode 100644 agent/src/main/java/org/sysmon/agent/MyRouteBuilder.java create mode 100644 agent/src/main/java/org/sysmon/agent/SysmonPluginManager.java create mode 100644 agent/src/main/java/org/sysmon/agent/SysmonPluginStatusProvider.java delete mode 100644 agent/src/main/java/org/sysmon/agent/beans/DiskBean.java delete mode 100644 agent/src/main/java/org/sysmon/agent/beans/ProcessorBeanLinux.java delete mode 100644 agent/src/main/resources/application.properties create mode 100644 agent/src/main/resources/simplelogger.properties create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 plugins/.gitignore create mode 100644 plugins/build.gradle create mode 100644 plugins/sysmon-aix/build.gradle create mode 100644 plugins/sysmon-aix/gradle.properties create mode 100644 plugins/sysmon-aix/src/main/java/org/sysmon/plugins/sysmon_aix/AixDiskExtension.java create mode 100644 plugins/sysmon-aix/src/main/java/org/sysmon/plugins/sysmon_aix/AixPlugin.java rename agent/src/main/java/org/sysmon/agent/beans/ProcessorBeanAix.java => plugins/sysmon-aix/src/main/java/org/sysmon/plugins/sysmon_aix/AixProcessorExtension.java (86%) create mode 100644 plugins/sysmon-linux/build.gradle create mode 100644 plugins/sysmon-linux/gradle.properties create mode 100644 plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxDiskExtension.java create mode 100644 plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxDiskStat.java rename agent/src/main/java/org/sysmon/agent/beans/MemoryBean.java => plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxMemoryExtension.java (67%) create mode 100644 plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxPlugin.java create mode 100644 plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxProcessorExtension.java create mode 100644 plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxProcessorStat.java create mode 100644 shared/src/main/java/org/sysmon/shared/AixPlugin.java create mode 100644 shared/src/main/java/org/sysmon/shared/MetricExtension.java create mode 100644 shared/src/main/java/org/sysmon/shared/SysmonPlugin.java diff --git a/agent/build.gradle b/agent/build.gradle index f084856..8b245bb 100644 --- a/agent/build.gradle +++ b/agent/build.gradle @@ -20,25 +20,25 @@ dependencies { testImplementation 'org.codehaus.groovy:groovy:3.0.7' testImplementation 'org.spockframework:spock-core:2.0-M4-groovy-3.0' testImplementation 'junit:junit:4.13.1' - testImplementation 'org.slf4j:slf4j-api:1.7.30' + testImplementation "org.slf4j:slf4j-api:${slf4jVersion}" testImplementation project(':shared') implementation project(':shared') - implementation 'org.slf4j:slf4j-api:1.7.30' - implementation 'org.slf4j:slf4j-simple:1.7.30' + implementation "org.slf4j:slf4j-api:${slf4jVersion}" + implementation "org.slf4j:slf4j-simple:${slf4jVersion}" - // https://mvnrepository.com/artifact/org.apache.camel/camel-core - implementation group: 'org.apache.camel', name: 'camel-core', version: '3.7.3' - implementation group: 'org.apache.camel', name: 'camel-main', version: '3.7.3' - implementation group: 'org.apache.camel', name: 'camel-bean', version: '3.7.3' - implementation group: 'org.apache.camel', name: 'camel-timer', version: '3.7.3' - implementation group: 'org.apache.camel', name: 'camel-stream', version: '3.7.3' + annotationProcessor(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}") + implementation group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}" } application { // Define the main class for the application. - mainClass = 'org.sysmon.agent.Application' + mainClassName = 'org.sysmon.agent.Application' +} + +run { + systemProperty 'pf4j.pluginsDir', '../plugins/test/' } tasks.named('test') { diff --git a/agent/src/main/java/org/sysmon/agent/Application.java b/agent/src/main/java/org/sysmon/agent/Application.java index 949bf05..8339e9c 100644 --- a/agent/src/main/java/org/sysmon/agent/Application.java +++ b/agent/src/main/java/org/sysmon/agent/Application.java @@ -3,24 +3,83 @@ */ package org.sysmon.agent; -import org.apache.camel.main.Main; +import org.pf4j.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sysmon.shared.MetricExtension; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; public class Application { - public static void main(String[] args) { + private static final Logger log = LoggerFactory.getLogger(Application.class); - // use Camels Main class - Main main = new Main(); + public static void main(String[] args) throws InterruptedException { - // and add the routes (you can specify multiple classes) - main.configure().addRoutesBuilder(MyRouteBuilder.class); + // create the plugin manager + PluginManager pluginManager = new SysmonPluginManager(); // or "new ZipPluginManager() / new DefaultPluginManager()" - // now keep the application running until the JVM is terminated (ctrl + c or sigterm) - try { - main.run(args); - } catch(Exception e) { - System.err.println(e.getMessage()); + // start and load all plugins of application + pluginManager.loadPlugins(); + pluginManager.startPlugins(); + + /* + final PluginManager pluginManager = new SysmonPluginManager() { + + protected ExtensionFinder createExtensionFinder() { + DefaultExtensionFinder extensionFinder = (DefaultExtensionFinder) super.createExtensionFinder(); + extensionFinder.addServiceProviderExtensionFinder(); + return extensionFinder; + } + + }; + + pluginManager.loadPlugins(); + pluginManager.startPlugins(); +*/ + + /* + List plugins = pluginManager.getPlugins(); + for(PluginWrapper wrapper : plugins) { + log.info(">>> Plugin Description: " + wrapper.getDescriptor().getPluginDescription()); + } + */ + + List metricExtensions = pluginManager.getExtensions(MetricExtension.class); + log.info(String.format("Found %d extensions for extension point '%s':", metricExtensions.size(), MetricExtension.class.getName())); + for (MetricExtension plugin : metricExtensions) { + log.info(">>> " + plugin.getGreeting()); } + + AtomicBoolean keepRunning = new AtomicBoolean(true); + Thread shutdownHook = new Thread(() -> { + keepRunning.set(false); + pluginManager.stopPlugins(); + System.out.println("Stopping sysmon, please wait ..."); + }); + Runtime.getRuntime().addShutdownHook(shutdownHook); + + + /* + do { + + for (MetricExtension plugin : metricExtensions) { + + // TODO: Find better way to avoid using plugins not working on runtime OS. + + if(plugin.isSupported()) { + System.out.println(">>> " + plugin.getMetrics()); + } + } + + Thread.sleep(15000); + } while (keepRunning.get()); + */ + + } + + } diff --git a/agent/src/main/java/org/sysmon/agent/MetricProcessor.java b/agent/src/main/java/org/sysmon/agent/MetricProcessor.java deleted file mode 100644 index 069c9e2..0000000 --- a/agent/src/main/java/org/sysmon/agent/MetricProcessor.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.sysmon.agent; - -import org.apache.camel.Exchange; -import org.apache.camel.Processor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sysmon.shared.MetricResult; - -public class MetricProcessor implements Processor { - - private final static Logger log = LoggerFactory.getLogger(MetricProcessor.class); - - - public void process(Exchange exchange) throws Exception { - - MetricResult payload = exchange.getIn().getBody(MetricResult.class); - log.info(payload.toString()); - - // do something with the payload and/or exchange here - //exchange.getIn().setBody("Changed body"); - - // do something... - } - - -} diff --git a/agent/src/main/java/org/sysmon/agent/MyRouteBuilder.java b/agent/src/main/java/org/sysmon/agent/MyRouteBuilder.java deleted file mode 100644 index ec5fb61..0000000 --- a/agent/src/main/java/org/sysmon/agent/MyRouteBuilder.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.sysmon.agent; - -import org.apache.camel.builder.RouteBuilder; -import org.sysmon.agent.beans.ProcessorBeanAix; -import org.sysmon.agent.beans.ProcessorBeanLinux; - -public class MyRouteBuilder extends RouteBuilder { - - private static final String osName = System.getProperty("os.name").toLowerCase(); - - @Override - public void configure() throws Exception { - - - // TODO: Some smarter way to do this ? - - if(osName.contains("linux")) { - // Linux specific beans - from("timer:collect?period=5000") - .bean(new ProcessorBeanLinux(), "getMetrics") - .to("seda:metrics"); - - } else if(osName.contains("aix")) { - // AIX specific beans - from("timer:collect?period=5000") - .bean(new ProcessorBeanAix(), "getMetrics") - .to("seda:metrics"); - - } else { - // Unsupported OS - throw new UnsupportedOperationException("OS not implemented: " + osName); - } - - - - // TODO: Discover beans on classpath and setup accordingly ?? - - // Setup metrics measurement beans - from("timer:collect?period=5000") - .bean("memoryBean", "getMetrics") - .to("seda:metrics"); - - from("timer:collect?period=5000") - .bean("diskBean", "getMetrics") - .to("seda:metrics"); - - - // TODO: Somehow combine all results in a format suitable for sending to a central REST endpoint - - from("seda:metrics").process("metricProcessor"); - - - } - -} - diff --git a/agent/src/main/java/org/sysmon/agent/SysmonPluginManager.java b/agent/src/main/java/org/sysmon/agent/SysmonPluginManager.java new file mode 100644 index 0000000..83b85ed --- /dev/null +++ b/agent/src/main/java/org/sysmon/agent/SysmonPluginManager.java @@ -0,0 +1,30 @@ +package org.sysmon.agent; + +import org.pf4j.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SysmonPluginManager extends DefaultPluginManager { + + private static final Logger log = LoggerFactory.getLogger(SysmonPluginManager.class); + + + public SysmonPluginManager() { + super(); + log.warn("SysmonPluginManager()"); + } + + @Override + protected PluginStatusProvider createPluginStatusProvider() { + log.warn("createPluginStatusProvider()"); + return new SysmonPluginStatusProvider(); + } + + @Override + protected ExtensionFactory createExtensionFactory() { + log.warn("createExtensionFactory()"); + return new SingletonExtensionFactory(); + } + + +} diff --git a/agent/src/main/java/org/sysmon/agent/SysmonPluginStatusProvider.java b/agent/src/main/java/org/sysmon/agent/SysmonPluginStatusProvider.java new file mode 100644 index 0000000..83d4ae6 --- /dev/null +++ b/agent/src/main/java/org/sysmon/agent/SysmonPluginStatusProvider.java @@ -0,0 +1,57 @@ +package org.sysmon.agent; + +import org.pf4j.PluginStatusProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +public class SysmonPluginStatusProvider implements PluginStatusProvider { + + private static final Logger log = LoggerFactory.getLogger(SysmonPluginStatusProvider.class); + + private final List enabledPlugins = new ArrayList<>(); + private final List disabledPlugins = new ArrayList<>(); + + + public SysmonPluginStatusProvider() { + log.warn("SysmonPluginManager()"); + } + + + @Override + public boolean isPluginDisabled(String pluginId) { + log.warn("isPluginDisabled() - " + pluginId); + if (disabledPlugins.contains(pluginId)) { + return true; + } + + return !enabledPlugins.isEmpty() && !enabledPlugins.contains(pluginId); + } + + @Override + public void disablePlugin(String pluginId) { + + log.warn("disablePlugin() - " + pluginId); + + if (isPluginDisabled(pluginId)) { + // do nothing + return; + } + + } + + @Override + public void enablePlugin(String pluginId) { + + log.warn("enablePlugin() - " + pluginId); + + if (!isPluginDisabled(pluginId)) { + // do nothing + return; + } + + } + +} diff --git a/agent/src/main/java/org/sysmon/agent/beans/DiskBean.java b/agent/src/main/java/org/sysmon/agent/beans/DiskBean.java deleted file mode 100644 index c0f74bf..0000000 --- a/agent/src/main/java/org/sysmon/agent/beans/DiskBean.java +++ /dev/null @@ -1,206 +0,0 @@ -package org.sysmon.agent.beans; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; - -import org.apache.camel.spi.Configurer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sysmon.shared.MetricBean; -import org.sysmon.shared.MetricMeasurement; -import org.sysmon.shared.MetricResult; - -@Configurer -public class DiskBean implements MetricBean { - - private final static Logger log = LoggerFactory.getLogger(DiskBean.class); - - private List currentDiskStats; - private List previousDiskStats; - - - @Override - public MetricResult getMetrics() { - - MetricResult result = new MetricResult("disk"); - try { - copyCurrentValues(); - readProcFile(); - result.setMeasurementList(calculate()); - } catch (IOException e) { - e.printStackTrace(); - } - - return result; - } - - - - private void readProcFile() throws IOException { - - currentDiskStats = new ArrayList<>(); - List allLines = Files.readAllLines(Paths.get("/proc/diskstats"), StandardCharsets.UTF_8); - for(String line : allLines) { - currentDiskStats.add(new LinuxDiskStat(line)); - } - - } - - - private void copyCurrentValues() { - - if(currentDiskStats != null && currentDiskStats.size() > 0) { - previousDiskStats = new ArrayList<>(currentDiskStats); - } - - } - - - private List calculate() { - - List measurementList = new ArrayList<>(); - - if(previousDiskStats == null || previousDiskStats.size() != currentDiskStats.size()) { - return measurementList; - } - - - for(int i = 0; i < currentDiskStats.size(); i++) { - - LinuxDiskStat curStat = currentDiskStats.get(i); - LinuxDiskStat preStat = previousDiskStats.get(i); - - if(curStat.device.startsWith("loop")) { - continue; - } - - long timeSpendDoingIo = curStat.timeSpentOnIo - preStat.timeSpentOnIo; - - // TODO: Calculate differences for wanted disk io stats - measurementList.add(new MetricMeasurement(curStat.getDevice() + "-iotime", timeSpendDoingIo)); - - } - - return measurementList; - } - - - public static class LinuxDiskStat { - /* - == =================================== - 1 major number - 2 minor mumber - 3 device name - 4 reads completed successfully - 5 reads merged - 6 sectors read - 7 time spent reading (ms) - 8 writes completed - 9 writes merged - 10 sectors written - 11 time spent writing (ms) - 12 I/Os currently in progress - 13 time spent doing I/Os (ms) - 14 weighted time spent doing I/Os (ms) - == =================================== - - Kernel 4.18+ appends four more fields for discard - tracking putting the total at 18: - - == =================================== - 15 discards completed successfully - 16 discards merged - 17 sectors discarded - 18 time spent discarding - == =================================== - - Kernel 5.5+ appends two more fields for flush requests: - - == ===================================== - 19 flush requests completed successfully - 20 time spent flushing - == ===================================== - */ - - private final int major; - private final int minor; - private final String device; // device name - private final Long readsCompleted; // successfully - private final Long readsMerged; - private final Long sectorsRead; // 512 bytes pr. sector - private final Long timeSpentReading; // ms - private final Long writesCompleted; // successfully - private final Long writesMerged; - private final Long sectorsWritten; // 512 bytes pr. sector - private final Long timeSpentWriting; // ms - private final Long ioInProgress; - private final Long timeSpentOnIo; // ms - private final Long timeSpentOnIoWeighted; - - private final Long discardsCompleted; // successfully - private final Long discardsMerged; - private final Long sectorsDiscarded; // 512 bytes pr. sector - private final Long timeSpentDiscarding; // ms - - private final Long flushRequestsCompleted; - private final Long timeSpentFlushing; // ms - - - LinuxDiskStat(String procString) { - - String[] splitStr = procString.trim().split("\\s+"); - if(splitStr.length < 14) { - throw new UnsupportedOperationException("Linux proc DISK string error: " + procString); - } - - this.major = Integer.parseInt(splitStr[0]); - this.minor = Integer.parseInt(splitStr[1]); - this.device = splitStr[2]; - this.readsCompleted = Long.parseLong(splitStr[3]); - this.readsMerged = Long.parseLong(splitStr[4]); - this.sectorsRead = Long.parseLong(splitStr[5]); - this.timeSpentReading = Long.parseLong(splitStr[6]); - this.writesCompleted = Long.parseLong(splitStr[7]); - this.writesMerged = Long.parseLong(splitStr[8]); - this.sectorsWritten = Long.parseLong(splitStr[9]); - this.timeSpentWriting = Long.parseLong(splitStr[10]); - this.ioInProgress = Long.parseLong(splitStr[11]); - this.timeSpentOnIo = Long.parseLong(splitStr[12]); - this.timeSpentOnIoWeighted = Long.parseLong(splitStr[13]); - - if(splitStr.length >= 18) { - this.discardsCompleted = Long.parseLong(splitStr[10]); - this.discardsMerged = Long.parseLong(splitStr[11]); - this.sectorsDiscarded = Long.parseLong(splitStr[12]); - this.timeSpentDiscarding = Long.parseLong(splitStr[13]); - } else { - this.discardsCompleted = null; - this.discardsMerged = null; - this.sectorsDiscarded = null; - this.timeSpentDiscarding = null; - } - - if(splitStr.length == 20) { - this.flushRequestsCompleted = Long.parseLong(splitStr[14]); - this.timeSpentFlushing = Long.parseLong(splitStr[15]); - } else { - this.flushRequestsCompleted = null; - this.timeSpentFlushing = null; - } - - } - - public String getDevice() { - return device; - } - - - } - -} - - diff --git a/agent/src/main/java/org/sysmon/agent/beans/ProcessorBeanLinux.java b/agent/src/main/java/org/sysmon/agent/beans/ProcessorBeanLinux.java deleted file mode 100644 index a35c294..0000000 --- a/agent/src/main/java/org/sysmon/agent/beans/ProcessorBeanLinux.java +++ /dev/null @@ -1,188 +0,0 @@ -package org.sysmon.agent.beans; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; - -import org.apache.camel.spi.Configurer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sysmon.shared.MetricBean; -import org.sysmon.shared.MetricMeasurement; -import org.sysmon.shared.MetricResult; - -@Configurer -public class ProcessorBeanLinux implements MetricBean { - - private final static Logger log = LoggerFactory.getLogger(ProcessorBeanLinux.class); - - private List currentProcessorStats; - private List previousProcessorStats; - - - @Override - public MetricResult getMetrics() { - - MetricResult result = new MetricResult("processor"); - try { - copyCurrentValues(); - readProcFile(); - result.setMeasurementList(calculate()); - } catch (IOException e) { - e.printStackTrace(); - } - - return result; - } - - - private void readProcFile() throws IOException { - - currentProcessorStats = new ArrayList<>(); - List allLines = Files.readAllLines(Paths.get("/proc/stat"), StandardCharsets.UTF_8); - for(String line : allLines) { - if(line.startsWith("cpu")) { - log.debug(line); - currentProcessorStats.add(new LinuxProcessorStat(line)); - } - } - - } - - - private void copyCurrentValues() { - - if(currentProcessorStats != null && currentProcessorStats.size() > 0) { - previousProcessorStats = new ArrayList<>(currentProcessorStats); - } - - } - - - private List calculate() { - - List measurementList = new ArrayList<>(); - - if(previousProcessorStats == null || previousProcessorStats.size() != currentProcessorStats.size()) { - return measurementList; - } - - for(int i = 0; i < currentProcessorStats.size(); i++) { - - LinuxProcessorStat curStat = currentProcessorStats.get(i); - LinuxProcessorStat preStat = previousProcessorStats.get(i); - - long workTimeDiff = curStat.getCombinedTime() - preStat.getCombinedTime(); - long idleTimeDiff = curStat.getCombinedIdleTime() - preStat.getCombinedIdleTime(); - float percentUsage = (float) (workTimeDiff - idleTimeDiff) / workTimeDiff; - - Integer pct = (int) (percentUsage * 100); - measurementList.add(new MetricMeasurement(curStat.getCpuName(), pct)); - - } - - return measurementList; - - } - - - public static class LinuxProcessorStat { - - private final String cpuName; - private final Long userTime; - private final Long niceTime; - private final Long systemTime; - private final Long idleTime; - private final Long ioWaitTime; - private final Long irqTime; - private final Long softIrqTime; - private final Long stealTime; - private final Long guestTime; - private final Long guestNiceTime; - - - LinuxProcessorStat(String procString) { - - String[] splitStr = procString.trim().split("\\s+"); - if(splitStr.length != 11) { - throw new UnsupportedOperationException("Linux proc CPU string error: " + procString); - } - - this.cpuName = splitStr[0]; - this.userTime = Long.parseLong(splitStr[1]); - this.niceTime = Long.parseLong(splitStr[2]); - this.systemTime = Long.parseLong(splitStr[3]); - this.idleTime = Long.parseLong(splitStr[4]); - this.ioWaitTime = Long.parseLong(splitStr[5]); - this.irqTime = Long.parseLong(splitStr[6]); - this.softIrqTime = Long.parseLong(splitStr[7]); - this.stealTime = Long.parseLong(splitStr[8]); - this.guestTime = Long.parseLong(splitStr[9]); - this.guestNiceTime = Long.parseLong(splitStr[10]); - - } - - public String getCpuName() { - return cpuName; - } - - public Long getUserTime() { - return userTime; - } - - public Long getNiceTime() { - return niceTime; - } - - public Long getSystemTime() { - return systemTime; - } - - public Long getIdleTime() { - return idleTime; - } - - public Long getIoWaitTime() { - return ioWaitTime; - } - - public Long getIrqTime() { - return irqTime; - } - - public Long getSoftIrqTime() { - return softIrqTime; - } - - public Long getStealTime() { - return stealTime; - } - - public Long getGuestTime() { - return guestTime; - } - - public Long getGuestNiceTime() { - return guestNiceTime; - } - - public Long getCombinedIdleTime() { - return idleTime + ioWaitTime; - } - - public Long getCombinedWorkTime() { - return userTime + niceTime + systemTime + irqTime + softIrqTime + stealTime + guestTime + guestNiceTime; - } - - public Long getCombinedTime() { - return getCombinedIdleTime() + getCombinedWorkTime(); - } - - } - -} - - diff --git a/agent/src/main/resources/application.properties b/agent/src/main/resources/application.properties deleted file mode 100644 index bf2ff6c..0000000 --- a/agent/src/main/resources/application.properties +++ /dev/null @@ -1,45 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# to configure camel main -# here you can configure options on camel main (see MainConfigurationProperties class) -camel.main.name = SysMonAgent - -# enable tracing -### camel.main.tracing = true - -# bean introspection to log reflection based configuration -camel.main.beanIntrospectionExtendedStatistics=true -camel.main.beanIntrospectionLoggingLevel=INFO - -# run in lightweight mode to be tiny as possible -camel.main.lightweight = true -# and eager load classes -#camel.main.eager-classloading = true - -# use object pooling to reduce JVM garbage collection -#camel.main.exchange-factory = pooled -#camel.main.exchange-factory-statistics-enabled = true - -# can be used to not start the route -# camel.main.auto-startup = false - -# configure beans -camel.beans.metricProcessor = #class:org.sysmon.agent.MetricProcessor -camel.beans.diskBean = #class:org.sysmon.agent.beans.DiskBean -camel.beans.memoryBean = #class:org.sysmon.agent.beans.MemoryBean -#camel.beans.processorBean = #class:org.sysmon.agent.beans.ProcessorBean diff --git a/agent/src/main/resources/simplelogger.properties b/agent/src/main/resources/simplelogger.properties new file mode 100644 index 0000000..82fb15c --- /dev/null +++ b/agent/src/main/resources/simplelogger.properties @@ -0,0 +1,6 @@ +org.slf4j.simpleLogger.logFile=System.err +org.slf4j.simpleLogger.showDateTime=true +org.slf4j.simpleLogger.showShortLogName=true +org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss.SSS +org.slf4j.simpleLogger.levelInBrackets=true +org.slf4j.simpleLogger.defaultLogLevel=info diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..f41962c --- /dev/null +++ b/build.gradle @@ -0,0 +1,14 @@ +subprojects { + apply plugin: 'java' + + dependencies { + testImplementation project(':shared') + } + + repositories { + mavenLocal() + mavenCentral() + } +} + + diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..6b9bbe0 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,2 @@ +pf4jVersion=3.6.0 +slf4jVersion=1.7.30 diff --git a/plugins/.gitignore b/plugins/.gitignore new file mode 100644 index 0000000..30d74d2 --- /dev/null +++ b/plugins/.gitignore @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/plugins/build.gradle b/plugins/build.gradle new file mode 100644 index 0000000..333e3f4 --- /dev/null +++ b/plugins/build.gradle @@ -0,0 +1,32 @@ +subprojects { + apply plugin: 'java-library' + + jar { + manifest { + attributes( + 'Plugin-Id' : "${pluginId}", + 'Plugin-Class' : "${pluginClass}", + 'Plugin-Version' : "${pluginVersion}", + 'Plugin-Provider' : "${pluginProvider}", + 'Plugin-Description': "${pluginDescription}" + ) + } + } + + task copyJar(type: Copy, dependsOn:[jar]) { + from jar // here it automatically reads jar file produced from jar task + into "../test/" + } + + tasks.assemble.dependsOn { + copyJar + } + +} + +task customCleanUp(type:Delete) { + delete "test" + //delete files("${buildDir}/test/*.jar") +} + +tasks.clean.dependsOn(tasks.customCleanUp) \ No newline at end of file diff --git a/plugins/sysmon-aix/build.gradle b/plugins/sysmon-aix/build.gradle new file mode 100644 index 0000000..a3d951b --- /dev/null +++ b/plugins/sysmon-aix/build.gradle @@ -0,0 +1,10 @@ +dependencies { + // compileOnly important!!! We do not want to put the api into the zip file since the main program has it already! + implementation project(':shared') + implementation(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}") { + exclude(group: "org.slf4j") + } + annotationProcessor(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}") + implementation "org.slf4j:slf4j-api:${slf4jVersion}" + +} diff --git a/plugins/sysmon-aix/gradle.properties b/plugins/sysmon-aix/gradle.properties new file mode 100644 index 0000000..46a90ea --- /dev/null +++ b/plugins/sysmon-aix/gradle.properties @@ -0,0 +1,6 @@ +pluginId=sysmon-aix +pluginClass=org.sysmon.plugins.sysmon_aix.AixPlugin +pluginVersion=0.0.1 +pluginProvider=System Monitor +pluginDependencies= +pluginDescription=Collects AIX OS metrics. \ No newline at end of file diff --git a/plugins/sysmon-aix/src/main/java/org/sysmon/plugins/sysmon_aix/AixDiskExtension.java b/plugins/sysmon-aix/src/main/java/org/sysmon/plugins/sysmon_aix/AixDiskExtension.java new file mode 100644 index 0000000..fd766ac --- /dev/null +++ b/plugins/sysmon-aix/src/main/java/org/sysmon/plugins/sysmon_aix/AixDiskExtension.java @@ -0,0 +1,25 @@ +package org.sysmon.plugins.sysmon_aix; + +import org.pf4j.Extension; +import org.sysmon.shared.MetricExtension; +import org.sysmon.shared.MetricResult; + +@Extension +public class AixDiskExtension implements MetricExtension { + + @Override + public boolean isSupported() { + return System.getProperty("os.name").toLowerCase().contains("aix"); + } + + @Override + public String getGreeting() { + return "Welcome from AIX DiskMetric"; + } + + @Override + public MetricResult getMetrics() { + return null; + } + +} \ No newline at end of file diff --git a/plugins/sysmon-aix/src/main/java/org/sysmon/plugins/sysmon_aix/AixPlugin.java b/plugins/sysmon-aix/src/main/java/org/sysmon/plugins/sysmon_aix/AixPlugin.java new file mode 100644 index 0000000..a210e43 --- /dev/null +++ b/plugins/sysmon-aix/src/main/java/org/sysmon/plugins/sysmon_aix/AixPlugin.java @@ -0,0 +1,36 @@ +package org.sysmon.plugins.sysmon_aix; + +import org.pf4j.PluginState; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; + +public class AixPlugin extends Plugin { + + private static final Logger log = LoggerFactory.getLogger(AixPlugin.class); + + public AixPlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + if(!System.getProperty("os.name").toLowerCase().contains("aix")) { + log.warn("start() - Plugin not supported here."); + wrapper.setPluginState(PluginState.DISABLED); + wrapper.getPlugin().stop(); + } else { + log.info("start() - Good to go."); + } + } + + @Override + public void stop() { + log.debug("stop()"); + } + + +} + + diff --git a/agent/src/main/java/org/sysmon/agent/beans/ProcessorBeanAix.java b/plugins/sysmon-aix/src/main/java/org/sysmon/plugins/sysmon_aix/AixProcessorExtension.java similarity index 86% rename from agent/src/main/java/org/sysmon/agent/beans/ProcessorBeanAix.java rename to plugins/sysmon-aix/src/main/java/org/sysmon/plugins/sysmon_aix/AixProcessorExtension.java index c0f1ac7..091e4c3 100644 --- a/agent/src/main/java/org/sysmon/agent/beans/ProcessorBeanAix.java +++ b/plugins/sysmon-aix/src/main/java/org/sysmon/plugins/sysmon_aix/AixProcessorExtension.java @@ -1,24 +1,32 @@ -package org.sysmon.agent.beans; +package org.sysmon.plugins.sysmon_aix; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sysmon.shared.MetricBean; +import org.pf4j.Extension; +import org.sysmon.shared.MetricExtension; import org.sysmon.shared.MetricResult; -public class ProcessorBeanAix implements MetricBean { +@Extension +public class AixProcessorExtension implements MetricExtension { - private final static Logger log = LoggerFactory.getLogger(ProcessorBeanAix.class); + @Override + public boolean isSupported() { + return System.getProperty("os.name").toLowerCase().contains("aix"); + } + @Override + public String getGreeting() { + return "Welcome from AIX ProcessorMetric"; + } @Override public MetricResult getMetrics() { - log.warn("TODO: AIX processor stat."); return null; } } + + /* diff --git a/plugins/sysmon-linux/build.gradle b/plugins/sysmon-linux/build.gradle new file mode 100644 index 0000000..a3d951b --- /dev/null +++ b/plugins/sysmon-linux/build.gradle @@ -0,0 +1,10 @@ +dependencies { + // compileOnly important!!! We do not want to put the api into the zip file since the main program has it already! + implementation project(':shared') + implementation(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}") { + exclude(group: "org.slf4j") + } + annotationProcessor(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}") + implementation "org.slf4j:slf4j-api:${slf4jVersion}" + +} diff --git a/plugins/sysmon-linux/gradle.properties b/plugins/sysmon-linux/gradle.properties new file mode 100644 index 0000000..8889e50 --- /dev/null +++ b/plugins/sysmon-linux/gradle.properties @@ -0,0 +1,7 @@ +pluginId=sysmon-linux +pluginClass=org.sysmon.plugins.sysmon_linux.LinuxPlugin +pluginVersion=0.0.1 +pluginProvider=System Monitor +pluginDependencies= +pluginDescription=Collects Linux OS metrics. + diff --git a/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxDiskExtension.java b/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxDiskExtension.java new file mode 100644 index 0000000..acdb55f --- /dev/null +++ b/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxDiskExtension.java @@ -0,0 +1,96 @@ +package org.sysmon.plugins.sysmon_linux; + +import org.pf4j.Extension; +import org.sysmon.shared.MetricExtension; +import org.sysmon.shared.MetricMeasurement; +import org.sysmon.shared.MetricResult; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +@Extension +public class LinuxDiskExtension implements MetricExtension { + + private List currentDiskStats; + private List previousDiskStats; + + @Override + public boolean isSupported() { + return System.getProperty("os.name").toLowerCase().contains("linux"); + } + + @Override + public String getGreeting() { + return "Welcome from Linux DiskMetric"; + } + + @Override + public MetricResult getMetrics() { + + MetricResult result = new MetricResult("disk"); + try { + copyCurrentValues(); + readProcFile(); + result.setMeasurementList(calculate()); + } catch (IOException e) { + e.printStackTrace(); + } + + return result; + } + + + + private void readProcFile() throws IOException { + + currentDiskStats = new ArrayList<>(); + List allLines = Files.readAllLines(Paths.get("/proc/diskstats"), StandardCharsets.UTF_8); + for(String line : allLines) { + currentDiskStats.add(new LinuxDiskStat(line)); + } + + } + + + private void copyCurrentValues() { + + if(currentDiskStats != null && currentDiskStats.size() > 0) { + previousDiskStats = new ArrayList<>(currentDiskStats); + } + + } + + + private List calculate() { + + List measurementList = new ArrayList<>(); + + if(previousDiskStats == null || previousDiskStats.size() != currentDiskStats.size()) { + return measurementList; + } + + + for(int i = 0; i < currentDiskStats.size(); i++) { + + LinuxDiskStat curStat = currentDiskStats.get(i); + LinuxDiskStat preStat = previousDiskStats.get(i); + + if(curStat.getDevice().startsWith("loop")) { + continue; + } + + long timeSpendDoingIo = curStat.getTimeSpentOnIo() - preStat.getTimeSpentOnIo(); + + // TODO: Calculate differences for wanted disk io stats + measurementList.add(new MetricMeasurement(curStat.getDevice() + "-iotime", timeSpendDoingIo)); + + } + + return measurementList; + } + +} diff --git a/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxDiskStat.java b/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxDiskStat.java new file mode 100644 index 0000000..4c5d2ab --- /dev/null +++ b/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxDiskStat.java @@ -0,0 +1,117 @@ +package org.sysmon.plugins.sysmon_linux; + +public class LinuxDiskStat { + /* + == =================================== + 1 major number + 2 minor mumber + 3 device name + 4 reads completed successfully + 5 reads merged + 6 sectors read + 7 time spent reading (ms) + 8 writes completed + 9 writes merged + 10 sectors written + 11 time spent writing (ms) + 12 I/Os currently in progress + 13 time spent doing I/Os (ms) + 14 weighted time spent doing I/Os (ms) + == =================================== + + Kernel 4.18+ appends four more fields for discard + tracking putting the total at 18: + + == =================================== + 15 discards completed successfully + 16 discards merged + 17 sectors discarded + 18 time spent discarding + == =================================== + + Kernel 5.5+ appends two more fields for flush requests: + + == ===================================== + 19 flush requests completed successfully + 20 time spent flushing + == ===================================== + */ + + private final int major; + private final int minor; + private final String device; // device name + private final Long readsCompleted; // successfully + private final Long readsMerged; + private final Long sectorsRead; // 512 bytes pr. sector + private final Long timeSpentReading; // ms + private final Long writesCompleted; // successfully + private final Long writesMerged; + private final Long sectorsWritten; // 512 bytes pr. sector + private final Long timeSpentWriting; // ms + private final Long ioInProgress; + private final Long timeSpentOnIo; // ms + private final Long timeSpentOnIoWeighted; + + private final Long discardsCompleted; // successfully + private final Long discardsMerged; + private final Long sectorsDiscarded; // 512 bytes pr. sector + private final Long timeSpentDiscarding; // ms + + private final Long flushRequestsCompleted; + private final Long timeSpentFlushing; // ms + + + LinuxDiskStat(String procString) { + + String[] splitStr = procString.trim().split("\\s+"); + if(splitStr.length < 14) { + throw new UnsupportedOperationException("Linux proc DISK string error: " + procString); + } + + this.major = Integer.parseInt(splitStr[0]); + this.minor = Integer.parseInt(splitStr[1]); + this.device = splitStr[2]; + this.readsCompleted = Long.parseLong(splitStr[3]); + this.readsMerged = Long.parseLong(splitStr[4]); + this.sectorsRead = Long.parseLong(splitStr[5]); + this.timeSpentReading = Long.parseLong(splitStr[6]); + this.writesCompleted = Long.parseLong(splitStr[7]); + this.writesMerged = Long.parseLong(splitStr[8]); + this.sectorsWritten = Long.parseLong(splitStr[9]); + this.timeSpentWriting = Long.parseLong(splitStr[10]); + this.ioInProgress = Long.parseLong(splitStr[11]); + this.timeSpentOnIo = Long.parseLong(splitStr[12]); + this.timeSpentOnIoWeighted = Long.parseLong(splitStr[13]); + + if(splitStr.length >= 18) { + this.discardsCompleted = Long.parseLong(splitStr[10]); + this.discardsMerged = Long.parseLong(splitStr[11]); + this.sectorsDiscarded = Long.parseLong(splitStr[12]); + this.timeSpentDiscarding = Long.parseLong(splitStr[13]); + } else { + this.discardsCompleted = null; + this.discardsMerged = null; + this.sectorsDiscarded = null; + this.timeSpentDiscarding = null; + } + + if(splitStr.length == 20) { + this.flushRequestsCompleted = Long.parseLong(splitStr[14]); + this.timeSpentFlushing = Long.parseLong(splitStr[15]); + } else { + this.flushRequestsCompleted = null; + this.timeSpentFlushing = null; + } + + } + + public String getDevice() { + return device; + } + + public Long getTimeSpentOnIo() { + return timeSpentOnIo; + } + + +} \ No newline at end of file diff --git a/agent/src/main/java/org/sysmon/agent/beans/MemoryBean.java b/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxMemoryExtension.java similarity index 67% rename from agent/src/main/java/org/sysmon/agent/beans/MemoryBean.java rename to plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxMemoryExtension.java index ec17c3e..47d6617 100644 --- a/agent/src/main/java/org/sysmon/agent/beans/MemoryBean.java +++ b/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxMemoryExtension.java @@ -1,4 +1,9 @@ -package org.sysmon.agent.beans; +package org.sysmon.plugins.sysmon_linux; + +import org.pf4j.Extension; +import org.sysmon.shared.MetricExtension; +import org.sysmon.shared.MetricMeasurement; +import org.sysmon.shared.MetricResult; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -9,23 +14,25 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.camel.spi.Configurer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sysmon.shared.MetricBean; -import org.sysmon.shared.MetricMeasurement; -import org.sysmon.shared.MetricResult; +@Extension +public class LinuxMemoryExtension implements MetricExtension { -@Configurer -public class MemoryBean implements MetricBean { - - private final static Logger log = LoggerFactory.getLogger(MemoryBean.class); private final Pattern pattern = Pattern.compile("^([a-zA-Z]+):\\s+(\\d+)\\s+"); + @Override + public boolean isSupported() { + return System.getProperty("os.name").toLowerCase().contains("linux"); + } + + @Override + public String getGreeting() { + return "Welcome from Linux MemoryMetric"; + } + @Override public MetricResult getMetrics() { - + MetricResult result = new MetricResult("memory"); try { result.setMeasurementList(readProcFile()); @@ -37,17 +44,16 @@ public class MemoryBean implements MetricBean { } - private List readProcFile() throws IOException { List measurementList = new ArrayList<>(); List allLines = Files.readAllLines(Paths.get("/proc/meminfo"), StandardCharsets.UTF_8); - for(String line : allLines) { + for (String line : allLines) { - if(line.startsWith("Mem")) { + if (line.startsWith("Mem")) { Matcher matcher = pattern.matcher(line); - if(matcher.find() && matcher.groupCount() == 2) { + if (matcher.find() && matcher.groupCount() == 2) { measurementList.add(new MetricMeasurement(matcher.group(1), matcher.group(2))); } } diff --git a/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxPlugin.java b/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxPlugin.java new file mode 100644 index 0000000..ef2139d --- /dev/null +++ b/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxPlugin.java @@ -0,0 +1,35 @@ +package org.sysmon.plugins.sysmon_linux; + +import org.pf4j.PluginState; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; + + +public class LinuxPlugin extends Plugin { + + private static final Logger log = LoggerFactory.getLogger(LinuxPlugin.class); + + public LinuxPlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + if(!System.getProperty("os.name").toLowerCase().contains("linux")) { + log.warn("start() - Plugin not supported here."); + wrapper.setPluginState(PluginState.DISABLED); + } else { + log.info("start() - Good to go."); + } + } + + @Override + public void stop() { + log.debug("stop()"); + } + + + +} diff --git a/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxProcessorExtension.java b/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxProcessorExtension.java new file mode 100644 index 0000000..12477d5 --- /dev/null +++ b/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxProcessorExtension.java @@ -0,0 +1,97 @@ +package org.sysmon.plugins.sysmon_linux; + + +import org.pf4j.Extension; +import org.sysmon.shared.MetricExtension; +import org.sysmon.shared.MetricMeasurement; +import org.sysmon.shared.MetricResult; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +@Extension +public class LinuxProcessorExtension implements MetricExtension { + + private List currentProcessorStats; + private List previousProcessorStats; + + @Override + public boolean isSupported() { + return System.getProperty("os.name").toLowerCase().contains("linux"); + } + + @Override + public String getGreeting() { + return "Welcome from Linux ProcessorMetric"; + } + + @Override + public MetricResult getMetrics() { + + MetricResult result = new MetricResult("processor"); + try { + copyCurrentValues(); + readProcFile(); + result.setMeasurementList(calculate()); + } catch (IOException e) { + e.printStackTrace(); + } + + return result; + } + + + private void readProcFile() throws IOException { + + currentProcessorStats = new ArrayList<>(); + List allLines = Files.readAllLines(Paths.get("/proc/stat"), StandardCharsets.UTF_8); + for(String line : allLines) { + if(line.startsWith("cpu")) { + currentProcessorStats.add(new LinuxProcessorStat(line)); + } + } + + } + + + private void copyCurrentValues() { + + if(currentProcessorStats != null && currentProcessorStats.size() > 0) { + previousProcessorStats = new ArrayList<>(currentProcessorStats); + } + + } + + + private List calculate() { + + List measurementList = new ArrayList<>(); + + if(previousProcessorStats == null || previousProcessorStats.size() != currentProcessorStats.size()) { + return measurementList; + } + + for(int i = 0; i < currentProcessorStats.size(); i++) { + + LinuxProcessorStat curStat = currentProcessorStats.get(i); + LinuxProcessorStat preStat = previousProcessorStats.get(i); + + long workTimeDiff = curStat.getCombinedTime() - preStat.getCombinedTime(); + long idleTimeDiff = curStat.getCombinedIdleTime() - preStat.getCombinedIdleTime(); + float percentUsage = (float) (workTimeDiff - idleTimeDiff) / workTimeDiff; + + Integer pct = (int) (percentUsage * 100); + measurementList.add(new MetricMeasurement(curStat.getCpuName(), pct)); + + } + + return measurementList; + + } +} + + diff --git a/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxProcessorStat.java b/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxProcessorStat.java new file mode 100644 index 0000000..2ef5742 --- /dev/null +++ b/plugins/sysmon-linux/src/main/java/org/sysmon/plugins/sysmon_linux/LinuxProcessorStat.java @@ -0,0 +1,95 @@ +package org.sysmon.plugins.sysmon_linux; + +public class LinuxProcessorStat { + + private final String cpuName; + private final Long userTime; + private final Long niceTime; + private final Long systemTime; + private final Long idleTime; + private final Long ioWaitTime; + private final Long irqTime; + private final Long softIrqTime; + private final Long stealTime; + private final Long guestTime; + private final Long guestNiceTime; + + + LinuxProcessorStat(String procString) { + + String[] splitStr = procString.trim().split("\\s+"); + if(splitStr.length != 11) { + throw new UnsupportedOperationException("Linux proc CPU string error: " + procString); + } + + this.cpuName = splitStr[0]; + this.userTime = Long.parseLong(splitStr[1]); + this.niceTime = Long.parseLong(splitStr[2]); + this.systemTime = Long.parseLong(splitStr[3]); + this.idleTime = Long.parseLong(splitStr[4]); + this.ioWaitTime = Long.parseLong(splitStr[5]); + this.irqTime = Long.parseLong(splitStr[6]); + this.softIrqTime = Long.parseLong(splitStr[7]); + this.stealTime = Long.parseLong(splitStr[8]); + this.guestTime = Long.parseLong(splitStr[9]); + this.guestNiceTime = Long.parseLong(splitStr[10]); + + } + + public String getCpuName() { + return cpuName; + } + + public Long getUserTime() { + return userTime; + } + + public Long getNiceTime() { + return niceTime; + } + + public Long getSystemTime() { + return systemTime; + } + + public Long getIdleTime() { + return idleTime; + } + + public Long getIoWaitTime() { + return ioWaitTime; + } + + public Long getIrqTime() { + return irqTime; + } + + public Long getSoftIrqTime() { + return softIrqTime; + } + + public Long getStealTime() { + return stealTime; + } + + public Long getGuestTime() { + return guestTime; + } + + public Long getGuestNiceTime() { + return guestNiceTime; + } + + public Long getCombinedIdleTime() { + return idleTime + ioWaitTime; + } + + public Long getCombinedWorkTime() { + return userTime + niceTime + systemTime + irqTime + softIrqTime + stealTime + guestTime + guestNiceTime; + } + + public Long getCombinedTime() { + return getCombinedIdleTime() + getCombinedWorkTime(); + } + +} diff --git a/settings.gradle b/settings.gradle index 20c03b4..7523a79 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,4 +8,12 @@ */ rootProject.name = 'sysmon' -include('shared', 'agent') +include('shared', 'agent', 'plugins') + +new File(rootDir, "plugins").listFiles().each { + + if (it.directory && new File(it, 'build.gradle').exists()) { + include ":plugins:${it.name}" + } + +} \ No newline at end of file diff --git a/shared/build.gradle b/shared/build.gradle index 8e35184..936de1d 100644 --- a/shared/build.gradle +++ b/shared/build.gradle @@ -20,10 +20,13 @@ dependencies { testImplementation 'org.codehaus.groovy:groovy:3.0.7' testImplementation 'org.spockframework:spock-core:2.0-M4-groovy-3.0' testImplementation 'junit:junit:4.13.1' - testImplementation 'org.slf4j:slf4j-api:1.7.30' + testImplementation "org.slf4j:slf4j-api:${slf4jVersion}" - implementation 'org.slf4j:slf4j-api:1.7.30' - implementation 'org.slf4j:slf4j-simple:1.7.30' + implementation "org.slf4j:slf4j-api:${slf4jVersion}" + implementation "org.slf4j:slf4j-simple:${slf4jVersion}" + + //annotationProcessor(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}") + implementation group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}" } diff --git a/shared/src/main/java/org/sysmon/shared/AixPlugin.java b/shared/src/main/java/org/sysmon/shared/AixPlugin.java new file mode 100644 index 0000000..5562dbd --- /dev/null +++ b/shared/src/main/java/org/sysmon/shared/AixPlugin.java @@ -0,0 +1,5 @@ +package org.sysmon.shared; + +public interface AixPlugin { + +} diff --git a/shared/src/main/java/org/sysmon/shared/MetricBean.java b/shared/src/main/java/org/sysmon/shared/MetricBean.java index 3ffe2e4..b51c8e3 100644 --- a/shared/src/main/java/org/sysmon/shared/MetricBean.java +++ b/shared/src/main/java/org/sysmon/shared/MetricBean.java @@ -1,5 +1,7 @@ package org.sysmon.shared; +import java.util.concurrent.Callable; + public interface MetricBean { public MetricResult getMetrics(); diff --git a/shared/src/main/java/org/sysmon/shared/MetricExtension.java b/shared/src/main/java/org/sysmon/shared/MetricExtension.java new file mode 100644 index 0000000..47b3d3f --- /dev/null +++ b/shared/src/main/java/org/sysmon/shared/MetricExtension.java @@ -0,0 +1,11 @@ +package org.sysmon.shared; + +import org.pf4j.ExtensionPoint; + +public interface MetricExtension extends ExtensionPoint { + + boolean isSupported(); + String getGreeting(); + MetricResult getMetrics(); + +} diff --git a/shared/src/main/java/org/sysmon/shared/MetricResult.java b/shared/src/main/java/org/sysmon/shared/MetricResult.java index 881b534..d2abdf3 100644 --- a/shared/src/main/java/org/sysmon/shared/MetricResult.java +++ b/shared/src/main/java/org/sysmon/shared/MetricResult.java @@ -20,7 +20,7 @@ public class MetricResult { public String toString() { - StringBuilder sb = new StringBuilder(name).append("\n"); + StringBuilder sb = new StringBuilder(String.format("%s - %s\n", timestamp.toString(), name)); for(MetricMeasurement mm : measurementList) { sb.append(mm.toString()).append("\n"); } diff --git a/shared/src/main/java/org/sysmon/shared/SysmonPlugin.java b/shared/src/main/java/org/sysmon/shared/SysmonPlugin.java new file mode 100644 index 0000000..9603038 --- /dev/null +++ b/shared/src/main/java/org/sysmon/shared/SysmonPlugin.java @@ -0,0 +1,24 @@ +package org.sysmon.shared; + +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SysmonPlugin extends Plugin { + + private static final Logger log = LoggerFactory.getLogger(SysmonPlugin.class); + + public SysmonPlugin(PluginWrapper wrapper) { + super(wrapper); + log.warn("SysmonPlugin"); + } + + @Override + public void start() { + log.warn("start();"); + } + + + +}