Merged in development (pull request #9)

Support for configuring extensions.
This commit is contained in:
Mark Nellemann 2021-09-10 20:00:13 +00:00
commit 39d3127437
31 changed files with 437 additions and 126 deletions

View file

@ -19,6 +19,7 @@ subprojects {
implementation "org.slf4j:slf4j-api:${slf4jVersion}" implementation "org.slf4j:slf4j-api:${slf4jVersion}"
implementation "org.slf4j:slf4j-simple:${slf4jVersion}" implementation "org.slf4j:slf4j-simple:${slf4jVersion}"
implementation 'org.tomlj:tomlj:1.0.0'
} }

View file

@ -37,11 +37,12 @@ def projectName = "sysmon-client"
application { application {
// Define the main class for the application. // Define the main class for the application.
mainClass.set('sysmon.client.Application') mainClass.set('sysmon.client.Application')
applicationDefaultJvmArgs = [ "-server", "-XX:+UseG1GC", "-Xmx32m" ] applicationDefaultJvmArgs = [ "-server", "-Xms16m", "-Xmx32m", "-XX:+UseG1GC" ]
} }
run { run {
systemProperty 'pf4j.pluginsDir', '../plugins/output/' systemProperty 'pf4j.pluginsDir', '../plugins/output/'
systemProperty 'sysmon.cfgFile', 'doc/sysmon-client.toml'
} }
tasks.named('test') { tasks.named('test') {

View file

@ -4,7 +4,7 @@ Works on IBM Power VIO (Virtual IO) servers, as well as regular IBM Power AIX in
## Installation ## Installation
We require Java 8, which should already be installed. We require Java 8, which should already be installed on AIX, or is available to install.
The RPM packages are *"noarch"* Java bytecode, so we can use the **--ignoreos** option to install: The RPM packages are *"noarch"* Java bytecode, so we can use the **--ignoreos** option to install:
```shell ```shell

View file

@ -2,8 +2,8 @@
Description=Sysmon Client Service Description=Sysmon Client Service
[Service] [Service]
TimeoutStartSec=0 TimeoutSec=20
Restart=always Restart=on-failure
ExecStart=/opt/sysmon/client/bin/client -s http://10.20.30.40:9925/metrics ExecStart=/opt/sysmon/client/bin/client -s http://10.20.30.40:9925/metrics
[Install] [Install]

View file

@ -0,0 +1,10 @@
# Configuration for sysmon-client
[extension.base_disk]
enabled = false
[extension.base_process]
enabled = true
include = [ "java", "influxd", "grafana-server" ]

View file

@ -4,10 +4,9 @@
package sysmon.client; package sysmon.client;
import org.apache.camel.main.Main; import org.apache.camel.main.Main;
import org.slf4j.Logger;
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;
@ -17,8 +16,6 @@ import java.util.concurrent.Callable;
@CommandLine.Command(name = "sysmon-client", mixinStandardHelpOptions = true) @CommandLine.Command(name = "sysmon-client", mixinStandardHelpOptions = true)
public class Application implements Callable<Integer> { public class Application implements Callable<Integer> {
private static final Logger log = LoggerFactory.getLogger(Application.class);
@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;
@ -28,6 +25,9 @@ public class Application implements Callable<Integer> {
@CommandLine.Option(names = { "-p", "--plugin-dir" }, description = "Plugin jar path (default: ${DEFAULT-VALUE}).", paramLabel = "<path>", defaultValue = "/opt/sysmon/plugins") @CommandLine.Option(names = { "-p", "--plugin-dir" }, description = "Plugin jar path (default: ${DEFAULT-VALUE}).", paramLabel = "<path>", defaultValue = "/opt/sysmon/plugins")
private String pluginPath; private String pluginPath;
@CommandLine.Option(names = { "-c", "--conf" }, description = "Configuration file [default: '/etc/sysmon-client.toml'].", paramLabel = "<file>", defaultValue = "/etc/sysmon-client.toml")
private File configurationFile;
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);
System.exit(exitCode); System.exit(exitCode);
@ -37,6 +37,8 @@ public class Application implements Callable<Integer> {
@Override @Override
public Integer call() throws IOException { public Integer call() throws IOException {
Configuration configuration = new Configuration();
if(hostname == null || hostname.isEmpty()) { if(hostname == null || hostname.isEmpty()) {
try { try {
hostname = InetAddress.getLocalHost().getHostName(); hostname = InetAddress.getLocalHost().getHostName();
@ -51,10 +53,26 @@ public class Application implements Callable<Integer> {
pluginPath = pf4jPluginsDir; pluginPath = pf4jPluginsDir;
} }
String sysmonCfgFile = System.getProperty("sysmon.cfgFile");
if(sysmonCfgFile != null) {
configurationFile = new File(sysmonCfgFile);
}
if(configurationFile.exists()) {
try {
configuration.parse(configurationFile.toPath());
} catch (Exception e) {
System.err.println(e.getMessage());
return 1;
}
}
Main main = new Main(); Main main = new Main();
main.bind("pluginPath", pluginPath); main.bind("pluginPath", pluginPath);
main.bind("myServerUrl", serverUrl.toString()); main.bind("myServerUrl", serverUrl.toString());
main.bind("myHostname", hostname); main.bind("myHostname", hostname);
main.bind("configuration", configuration);
main.configure().addRoutesBuilder(ClientRouteBuilder.class); main.configure().addRoutesBuilder(ClientRouteBuilder.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)
@ -62,6 +80,7 @@ public class Application implements Callable<Integer> {
main.run(); main.run();
} catch (Exception e) { } catch (Exception e) {
System.err.println(e.getMessage()); System.err.println(e.getMessage());
return 1;
} }
return 0; return 0;

View file

@ -24,6 +24,7 @@ public class ClientRouteBuilder extends RouteBuilder {
public void configure() { public void configure() {
Registry registry = getContext().getRegistry(); Registry registry = getContext().getRegistry();
Configuration configuration = (Configuration) registry.lookupByName("configuration");
Path[] pluginpaths = { Paths.get(registry.lookupByNameAndType("pluginPath", String.class)) }; Path[] pluginpaths = { Paths.get(registry.lookupByNameAndType("pluginPath", String.class)) };
PluginManager pluginManager = new JarPluginManager(pluginpaths); PluginManager pluginManager = new JarPluginManager(pluginpaths);
@ -34,9 +35,18 @@ public class ClientRouteBuilder extends RouteBuilder {
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()) { final String name = ext.getName();
final String provides = ext.getProvides();
String provides = ext.getProvides(); // Load configuration if available
if(configuration.isForExtension(name)) {
log.info(">>> Loading configuring for extension: " + ext.getDescription());
ext.setConfiguration(configuration.getForExtension(name));
}
if(ext.isSupported() && ext.isEnabled()) {
// Check that another extension has not already been loaded - TODO: Is this required ?
if(providers.contains(provides)) { if(providers.contains(provides)) {
log.warn("Skipping extension (already provided): " + ext.getName()); log.warn("Skipping extension (already provided): " + ext.getName());
continue; continue;
@ -46,7 +56,7 @@ public class ClientRouteBuilder extends RouteBuilder {
providers.add(provides); providers.add(provides);
// TODO: Make timer thread configurable // TODO: Make timer thread configurable ?
// Setup Camel route for this extension // Setup Camel route for this extension
// a unique timer name gives the timer it's own thread, otherwise it's a shared thread for other timers with same name. // a unique timer name gives the timer it's own thread, otherwise it's a shared thread for other timers with same name.
@ -62,7 +72,7 @@ public class ClientRouteBuilder extends RouteBuilder {
.otherwise() .otherwise()
.to("seda:metrics?discardWhenFull=true"); .to("seda:metrics?discardWhenFull=true");
} else { } else {
log.info(">>> Skipping extension (not supported here): " + ext.getDescription()); log.info(">>> Skipping extension (not supported or disabled): " + ext.getDescription());
} }
} }

View file

@ -0,0 +1,64 @@
package sysmon.client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tomlj.Toml;
import org.tomlj.TomlParseResult;
import org.tomlj.TomlTable;
import java.io.IOException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public final class Configuration {
private final static Logger log = LoggerFactory.getLogger(Configuration.class);
private TomlParseResult result;
void parse(Path configurationFile) throws IOException {
log.info("Parsing configuration file: " + configurationFile);
result = Toml.parse(configurationFile);
result.errors().forEach(error -> log.error(error.toString()));
}
boolean isForExtension(String extName) {
if(result == null) {
return false;
}
String key = String.format("extension.%s", extName);
return result.contains(key);
}
Map<String, Object> getForExtension(String extName) {
if(result == null) {
log.debug("No configuration file loaded ...");
return null;
}
Map<String, Object> map = new HashMap<>();
String key = String.format("extension.%s", extName);
TomlTable table = result.getTableOrEmpty(key);
table.keySet().forEach( k -> {
if(table.isString(k)) {
map.put(k, table.getString(k));
} else if(table.isBoolean(k)) {
map.put(k, table.getBoolean(k));
} else if(table.isDouble(k)) {
map.put(k, table.getDouble(k));
} else if(table.isArray(k)) {
map.put(k, Objects.requireNonNull(table.getArray(k)).toList());
}
});
return map;
}
}

View file

@ -10,17 +10,11 @@
} }
], ],
"__requires": [ "__requires": [
{
"type": "panel",
"id": "gauge",
"name": "Gauge",
"version": ""
},
{ {
"type": "grafana", "type": "grafana",
"id": "grafana", "id": "grafana",
"name": "Grafana", "name": "Grafana",
"version": "8.0.6" "version": "8.1.2"
}, },
{ {
"type": "datasource", "type": "datasource",
@ -56,6 +50,12 @@
"hide": true, "hide": true,
"iconColor": "rgba(0, 211, 255, 1)", "iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts", "name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard" "type": "dashboard"
} }
] ]
@ -65,7 +65,7 @@
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
"iteration": 1631013505736, "iteration": 1631256755587,
"links": [], "links": [],
"panels": [ "panels": [
{ {
@ -120,7 +120,7 @@
"showHeader": true, "showHeader": true,
"sortBy": [] "sortBy": []
}, },
"pluginVersion": "8.0.6", "pluginVersion": "8.1.2",
"targets": [ "targets": [
{ {
"groupBy": [ "groupBy": [
@ -286,7 +286,7 @@
"text": {}, "text": {},
"textMode": "auto" "textMode": "auto"
}, },
"pluginVersion": "8.0.6", "pluginVersion": "8.1.2",
"targets": [ "targets": [
{ {
"groupBy": [ "groupBy": [
@ -377,7 +377,7 @@
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"color": { "color": {
"mode": "continuous-GrYlRd" "mode": "thresholds"
}, },
"mappings": [], "mappings": [],
"thresholds": { "thresholds": {
@ -426,6 +426,10 @@
}, },
"id": 26, "id": 26,
"options": { "options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": [
"lastNotNull" "lastNotNull"
@ -433,11 +437,10 @@
"fields": "", "fields": "",
"values": false "values": false
}, },
"showThresholdLabels": false, "text": {},
"showThresholdMarkers": true, "textMode": "auto"
"text": {}
}, },
"pluginVersion": "8.0.6", "pluginVersion": "8.1.2",
"targets": [ "targets": [
{ {
"groupBy": [ "groupBy": [
@ -471,10 +474,6 @@
"params": [], "params": [],
"type": "sum" "type": "sum"
}, },
{
"params": [],
"type": "non_negative_difference"
},
{ {
"params": [ "params": [
"read" "read"
@ -493,10 +492,6 @@
"params": [], "params": [],
"type": "sum" "type": "sum"
}, },
{
"params": [],
"type": "non_negative_difference"
},
{ {
"params": [ "params": [
"write" "write"
@ -529,7 +524,7 @@
"timeFrom": null, "timeFrom": null,
"timeShift": null, "timeShift": null,
"title": "Disk Metrics", "title": "Disk Metrics",
"type": "gauge" "type": "stat"
}, },
{ {
"datasource": "${DS_INFLUXDB-SYSMON}", "datasource": "${DS_INFLUXDB-SYSMON}",
@ -890,7 +885,7 @@
"refresh": 2, "refresh": 2,
"regex": "", "regex": "",
"skipUrlSync": false, "skipUrlSync": false,
"sort": 0, "sort": 5,
"tagValuesQuery": "", "tagValuesQuery": "",
"tagsQuery": "", "tagsQuery": "",
"type": "query", "type": "query",
@ -913,14 +908,14 @@
"refresh": 1, "refresh": 1,
"regex": "", "regex": "",
"skipUrlSync": false, "skipUrlSync": false,
"sort": 0, "sort": 5,
"type": "query" "type": "query"
}, },
{ {
"allValue": "", "allValue": null,
"current": {}, "current": {},
"datasource": "${DS_INFLUXDB-SYSMON}", "datasource": "${DS_INFLUXDB-SYSMON}",
"definition": "SHOW TAG VALUES FROM \"base_process\" WITH KEY = \"pid\" WHERE hostname =~ /$hostname/AND \"name\" =~ /$process/ AND time > now() - 60m", "definition": "SELECT DISTINCT(\"pid\") FROM (SELECT * FROM \"base_process\" WHERE time > now() - 60m AND \"hostname\" =~ /$hostname/ AND \"name\" =~ /$process/)",
"description": null, "description": null,
"error": null, "error": null,
"hide": 0, "hide": 0,
@ -929,17 +924,17 @@
"multi": false, "multi": false,
"name": "pid", "name": "pid",
"options": [], "options": [],
"query": "SHOW TAG VALUES FROM \"base_process\" WITH KEY = \"pid\" WHERE hostname =~ /$hostname/AND \"name\" =~ /$process/ AND time > now() - 60m", "query": "SELECT DISTINCT(\"pid\") FROM (SELECT * FROM \"base_process\" WHERE time > now() - 60m AND \"hostname\" =~ /$hostname/ AND \"name\" =~ /$process/)",
"refresh": 1, "refresh": 2,
"regex": "", "regex": "",
"skipUrlSync": false, "skipUrlSync": false,
"sort": 0, "sort": 3,
"type": "query" "type": "query"
} }
] ]
}, },
"time": { "time": {
"from": "now-3h", "from": "now-6h",
"to": "now-30s" "to": "now-30s"
}, },
"timepicker": { "timepicker": {
@ -958,5 +953,5 @@
"timezone": "", "timezone": "",
"title": "Sysmon - Process Explorer", "title": "Sysmon - Process Explorer",
"uid": "Vjut5mS7k", "uid": "Vjut5mS7k",
"version": 11 "version": 15
} }

View file

@ -1,4 +1,4 @@
version=0.0.9 version=0.0.10
pf4jVersion=3.6.0 pf4jVersion=3.6.0
slf4jVersion=1.7.32 slf4jVersion=1.7.32
camelVersion=3.11.1 camelVersion=3.11.1

View file

@ -19,6 +19,20 @@ public class AixNetstatExtension implements MetricExtension {
private static final Logger log = LoggerFactory.getLogger(AixNetstatExtension.class); private static final Logger log = LoggerFactory.getLogger(AixNetstatExtension.class);
// Extension details
private final String name = "aix_network_netstat";
private final String provides = "network_netstat";
private final String description = "AIX Netstat Metrics";
// Configuration / Options
private boolean enabled = true;
@Override
public boolean isEnabled() {
return enabled;
}
@Override @Override
public boolean isSupported() { public boolean isSupported() {
@ -37,17 +51,24 @@ public class AixNetstatExtension implements MetricExtension {
@Override @Override
public String getName() { public String getName() {
return "aix_network_netstat"; return name;
} }
@Override @Override
public String getProvides() { public String getProvides() {
return "network_netstat"; return provides;
} }
@Override @Override
public String getDescription() { public String getDescription() {
return "AIX Netstat Metrics"; return description;
}
@Override
public void setConfiguration(Map<String, Object> map) {
if (map.containsKey("enabled")) {
enabled = (boolean) map.get("enabled");
}
} }
@Override @Override
@ -63,7 +84,7 @@ public class AixNetstatExtension implements MetricExtension {
} }
log.debug(fieldsMap.toString()); log.debug(fieldsMap.toString());
return new MetricResult(getName(), new Measurement(tagsMap, fieldsMap)); return new MetricResult(name, new Measurement(tagsMap, fieldsMap));
} }

View file

@ -8,7 +8,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
public class AixNetstatParser { public class AixNetstatParser {

View file

@ -11,7 +11,6 @@ import sysmon.shared.PluginHelper;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
@Extension @Extension
@ -19,6 +18,20 @@ public class AixProcessorExtension implements MetricExtension {
private static final Logger log = LoggerFactory.getLogger(AixProcessorExtension.class); private static final Logger log = LoggerFactory.getLogger(AixProcessorExtension.class);
// Extension details
private final String name = "aix_processor";
private final String provides = "lpar_processor";
private final String description = "AIX Processor Metrics";
// Configuration / Options
private boolean enabled = true;
@Override
public boolean isEnabled() {
return enabled;
}
@Override @Override
public boolean isSupported() { public boolean isSupported() {
@ -38,17 +51,24 @@ public class AixProcessorExtension implements MetricExtension {
@Override @Override
public String getName() { public String getName() {
return "aix_processor"; return name;
} }
@Override @Override
public String getProvides() { public String getProvides() {
return "processor_lpar"; return provides;
} }
@Override @Override
public String getDescription() { public String getDescription() {
return "AIX Processor Metrics"; return description;
}
@Override
public void setConfiguration(Map<String, Object> map) {
if (map.containsKey("enabled")) {
enabled = (boolean) map.get("enabled");
}
} }
@Override @Override
@ -63,7 +83,7 @@ public class AixProcessorExtension implements MetricExtension {
fieldsMap = processorStat.getFields(); fieldsMap = processorStat.getFields();
} }
return new MetricResult(getName(), new Measurement(tagsMap, fieldsMap)); return new MetricResult(name, new Measurement(tagsMap, fieldsMap));
} }

View file

@ -8,8 +8,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.Objects;
import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -86,7 +85,7 @@ public class AixProcessorStat {
} }
//String lparstat = lines.get(lines.size() -1); //String lparstat = lines.get(lines.size() -1);
String[] splitStr = lastLine.trim().split("\\s+"); String[] splitStr = Objects.requireNonNull(lastLine).trim().split("\\s+");
if(type.equalsIgnoreCase("shared") && splitStr.length < 9 || if(type.equalsIgnoreCase("shared") && splitStr.length < 9 ||
type.equalsIgnoreCase("dedicated") && splitStr.length < 8) { type.equalsIgnoreCase("dedicated") && splitStr.length < 8) {
throw new UnsupportedOperationException("lparstat string error: " + lastLine); throw new UnsupportedOperationException("lparstat string error: " + lastLine);

View file

@ -36,3 +36,30 @@ Metrics reported are:
- **writes** - The total number of bytes written. - **writes** - The total number of bytes written.
- **iotime** - Time spent on IO in milliseconds. - **iotime** - Time spent on IO in milliseconds.
- **queue** - Lenght of IO queue. - **queue** - Lenght of IO queue.
## Process Extension
Reports metrics on one or more running processes.
- **mem_rss** - Resident set memory in bytes.
- **mem_vsz** - Virtual memory in bytes.
- **kernel_time** - Time spent (in milliseconds) in kernel space.
- **user_time** - Time used (in milliseconds) in user space.
- **read_bytes** - Bytes read by process.
- **write_bytes** - Bytes written by process.
- **files** - Files currently open by process.
- **threads** - Running threads.
- **user** - User running the process.
- **group** - Group running the process
- **prio** - Process priority.
### Configuration
The **include** option let's you specify what processes to report for.
```toml
[extension.base_process]
enabled = true # true or false
include = [ "java", "influxd", "grafana-server" ]
```

View file

@ -3,7 +3,6 @@ package sysmon.plugins.os_base;
import org.pf4j.Extension; import org.pf4j.Extension;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import oshi.SystemInfo;
import oshi.hardware.HWDiskStore; import oshi.hardware.HWDiskStore;
import oshi.hardware.HardwareAbstractionLayer; import oshi.hardware.HardwareAbstractionLayer;
import sysmon.shared.Measurement; import sysmon.shared.Measurement;
@ -19,9 +18,22 @@ public class BaseDiskExtension implements MetricExtension {
private static final Logger log = LoggerFactory.getLogger(BaseDiskExtension.class); private static final Logger log = LoggerFactory.getLogger(BaseDiskExtension.class);
// Extension details
private final String name = "base_disk";
private final String provides = "disk";
private final String description = "Base Disk Metrics";
// Configuration / Options
private boolean enabled = true;
private HardwareAbstractionLayer hardwareAbstractionLayer; private HardwareAbstractionLayer hardwareAbstractionLayer;
@Override
public boolean isEnabled() {
return enabled;
}
@Override @Override
public boolean isSupported() { public boolean isSupported() {
hardwareAbstractionLayer = BasePlugin.getHardwareAbstractionLayer(); hardwareAbstractionLayer = BasePlugin.getHardwareAbstractionLayer();
@ -30,19 +42,25 @@ public class BaseDiskExtension implements MetricExtension {
@Override @Override
public String getName() { public String getName() {
return "base_disk"; return name;
} }
@Override @Override
public String getProvides() { public String getProvides() {
return "disk"; return provides;
} }
@Override @Override
public String getDescription() { public String getDescription() {
return "Base Disk Metrics"; return description;
} }
@Override
public void setConfiguration(Map<String, Object> map) {
if (map.containsKey("enabled")) {
enabled = (boolean) map.get("enabled");
}
}
@Override @Override
public MetricResult getMetrics() { public MetricResult getMetrics() {
@ -58,7 +76,7 @@ public class BaseDiskExtension implements MetricExtension {
List<HWDiskStore> diskStores = hardwareAbstractionLayer.getDiskStores(); List<HWDiskStore> diskStores = hardwareAbstractionLayer.getDiskStores();
for(HWDiskStore store : diskStores) { for(HWDiskStore store : diskStores) {
String name = store.getName(); String name = store.getName();
if (name.matches("hdisk[0-9]+") || name.matches("/dev/x?[sv]d[a-z]{1}") || name.matches("/dev/nvme[0-9]n[0-9]")) { if (name.matches("hdisk[0-9]+") || name.matches("/dev/x?[sv]d[a-z]") || name.matches("/dev/nvme[0-9]n[0-9]")) {
log.debug("Using device: " + name); log.debug("Using device: " + name);
writeBytes += store.getWriteBytes(); writeBytes += store.getWriteBytes();
readBytes += store.getReadBytes(); readBytes += store.getReadBytes();
@ -73,7 +91,7 @@ public class BaseDiskExtension implements MetricExtension {
fieldsMap.put("queue", queueLength); fieldsMap.put("queue", queueLength);
log.debug(fieldsMap.toString()); log.debug(fieldsMap.toString());
return new MetricResult(getName(), new Measurement(tagsMap, fieldsMap)); return new MetricResult(name, new Measurement(tagsMap, fieldsMap));
} }
} }

View file

@ -3,7 +3,6 @@ package sysmon.plugins.os_base;
import org.pf4j.Extension; import org.pf4j.Extension;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import oshi.SystemInfo;
import oshi.hardware.HardwareAbstractionLayer; import oshi.hardware.HardwareAbstractionLayer;
import sysmon.shared.Measurement; import sysmon.shared.Measurement;
import sysmon.shared.MetricExtension; import sysmon.shared.MetricExtension;
@ -17,8 +16,22 @@ public class BaseMemoryExtension implements MetricExtension {
private static final Logger log = LoggerFactory.getLogger(BaseMemoryExtension.class); private static final Logger log = LoggerFactory.getLogger(BaseMemoryExtension.class);
// Extension details
private final String name = "base_memory";
private final String provides = "memory";
private final String description = "Base Memory Metrics";
// Configuration / Options
private boolean enabled = true;
private HardwareAbstractionLayer hardwareAbstractionLayer; private HardwareAbstractionLayer hardwareAbstractionLayer;
@Override
public boolean isEnabled() {
return enabled;
}
@Override @Override
public boolean isSupported() { public boolean isSupported() {
hardwareAbstractionLayer = BasePlugin.getHardwareAbstractionLayer(); hardwareAbstractionLayer = BasePlugin.getHardwareAbstractionLayer();
@ -27,17 +40,24 @@ public class BaseMemoryExtension implements MetricExtension {
@Override @Override
public String getName() { public String getName() {
return "base_memory"; return name;
} }
@Override @Override
public String getProvides() { public String getProvides() {
return "memory"; return provides;
} }
@Override @Override
public String getDescription() { public String getDescription() {
return "Base Memory Metrics"; return description;
}
@Override
public void setConfiguration(Map<String, Object> map) {
if (map.containsKey("enabled")) {
enabled = (boolean) map.get("enabled");
}
} }
@Override @Override
@ -57,7 +77,7 @@ public class BaseMemoryExtension implements MetricExtension {
fieldsMap.put("virtual", hardwareAbstractionLayer.getMemory().getVirtualMemory().getVirtualInUse()); fieldsMap.put("virtual", hardwareAbstractionLayer.getMemory().getVirtualMemory().getVirtualInUse());
log.debug(fieldsMap.toString()); log.debug(fieldsMap.toString());
return new MetricResult(getName(), new Measurement(tagsMap, fieldsMap)); return new MetricResult(name, new Measurement(tagsMap, fieldsMap));
} }

View file

@ -3,7 +3,6 @@ package sysmon.plugins.os_base;
import org.pf4j.Extension; import org.pf4j.Extension;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import oshi.SystemInfo;
import oshi.hardware.HardwareAbstractionLayer; import oshi.hardware.HardwareAbstractionLayer;
import oshi.hardware.NetworkIF; import oshi.hardware.NetworkIF;
import sysmon.shared.Measurement; import sysmon.shared.Measurement;
@ -19,8 +18,22 @@ public class BaseNetworkExtension implements MetricExtension {
private static final Logger log = LoggerFactory.getLogger(BaseNetworkExtension.class); private static final Logger log = LoggerFactory.getLogger(BaseNetworkExtension.class);
// Extension details
private final String name = "base_network";
private final String provides = "network";
private final String description = "Base Network Metrics";
// Configuration / Options
private boolean enabled = true;
private HardwareAbstractionLayer hardwareAbstractionLayer; private HardwareAbstractionLayer hardwareAbstractionLayer;
@Override
public boolean isEnabled() {
return enabled;
}
@Override @Override
public boolean isSupported() { public boolean isSupported() {
hardwareAbstractionLayer = BasePlugin.getHardwareAbstractionLayer(); hardwareAbstractionLayer = BasePlugin.getHardwareAbstractionLayer();
@ -29,17 +42,24 @@ public class BaseNetworkExtension implements MetricExtension {
@Override @Override
public String getName() { public String getName() {
return "base_network"; return name;
} }
@Override @Override
public String getProvides() { public String getProvides() {
return "network"; return provides;
} }
@Override @Override
public String getDescription() { public String getDescription() {
return "Base Network Metrics"; return description;
}
@Override
public void setConfiguration(Map<String, Object> map) {
if (map.containsKey("enabled")) {
enabled = (boolean) map.get("enabled");
}
} }
@Override @Override
@ -75,7 +95,7 @@ public class BaseNetworkExtension implements MetricExtension {
fieldsMap.put("txErrors", txErrs); fieldsMap.put("txErrors", txErrs);
log.debug(fieldsMap.toString()); log.debug(fieldsMap.toString());
return new MetricResult(getName(), new Measurement(tagsMap, fieldsMap)); return new MetricResult(name, new Measurement(tagsMap, fieldsMap));
} }
} }

View file

@ -9,29 +9,31 @@ import sysmon.shared.Measurement;
import sysmon.shared.MetricExtension; import sysmon.shared.MetricExtension;
import sysmon.shared.MetricResult; import sysmon.shared.MetricResult;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
@Extension @Extension
public class BaseProcessExtension implements MetricExtension { public class BaseProcessExtension implements MetricExtension {
private static final Logger log = LoggerFactory.getLogger(BaseProcessorExtension.class); private static final Logger log = LoggerFactory.getLogger(BaseProcessorExtension.class);
// TODO: configurable include-list and/or exclude-list of process names // Extension details
private final List<String> includeList = new ArrayList<String>() {{ private final String name = "base_process";
private final String provides = "process";
private final String description = "Base Process Metrics";
// Configuration / Options
private boolean enabled = true;
private List<?> includeList = new ArrayList<Object>() {{
add("java"); add("java");
add("nginx");
add("influxd");
add("dockerd");
add("containerd");
add("mysqld");
add("postgres");
add("grafana-server");
}}; }};
private SystemInfo systemInfo; private SystemInfo systemInfo;
@Override
public boolean isEnabled() {
return enabled;
}
@Override @Override
public boolean isSupported() { public boolean isSupported() {
systemInfo = BasePlugin.getSystemInfo(); systemInfo = BasePlugin.getSystemInfo();
@ -40,19 +42,29 @@ public class BaseProcessExtension implements MetricExtension {
@Override @Override
public String getName() { public String getName() {
return "base_process"; return name;
} }
@Override @Override
public String getProvides() { public String getProvides() {
return "process"; return provides;
} }
@Override @Override
public String getDescription() { public String getDescription() {
return "Base Process Metrics"; return description;
} }
@Override
public void setConfiguration(Map<String, Object> map) {
if(map.containsKey("enabled")) {
enabled = (boolean) map.get("enabled");
}
if(map.containsKey("include")) {
includeList = (List<?>) map.get("include");
}
log.info(includeList.toString());
}
@Override @Override
public MetricResult getMetrics() { public MetricResult getMetrics() {
@ -71,7 +83,7 @@ public class BaseProcessExtension implements MetricExtension {
if(!includeList.contains(name)) { if(!includeList.contains(name)) {
continue; continue;
} }
log.debug("pid: " + p.getProcessID() + ", name: " + name + ", virt: " + p.getVirtualSize() + " rss: " + p.getResidentSetSize() + " cmd: " + p.getCommandLine()); log.debug("pid: " + p.getProcessID() + ", name: " + name + ", virt: " + p.getVirtualSize() + " rss: " + p.getResidentSetSize());
HashMap<String, String> tagsMap = new HashMap<>(); HashMap<String, String> tagsMap = new HashMap<>();
HashMap<String, Object> fieldsMap = new HashMap<>(); HashMap<String, Object> fieldsMap = new HashMap<>();
@ -95,7 +107,7 @@ public class BaseProcessExtension implements MetricExtension {
} }
//log.info("Size of measurements: " + measurementList.size()); //log.info("Size of measurements: " + measurementList.size());
return new MetricResult(getName(), measurementList); return new MetricResult(name, measurementList);
} }
} }

View file

@ -3,20 +3,13 @@ package sysmon.plugins.os_base;
import org.pf4j.Extension; import org.pf4j.Extension;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor; import oshi.hardware.CentralProcessor;
import oshi.hardware.HardwareAbstractionLayer; import oshi.hardware.HardwareAbstractionLayer;
import sysmon.shared.Measurement; import sysmon.shared.Measurement;
import sysmon.shared.MetricExtension; import sysmon.shared.MetricExtension;
import sysmon.shared.MetricResult; import 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.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
@Extension @Extension
@ -24,9 +17,22 @@ public class BaseProcessorExtension implements MetricExtension {
private static final Logger log = LoggerFactory.getLogger(BaseProcessorExtension.class); private static final Logger log = LoggerFactory.getLogger(BaseProcessorExtension.class);
// Extension details
private final String name = "base_processor";
private final String provides = "processor";
private final String description = "Base Processor Metrics";
// Configuration / Options
private boolean enabled = true;
private HardwareAbstractionLayer hardwareAbstractionLayer; private HardwareAbstractionLayer hardwareAbstractionLayer;
private long[] oldTicks; private long[] oldTicks;
@Override
public boolean isEnabled() {
return enabled;
}
@Override @Override
public boolean isSupported() { public boolean isSupported() {
hardwareAbstractionLayer = BasePlugin.getHardwareAbstractionLayer(); hardwareAbstractionLayer = BasePlugin.getHardwareAbstractionLayer();
@ -35,19 +41,25 @@ public class BaseProcessorExtension implements MetricExtension {
@Override @Override
public String getName() { public String getName() {
return "base_processor"; return name;
} }
@Override @Override
public String getProvides() { public String getProvides() {
return "processor"; return provides;
} }
@Override @Override
public String getDescription() { public String getDescription() {
return "Base Processor Metrics"; return description;
} }
@Override
public void setConfiguration(Map<String, Object> map) {
if (map.containsKey("enabled")) {
enabled = (boolean) map.get("enabled");
}
}
@Override @Override
public MetricResult getMetrics() { public MetricResult getMetrics() {
@ -86,7 +98,7 @@ public class BaseProcessorExtension implements MetricExtension {
oldTicks = ticks; oldTicks = ticks;
log.debug(fieldsMap.toString()); log.debug(fieldsMap.toString());
return new MetricResult(getName(), new Measurement(tagsMap, fieldsMap)); return new MetricResult(name, new Measurement(tagsMap, fieldsMap));
} }
} }

View file

@ -8,6 +8,7 @@ import sysmon.shared.MetricExtension;
import sysmon.shared.MetricResult; import sysmon.shared.MetricResult;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
// Disable for now... // Disable for now...
//@Extension //@Extension
@ -15,9 +16,23 @@ public class TestExtension implements MetricExtension {
private static final Logger log = LoggerFactory.getLogger(TestExtension.class); private static final Logger log = LoggerFactory.getLogger(TestExtension.class);
// Extension details
private final String name = "ibmi_test";
private final String provides = "ibmi_test";
private final String description = "IBM i Test Metrics";
// Configuration / Options
private boolean enabled = true;
private AS400 as400; private AS400 as400;
private SystemStatus systemStatus; private SystemStatus systemStatus;
@Override
public boolean isEnabled() {
return enabled;
}
@Override @Override
public boolean isSupported() { public boolean isSupported() {
@ -47,17 +62,24 @@ public class TestExtension implements MetricExtension {
@Override @Override
public String getName() { public String getName() {
return "ibmi-test"; return name;
} }
@Override @Override
public String getProvides() { public String getProvides() {
return "test"; return provides;
} }
@Override @Override
public String getDescription() { public String getDescription() {
return "IBM i Test Extension"; return description;
}
@Override
public void setConfiguration(Map<String, Object> map) {
if (map.containsKey("enabled")) {
enabled = (boolean) map.get("enabled");
}
} }
@Override @Override

View file

@ -19,6 +19,20 @@ public class LinuxNetstatExtension implements MetricExtension {
private static final Logger log = LoggerFactory.getLogger(LinuxNetstatExtension.class); private static final Logger log = LoggerFactory.getLogger(LinuxNetstatExtension.class);
// Extension details
private final String name = "linux_network_netstat";
private final String provides = "network_netstat";
private final String description = "Linux Netstat Metrics";
// Configuration / Options
private boolean enabled = true;
@Override
public boolean isEnabled() {
return enabled;
}
@Override @Override
public boolean isSupported() { public boolean isSupported() {
@ -37,17 +51,24 @@ public class LinuxNetstatExtension implements MetricExtension {
@Override @Override
public String getName() { public String getName() {
return "linux_network_netstat"; return name;
} }
@Override @Override
public String getProvides() { public String getProvides() {
return "network_netstat"; return provides;
} }
@Override @Override
public String getDescription() { public String getDescription() {
return "Linux Netstat Metrics"; return description;
}
@Override
public void setConfiguration(Map<String, Object> map) {
if (map.containsKey("enabled")) {
enabled = (boolean) map.get("enabled");
}
} }
@Override @Override
@ -63,7 +84,7 @@ public class LinuxNetstatExtension implements MetricExtension {
} }
log.debug(fieldsMap.toString()); log.debug(fieldsMap.toString());
return new MetricResult(getName(), new Measurement(tagsMap, fieldsMap)); return new MetricResult(name, new Measurement(tagsMap, fieldsMap));
} }

View file

@ -8,7 +8,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
public class LinuxNetstatParser { public class LinuxNetstatParser {

View file

@ -5,7 +5,6 @@ import org.slf4j.LoggerFactory;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;

View file

@ -17,6 +17,20 @@ public class LinuxSockstatExtension implements MetricExtension {
private static final Logger log = LoggerFactory.getLogger(LinuxSockstatExtension.class); private static final Logger log = LoggerFactory.getLogger(LinuxSockstatExtension.class);
// Extension details
private final String name = "linux_network_sockets";
private final String provides = "network_sockets";
private final String description = "Linux Network Socket Metrics";
// Configuration / Options
private boolean enabled = true;
@Override
public boolean isEnabled() {
return enabled;
}
@Override @Override
public boolean isSupported() { public boolean isSupported() {
@ -30,17 +44,24 @@ public class LinuxSockstatExtension implements MetricExtension {
@Override @Override
public String getName() { public String getName() {
return "linux_network_sockets"; return name;
} }
@Override @Override
public String getProvides() { public String getProvides() {
return "network_sockets"; return provides;
} }
@Override @Override
public String getDescription() { public String getDescription() {
return "Linux Network Socket Metrics"; return description;
}
@Override
public void setConfiguration(Map<String, Object> map) {
if (map.containsKey("enabled")) {
enabled = (boolean) map.get("enabled");
}
} }
@Override @Override
@ -52,7 +73,7 @@ public class LinuxSockstatExtension implements MetricExtension {
HashMap<String, Object> fieldsMap = sockStat.getFields(); HashMap<String, Object> fieldsMap = sockStat.getFields();
log.debug(fieldsMap.toString()); log.debug(fieldsMap.toString());
return new MetricResult(getName(), new Measurement(tagsMap, fieldsMap)); return new MetricResult(name, new Measurement(tagsMap, fieldsMap));
} }

View file

@ -28,7 +28,7 @@ def projectName = "sysmon-server"
application { application {
// Define the main class for the application. // Define the main class for the application.
mainClass.set('sysmon.server.Application') mainClass.set('sysmon.server.Application')
applicationDefaultJvmArgs = [ "-server", "-XX:+UseG1GC", "-Xmx128m" ] applicationDefaultJvmArgs = [ "-server", "-Xms64m", "-Xmx128m", "-XX:+UseG1GC" ]
} }
tasks.named('test') { tasks.named('test') {

View file

@ -2,8 +2,10 @@
Description=Sysmon Server Service Description=Sysmon Server Service
[Service] [Service]
TimeoutStartSec=0 #User=nobody
Restart=always #Group=nobody
TimeoutSec=20
Restart=on-failure
ExecStart=/opt/sysmon/server/bin/server ExecStart=/opt/sysmon/server/bin/server
[Install] [Install]

View file

@ -2,9 +2,7 @@ package sysmon.server;
import org.apache.camel.main.Main; import org.apache.camel.main.Main;
import org.influxdb.InfluxDB; import org.influxdb.InfluxDB;
import org.influxdb.InfluxDBException;
import org.influxdb.InfluxDBFactory; import org.influxdb.InfluxDBFactory;
import org.influxdb.dto.Query;
import picocli.CommandLine; import picocli.CommandLine;
import java.io.IOException; import java.io.IOException;

View file

@ -2,8 +2,6 @@ package sysmon.server;
import org.apache.camel.Exchange; import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder; import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.influxdb.InfluxDbConstants;
import org.apache.camel.component.jackson.JacksonDataFormat;
import org.apache.camel.model.rest.RestBindingMode; import org.apache.camel.model.rest.RestBindingMode;
import org.apache.camel.spi.Registry; import org.apache.camel.spi.Registry;
import sysmon.shared.MetricResult; import sysmon.shared.MetricResult;
@ -39,7 +37,7 @@ public class ServerRouteBuilder extends RouteBuilder {
.route() .route()
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(202)) .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(202))
.setHeader("Content-Type", constant("application/x-www-form-urlencoded")) .setHeader("Content-Type", constant("application/x-www-form-urlencoded"))
.to("seda:inbound") .to("seda:inbound?discardWhenFull=true")
.endRest(); .endRest();
fromF("seda:inbound?concurrentConsumers=%s", threads) fromF("seda:inbound?concurrentConsumers=%s", threads)

View file

@ -2,14 +2,18 @@ package sysmon.shared;
import org.pf4j.ExtensionPoint; import org.pf4j.ExtensionPoint;
import java.util.Map;
public interface MetricExtension extends ExtensionPoint { public interface MetricExtension extends ExtensionPoint {
boolean isEnabled();
boolean isSupported(); boolean isSupported();
String getName(); String getName();
String getProvides(); String getProvides();
String getDescription(); String getDescription();
void setConfiguration(Map<String, Object> map);
MetricResult getMetrics() throws Exception; MetricResult getMetrics() throws Exception;
} }

View file

@ -3,7 +3,6 @@ package sysmon.shared;
import java.io.Serializable; import java.io.Serializable;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
public class MetricResult implements Serializable { public class MetricResult implements Serializable {