More work on packages, plugins and tests.

This commit is contained in:
Mark Nellemann 2021-05-11 15:37:23 +02:00
parent 088d49c90c
commit bc43d687a0
22 changed files with 330 additions and 58 deletions

View file

@ -1,15 +1,14 @@
plugins { plugins {
id 'application' id 'application'
id "com.github.johnrengelman.shadow" version "6.1.0" id "com.github.johnrengelman.shadow" version "7.0.0"
id "net.nemerosa.versioning" version "2.14.0" id "net.nemerosa.versioning" version "2.14.0"
id "nebula.ospackage" version "8.4.1" id "nebula.ospackage" version "8.5.6"
} }
dependencies { dependencies {
testImplementation project(':shared') testImplementation project(':shared')
implementation project(':shared') implementation project(':shared')
implementation project(':plugins')
annotationProcessor(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}") annotationProcessor(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}")
implementation group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}" implementation group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}"
@ -48,7 +47,7 @@ ospackage {
user = 'root' user = 'root'
packager = "Mark Nellemann <mark.nellemann@gmail.com>" packager = "Mark Nellemann <mark.nellemann@gmail.com>"
into '/opt/sysmon-client' into '/opt/sysmon/client'
from(shadowJar.outputs.files) { from(shadowJar.outputs.files) {
into 'lib' into 'lib'
@ -90,3 +89,10 @@ jar {
) )
} }
} }
shadowJar {
archiveBaseName.set('sysmon-client')
archiveClassifier.set('')
archiveVersion.set('')
mergeServiceFiles() // Tell plugin to merge duplicate service files
}

View file

@ -8,10 +8,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import picocli.CommandLine; import picocli.CommandLine;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.URL; import java.net.URL;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Properties;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
@CommandLine.Command(name = "sysmon-client", mixinStandardHelpOptions = true) @CommandLine.Command(name = "sysmon-client", mixinStandardHelpOptions = true)
@ -22,9 +24,11 @@ public class Application implements Callable<Integer> {
@CommandLine.Option(names = { "-s", "--server-url" }, description = "Server URL (default: ${DEFAULT-VALUE}).", defaultValue = "http://127.0.0.1:9925/metrics", paramLabel = "<url>") @CommandLine.Option(names = { "-s", "--server-url" }, description = "Server URL (default: ${DEFAULT-VALUE}).", defaultValue = "http://127.0.0.1:9925/metrics", paramLabel = "<url>")
private URL serverUrl; private URL serverUrl;
@CommandLine.Option(names = { "-n", "--hostname" }, description = "Client hostname.", paramLabel = "<name>") @CommandLine.Option(names = { "-n", "--hostname" }, description = "Client hostname (default: <hostname>).", paramLabel = "<name>")
private String hostname; private String hostname;
@CommandLine.Option(names = { "-p", "--plugins" }, description = "Plugin jar path (default: ${DEFAULT-VALUE}).", paramLabel = "<path>", defaultValue = "/opt/sysmon/plugins")
private File plugins;
public static void main(String... args) { public static void main(String... args) {
int exitCode = new CommandLine(new Application()).execute(args); int exitCode = new CommandLine(new Application()).execute(args);

View file

@ -11,7 +11,11 @@ import org.slf4j.LoggerFactory;
import org.sysmon.shared.MetricExtension; import org.sysmon.shared.MetricExtension;
import org.sysmon.shared.MetricResult; import org.sysmon.shared.MetricResult;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Properties;
public class ClientRouteBuilder extends RouteBuilder { public class ClientRouteBuilder extends RouteBuilder {
@ -22,17 +26,29 @@ public class ClientRouteBuilder extends RouteBuilder {
Registry registry = getContext().getRegistry(); Registry registry = getContext().getRegistry();
PluginManager pluginManager = new JarPluginManager(); Path[] pluginpaths = { new File("/opt/sysmon/plugins").toPath() };
PluginManager pluginManager = new JarPluginManager(pluginpaths);
pluginManager.loadPlugins(); pluginManager.loadPlugins();
pluginManager.startPlugins(); pluginManager.startPlugins();
List<String> providers = new ArrayList<>();
List<MetricExtension> metricExtensions = pluginManager.getExtensions(MetricExtension.class); List<MetricExtension> metricExtensions = pluginManager.getExtensions(MetricExtension.class);
for (MetricExtension ext : metricExtensions) { for (MetricExtension ext : metricExtensions) {
if(ext.isSupported()) { if(ext.isSupported()) {
String provides = ext.getProvides();
if(providers.contains(provides)) {
log.warn("Skipping extension (already provided): " + ext.getName());
continue;
}
log.info(">>> Enabling extension: " + ext.getDescription()); log.info(">>> Enabling extension: " + ext.getDescription());
providers.add(provides);
// Setup Camel route for this extension // Setup Camel route for this extension
from("timer:collect?period=30000") from("timer:collect?fixedRate=true&period=30s")
.bean(ext, "getMetrics") .bean(ext, "getMetrics")
//.doTry() //.doTry()
.process(new MetricEnrichProcessor(registry)) .process(new MetricEnrichProcessor(registry))

View file

@ -1,4 +1,7 @@
group=org.sysmon
version=0.0.1-SNAPSHOT
pf4jVersion=3.6.0 pf4jVersion=3.6.0
slf4jVersion=1.7.30 slf4jVersion=1.7.30
camelVersion=3.7.3 camelVersion=3.7.4
picocliVersion=4.6.1 picocliVersion=4.6.1

View file

@ -1,3 +1,7 @@
plugins {
id "nebula.ospackage" version "8.5.6"
}
subprojects { subprojects {
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'groovy' apply plugin: 'groovy'
@ -50,3 +54,28 @@ task customCleanUp(type:Delete) {
} }
tasks.clean.dependsOn(tasks.customCleanUp) tasks.clean.dependsOn(tasks.customCleanUp)
apply plugin: 'nebula.ospackage'
ospackage {
packageName = 'sysmon-plugins'
release = '1'
user = 'root'
packager = "Mark Nellemann <mark.nellemann@gmail.com>"
into '/opt/sysmon/plugins'
from('output/') {
into ''
}
}
buildRpm {
dependsOn assemble
os = "LINUX"
}
buildDeb {
dependsOn assemble
}

View file

@ -17,6 +17,11 @@ public class AixDiskExtension implements MetricExtension {
return "aix-disk"; return "aix-disk";
} }
@Override
public String getProvides() {
return "disk";
}
@Override @Override
public String getDescription() { public String getDescription() {
return "AIX Disk Metrics (TODO)"; return "AIX Disk Metrics (TODO)";

View file

@ -8,7 +8,7 @@ import org.sysmon.shared.MetricExtension;
import org.sysmon.shared.MetricResult; import org.sysmon.shared.MetricResult;
import org.sysmon.shared.PluginHelper; import org.sysmon.shared.PluginHelper;
import java.util.HashMap; import java.io.File;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -19,7 +19,19 @@ public class AixProcessorExtension implements MetricExtension {
@Override @Override
public boolean isSupported() { public boolean isSupported() {
return System.getProperty("os.name").toLowerCase().contains("aix");
String osArch = System.getProperty("os.arch").toLowerCase();
if(!osArch.startsWith("ppc64")) {
log.warn("Wrong os arch: " + osArch);
return false;
}
if(!PluginHelper.canExecute("lparstat")) {
log.warn("No lparstat command found.");
return false;
}
return true;
} }
@Override @Override
@ -27,6 +39,11 @@ public class AixProcessorExtension implements MetricExtension {
return "aix-processor"; return "aix-processor";
} }
@Override
public String getProvides() {
return "processor";
}
@Override @Override
public String getDescription() { public String getDescription() {
return "AIX Processor Metrics"; return "AIX Processor Metrics";
@ -35,7 +52,7 @@ public class AixProcessorExtension implements MetricExtension {
@Override @Override
public MetricResult getMetrics() { public MetricResult getMetrics() {
List<String> vmstat = PluginHelper.executeCommand("/usr/bin/lparstat 1 1"); List<String> vmstat = PluginHelper.executeCommand("lparstat 1 1");
AixProcessorStat processorStat = processCommandOutput(vmstat); AixProcessorStat processorStat = processCommandOutput(vmstat);
Map<String, String> tagsMap = processorStat.getTags(); Map<String, String> tagsMap = processorStat.getTags();

View file

@ -13,7 +13,12 @@ public class AixProcessorStat {
private static final Logger log = LoggerFactory.getLogger(AixProcessorStat.class); private static final Logger log = LoggerFactory.getLogger(AixProcessorStat.class);
private final Pattern pattern = Pattern.compile("^System configuration: type=(\\S+) mode=(\\S+) smt=(\\d+) lcpu=(\\d+) mem=(\\d+)MB psize=(\\d+) ent=(\\d+\\.?\\d*)"); // System configuration: type=Shared mode=Uncapped smt=8 lcpu=8 mem=4096MB psize=19 ent=0.50
private final Pattern patternAix = Pattern.compile("^System configuration: type=(\\S+) mode=(\\S+) smt=(\\d+) lcpu=(\\d+) mem=(\\d+)MB psize=(\\d+) ent=(\\d+\\.?\\d*)");
// type=Shared mode=Uncapped smt=8 lcpu=4 mem=4101120 kB cpus=24 ent=4.00
private final Pattern patternLinux = Pattern.compile("^type=(\\S+) mode=(\\S+) smt=(\\d+) lcpu=(\\d+) mem=(\\d+) kB cpus=(\\d+) ent=(\\d+\\.?\\d*)");
private String type; private String type;
private String mode; private String mode;
@ -31,34 +36,44 @@ public class AixProcessorStat {
private final Float lbusy; // Indicates the percentage of logical processor(s) utilization that occurred while executing at the user and system level. private final Float lbusy; // Indicates the percentage of logical processor(s) utilization that occurred while executing at the user and system level.
/* AixProcessorStat(List<String> lines) {
System configuration: type=Shared mode=Uncapped smt=8 lcpu=8 mem=4096MB psize=19 ent=0.50 Pattern p;
for (String line : lines) {
if (line.startsWith("System configuration:")) {
%user %sys %wait %idle physc %entc lbusy vcsw phint %nsp %utcyc p = patternAix;
----- ----- ------ ------ ----- ----- ------ ----- ----- ----- ------ Matcher matcher = patternAix.matcher(line);
0.1 0.0 0.0 99.9 0.00 0.2 1.9 37441986 316 149 33.06
*/
AixProcessorStat(List<String> vmstatLines) {
for(String line : vmstatLines) {
Matcher matcher = pattern.matcher(line);
if (matcher.find() && matcher.groupCount() == 7) { if (matcher.find() && matcher.groupCount() == 7) {
type=matcher.group(1); type = matcher.group(1);
mode=matcher.group(2); mode = matcher.group(2);
smt = Integer.parseInt(matcher.group(3)); smt = Integer.parseInt(matcher.group(3));
lcpu = Integer.parseInt(matcher.group(4)); lcpu = Integer.parseInt(matcher.group(4));
psize = Integer.parseInt(matcher.group(5)); psize = Integer.parseInt(matcher.group(5));
ent = Float.parseFloat(matcher.group(7)); ent = Float.parseFloat(matcher.group(7));
break;
} }
} }
String vmstat = vmstatLines.get(vmstatLines.size() -1); if (line.startsWith("type=")) {
String[] splitStr = vmstat.trim().split("\\s+"); //type=Shared mode=Uncapped smt=8 lcpu=4 mem=4101120 kB cpus=24 ent=4.00
if(splitStr.length != 11) {
throw new UnsupportedOperationException("vmstat string error: " + splitStr.length); Matcher matcher = patternLinux.matcher(line);
if (matcher.find() && matcher.groupCount() == 7) {
type = matcher.group(1);
mode = matcher.group(2);
smt = Integer.parseInt(matcher.group(3));
lcpu = Integer.parseInt(matcher.group(4));
psize = Integer.parseInt(matcher.group(6));
ent = Float.parseFloat(matcher.group(7));
}
}
}
String lparstat = lines.get(lines.size() -1);
String[] splitStr = lparstat.trim().split("\\s+");
if(splitStr.length < 9) {
throw new UnsupportedOperationException("lparstat string error: " + lparstat);
} }
this.user = Float.parseFloat(splitStr[0]); this.user = Float.parseFloat(splitStr[0]);

View file

@ -4,10 +4,10 @@ import spock.lang.Specification
class AixProcessorTest extends Specification { class AixProcessorTest extends Specification {
void "test lparstat output processing"() { void "test AIX lparstat output processing"() {
setup: setup:
def testFile = new File(getClass().getResource('/lparstat.txt').toURI()) def testFile = new File(getClass().getResource('/lparstat-aix.txt').toURI())
List<String> lines = testFile.readLines("UTF-8") List<String> lines = testFile.readLines("UTF-8")
when: when:
@ -24,4 +24,25 @@ class AixProcessorTest extends Specification {
} }
void "test Linux lparstat output processing"() {
setup:
def testFile = new File(getClass().getResource('/lparstat-linux.txt').toURI())
List<String> lines = testFile.readLines("UTF-8")
when:
AixProcessorExtension extension = new AixProcessorExtension()
AixProcessorStat stats = extension.processCommandOutput(lines)
then:
stats.getUser() == 0.03f
stats.getSys() == 0.0f
stats.getWait() == 0.0f
stats.getIdle() == 99.97f
stats.getFields().get("ent") == 4.00f
stats.getTags().get("mode") == "Uncapped"
stats.getTags().get("type") == "Shared"
}
} }

View file

@ -0,0 +1,7 @@
System Configuration
type=Shared mode=Uncapped smt=8 lcpu=4 mem=4101120 kB cpus=24 ent=4.00
%user %sys %wait %idle physc %entc lbusy vcsw phint
----- ----- ----- ----- ----- ----- ----- ----- -----
0.03 0.00 0.00 99.97 0.000000 0.000000 0.03 445478301 18863

View file

@ -27,7 +27,8 @@ public class LinuxDiskExtension implements MetricExtension {
@Override @Override
public boolean isSupported() { public boolean isSupported() {
return System.getProperty("os.name").toLowerCase().contains("linux"); //return System.getProperty("os.name").toLowerCase().contains("linux");
return false; // TODO: Not ready yet.
} }
@Override @Override
@ -35,6 +36,11 @@ public class LinuxDiskExtension implements MetricExtension {
return "linux-disk"; return "linux-disk";
} }
@Override
public String getProvides() {
return "disk";
}
@Override @Override
public String getDescription() { public String getDescription() {
return "Linux Disk Metrics"; return "Linux Disk Metrics";

View file

@ -6,6 +6,8 @@ import org.sysmon.shared.MetricExtension;
import org.sysmon.shared.MetricResult; import org.sysmon.shared.MetricResult;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
@ -31,6 +33,11 @@ public class LinuxMemoryExtension implements MetricExtension {
return "linux-memory"; return "linux-memory";
} }
@Override
public String getProvides() {
return "memory";
}
@Override @Override
public String getDescription() { public String getDescription() {
return "Linux Memory Metrics"; return "Linux Memory Metrics";
@ -42,7 +49,7 @@ public class LinuxMemoryExtension implements MetricExtension {
MetricResult result = new MetricResult("memory"); MetricResult result = new MetricResult("memory");
try { try {
result.setMeasurement(readProcFile()); result.setMeasurement(processProcFile(readProcFile()));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -51,27 +58,51 @@ public class LinuxMemoryExtension implements MetricExtension {
} }
private Measurement readProcFile() throws IOException { protected List<String> readProcFile() throws IOException {
List<String> allLines = Files.readAllLines(Paths.get("/proc/meminfo"), StandardCharsets.UTF_8);
return allLines;
}
protected Measurement processProcFile(List<String> lines) {
Map<String, String> tagsMap = new HashMap<>(); Map<String, String> tagsMap = new HashMap<>();
Map<String, Object> fieldsMap = new HashMap<>(); Map<String, Object> fieldsMap = new HashMap<>();
List<String> allLines = Files.readAllLines(Paths.get("/proc/meminfo"), StandardCharsets.UTF_8); Long total = null;
for (String line : allLines) { Long available = null;
for (String line : lines) {
if (line.startsWith("Mem")) { if (line.startsWith("Mem")) {
Matcher matcher = pattern.matcher(line); Matcher matcher = pattern.matcher(line);
if (matcher.find() && matcher.groupCount() == 2) { if (matcher.find() && matcher.groupCount() == 2) {
String key = matcher.group(1).substring(3).toLowerCase(); // remove "Mem" and lowercase String key = matcher.group(1).substring(3).toLowerCase(); // remove "Mem" and lowercase
Object value = matcher.group(2); String value = matcher.group(2);
fieldsMap.put(key, value);
switch (key) {
case "total":
total = Long.parseLong(value);
fieldsMap.put(key, total);
break;
case "available":
available = Long.parseLong(value);
fieldsMap.put(key, available);
break;
}
} }
} }
}
if(total != null && available != null) {
BigDecimal usage = BigDecimal.valueOf(((float)(total - available) / total) * 100);
fieldsMap.put("usage", usage.setScale(2, RoundingMode.HALF_EVEN));
} }
return new Measurement(tagsMap, fieldsMap); return new Measurement(tagsMap, fieldsMap);
} }
} }

View file

@ -35,6 +35,11 @@ public class LinuxProcessorExtension implements MetricExtension {
return "linux-processor"; return "linux-processor";
} }
@Override
public String getProvides() {
return "processor";
}
@Override @Override
public String getDescription() { public String getDescription() {
return "Linux Processor Metrics"; return "Linux Processor Metrics";

View file

@ -0,0 +1,23 @@
import org.sysmon.plugins.sysmon_linux.LinuxMemoryExtension
import org.sysmon.shared.Measurement
import spock.lang.Specification
class LinuxMemoryTest extends Specification {
void "test proc file processing"() {
setup:
def testFile = new File(getClass().getResource('/meminfo.txt').toURI())
List<String> lines = testFile.readLines("UTF-8")
when:
LinuxMemoryExtension extension = new LinuxMemoryExtension()
Measurement m = extension.processProcFile(lines);
then:
m.getFields().get("total") == 16069616
m.getFields().get("available") == 7968744
m.getFields().get("usage") == 50.41
}
}

View file

@ -0,0 +1,51 @@
MemTotal: 16069616 kB
MemFree: 1587092 kB
MemAvailable: 7968744 kB
Buffers: 463364 kB
Cached: 6808540 kB
SwapCached: 2156 kB
Active: 9179808 kB
Inactive: 4369880 kB
Active(anon): 6366532 kB
Inactive(anon): 761912 kB
Active(file): 2813276 kB
Inactive(file): 3607968 kB
Unevictable: 270200 kB
Mlocked: 48 kB
SwapTotal: 3985404 kB
SwapFree: 3974652 kB
Dirty: 9708 kB
Writeback: 0 kB
AnonPages: 6545944 kB
Mapped: 1948448 kB
Shmem: 852772 kB
KReclaimable: 302640 kB
Slab: 502784 kB
SReclaimable: 302640 kB
SUnreclaim: 200144 kB
KernelStack: 21376 kB
PageTables: 52856 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 12020212 kB
Committed_AS: 14750600 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 42828 kB
VmallocChunk: 0 kB
Percpu: 8320 kB
HardwareCorrupted: 0 kB
AnonHugePages: 0 kB
ShmemHugePages: 0 kB
ShmemPmdMapped: 0 kB
FileHugePages: 0 kB
FilePmdMapped: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
Hugetlb: 0 kB
DirectMap4k: 410796 kB
DirectMap2M: 10795008 kB
DirectMap1G: 6291456 kB

View file

@ -1,7 +1,7 @@
plugins { plugins {
id 'application' id 'application'
id "com.github.johnrengelman.shadow" version "6.1.0" id "com.github.johnrengelman.shadow" version "7.0.0"
id "net.nemerosa.versioning" version "2.14.0" id "net.nemerosa.versioning" version "2.14.0"
id "nebula.ospackage" version "8.5.6" id "nebula.ospackage" version "8.5.6"
} }
@ -39,7 +39,7 @@ ospackage {
user = 'root' user = 'root'
packager = "Mark Nellemann <mark.nellemann@gmail.com>" packager = "Mark Nellemann <mark.nellemann@gmail.com>"
into '/opt/sysmon-server' into '/opt/sysmon/server'
from(shadowJar.outputs.files) { from(shadowJar.outputs.files) {
into 'lib' into 'lib'
@ -69,7 +69,8 @@ buildDeb {
dependsOn startShadowScripts dependsOn startShadowScripts
} }
task aixRpm(type: Rpm) { task buildRpmAix(type: Rpm) {
dependsOn startShadowScripts
os "AIX" os "AIX"
} }
@ -83,6 +84,14 @@ jar {
'Build-Version' : versioning.info.tag ?: (versioning.info.branch + "-" + versioning.info.build), 'Build-Version' : versioning.info.tag ?: (versioning.info.branch + "-" + versioning.info.build),
'Build-Revision' : versioning.info.commit, 'Build-Revision' : versioning.info.commit,
'Build-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ss.SSSZ").toString(), 'Build-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ss.SSSZ").toString(),
'Add-Opens' : 'java.base/java.lang.invoke' // To ignore "Illegal reflective access by retrofit2.Platform" warnings
) )
} }
} }
shadowJar {
archiveBaseName.set('sysmon-server')
archiveClassifier.set('')
archiveVersion.set('')
mergeServiceFiles() // Tell plugin to merge duplicate service files
}

View file

@ -1,12 +1,16 @@
package org.sysmon.server; package org.sysmon.server;
import org.apache.camel.CamelContext;
import org.apache.camel.main.Main; import org.apache.camel.main.Main;
import org.apache.camel.support.DefaultRegistry;
import org.apache.camel.support.SimpleRegistry;
import org.influxdb.InfluxDB; import org.influxdb.InfluxDB;
import org.influxdb.InfluxDBFactory; import org.influxdb.InfluxDBFactory;
import picocli.CommandLine; import picocli.CommandLine;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Properties;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
@CommandLine.Command(name = "sysmon-server", mixinStandardHelpOptions = true) @CommandLine.Command(name = "sysmon-server", mixinStandardHelpOptions = true)
@ -21,8 +25,11 @@ public class Application implements Callable<Integer> {
@CommandLine.Option(names = { "-p", "--influxdb-pass" }, description = "InfluxDB Password (default: ${DEFAULT-VALUE}).", defaultValue = "", paramLabel = "<pass>") @CommandLine.Option(names = { "-p", "--influxdb-pass" }, description = "InfluxDB Password (default: ${DEFAULT-VALUE}).", defaultValue = "", paramLabel = "<pass>")
private String influxPass; private String influxPass;
@CommandLine.Option(names = { "-s", "--server-port" }, description = "Server port (default: ${DEFAULT-VALUE}).", defaultValue = "9925", paramLabel = "<port>") @CommandLine.Option(names = { "-H", "--server-host" }, description = "Server listening address (default: ${DEFAULT-VALUE}).", paramLabel = "<addr>")
private String listenPort; private String listenHost = "0.0.0.0";
@CommandLine.Option(names = { "-P", "--server-port" }, description = "Server listening port (default: ${DEFAULT-VALUE}).", paramLabel = "<port>")
private Integer listenPort = 9925;
public static void main(String... args) { public static void main(String... args) {
@ -34,14 +41,19 @@ public class Application implements Callable<Integer> {
@Override @Override
public Integer call() throws IOException { public Integer call() throws IOException {
Properties properties = new Properties();
properties.put("http.host", listenHost);
properties.put("http.port", listenPort);
InfluxDB influxConnectionBean = InfluxDBFactory.connect(influxUrl.toString(), influxUser, influxPass); InfluxDB influxConnectionBean = InfluxDBFactory.connect(influxUrl.toString(), influxUser, influxPass);
Main main = new Main(); Main main = new Main();
main.bind("myInfluxConnection", influxConnectionBean); main.bind("myInfluxConnection", influxConnectionBean);
main.bind("myListenPort", Integer.parseInt(listenPort)); main.bind("http.host", listenHost);
main.bind("http.port", listenPort);
main.bind("properties", properties);
main.configure().addRoutesBuilder(ServerRouteBuilder.class); main.configure().addRoutesBuilder(ServerRouteBuilder.class);
// now keep the application running until the JVM is terminated (ctrl + c or sigterm) // now keep the application running until the JVM is terminated (ctrl + c or sigterm)
try { try {
main.run(); main.run();

View file

@ -5,6 +5,8 @@ import org.apache.camel.model.rest.RestBindingMode;
import org.apache.camel.spi.Registry; import org.apache.camel.spi.Registry;
import org.sysmon.shared.MetricResult; import org.sysmon.shared.MetricResult;
import java.util.Properties;
public class ServerRouteBuilder extends RouteBuilder { public class ServerRouteBuilder extends RouteBuilder {
@Override @Override
@ -14,8 +16,8 @@ public class ServerRouteBuilder extends RouteBuilder {
restConfiguration().component("jetty") restConfiguration().component("jetty")
.bindingMode(RestBindingMode.auto) .bindingMode(RestBindingMode.auto)
.host("127.0.0.1") .host(registry.lookupByNameAndType("http.host", String.class))
.port((Integer) registry.lookupByName("myListenPort")); .port(registry.lookupByNameAndType("http.port", Integer.class));
rest() rest()
.get("/") .get("/")
@ -39,7 +41,7 @@ public class ServerRouteBuilder extends RouteBuilder {
.log(">>> metric: ${header.hostname} - ${body}") .log(">>> metric: ${header.hostname} - ${body}")
.doTry() .doTry()
.process(new MetricResultToPointProcessor()) .process(new MetricResultToPointProcessor())
.to("influxdb://myInfluxConnection?databaseName=sysmon&retentionPolicy=autogen") .to("influxdb://ref.myInfluxConnection?databaseName=sysmon&retentionPolicy=autogen")
.doCatch(Exception.class) .doCatch(Exception.class)
.log("Error storing metric to InfluxDB: ${exception}") .log("Error storing metric to InfluxDB: ${exception}")
.end(); .end();

View file

@ -27,7 +27,7 @@ camel.main.name = sysmon-server
#camel.main.beanIntrospectionLoggingLevel=INFO #camel.main.beanIntrospectionLoggingLevel=INFO
# run in lightweight mode to be tiny as possible # run in lightweight mode to be tiny as possible
camel.main.lightweight = true #camel.main.lightweight = true
# and eager load classes # and eager load classes
#camel.main.eager-classloading = true #camel.main.eager-classloading = true

View file

@ -7,6 +7,7 @@ public interface MetricExtension extends ExtensionPoint {
boolean isSupported(); boolean isSupported();
String getName(); String getName();
String getProvides();
String getDescription(); String getDescription();
MetricResult getMetrics(); MetricResult getMetrics();

View file

@ -7,8 +7,12 @@ import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Stream;
public class PluginHelper { public class PluginHelper {
@ -58,5 +62,10 @@ public class PluginHelper {
} }
public static boolean canExecute(String cmd) {
return Stream.of(System.getenv("PATH").split(Pattern.quote(File.pathSeparator)))
.map(Paths::get)
.anyMatch(path -> Files.exists(path.resolve(cmd)));
}
} }