Measurements simplified again, to ensure influxdb route works.

More work on AIX plugin.
This commit is contained in:
Mark Nellemann 2021-05-10 16:56:56 +02:00
parent ce896b479b
commit a839304525
25 changed files with 271 additions and 224 deletions

View file

@ -9,6 +9,7 @@ plugins {
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}"

View file

@ -4,16 +4,21 @@
package org.sysmon.client; package org.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.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.util.concurrent.Callable; 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;
@ -31,7 +36,12 @@ public class Application implements Callable<Integer> {
public Integer call() throws IOException { public Integer call() throws IOException {
if(hostname == null || hostname.isEmpty()) { if(hostname == null || hostname.isEmpty()) {
hostname = InetAddress.getLocalHost().getHostName(); try {
hostname = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
log.warn(e.getMessage());
hostname = "unknown";
}
} }
Main main = new Main(); Main main = new Main();

View file

@ -27,7 +27,6 @@ public class ClientRouteBuilder extends RouteBuilder {
pluginManager.startPlugins(); pluginManager.startPlugins();
List<MetricExtension> metricExtensions = pluginManager.getExtensions(MetricExtension.class); List<MetricExtension> metricExtensions = pluginManager.getExtensions(MetricExtension.class);
//log.info(String.format("Found %d extensions for extension point '%s':", metricExtensions.size(), MetricExtension.class.getName()));
for (MetricExtension ext : metricExtensions) { for (MetricExtension ext : metricExtensions) {
if(ext.isSupported()) { if(ext.isSupported()) {
log.info(">>> Enabling extension: " + ext.getDescription()); log.info(">>> Enabling extension: " + ext.getDescription());
@ -42,7 +41,6 @@ public class ClientRouteBuilder extends RouteBuilder {
.stop() .stop()
.otherwise() .otherwise()
.to("seda:metrics"); .to("seda:metrics");
} }
} }

View file

@ -20,7 +20,7 @@ public class MetricEnrichProcessor implements Processor {
MetricResult metricResult = exchange.getIn().getBody(MetricResult.class); MetricResult metricResult = exchange.getIn().getBody(MetricResult.class);
// We make sure MetricResults with no measurements are not sent further down the line // We make sure MetricResults with no measurements are not sent further down the line
if(metricResult == null || metricResult.getMeasurements().size() < 1) { if(metricResult == null || metricResult.getMeasurement() == null) {
exchange.setProperty("skip", true); exchange.setProperty("skip", true);
return; return;
} }

View file

@ -47,7 +47,6 @@ subprojects {
task customCleanUp(type:Delete) { task customCleanUp(type:Delete) {
delete "output" delete "output"
//delete files("${buildDir}/test/*.jar")
} }
tasks.clean.dependsOn(tasks.customCleanUp) tasks.clean.dependsOn(tasks.customCleanUp)

View file

@ -24,7 +24,7 @@ public class AixDiskExtension implements MetricExtension {
@Override @Override
public MetricResult getMetrics() { public MetricResult getMetrics() {
return null; return new MetricResult("disk");
} }
} }

View file

@ -8,7 +8,6 @@ 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.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -36,39 +35,18 @@ public class AixProcessorExtension implements MetricExtension {
@Override @Override
public MetricResult getMetrics() { public MetricResult getMetrics() {
MetricResult result = new MetricResult("processor"); List<String> vmstat = PluginHelper.executeCommand("/usr/bin/lparstat 1 1");
List<Measurement> measurementList = new ArrayList<>(); AixProcessorStat processorStat = processCommandOutput(vmstat);
List<String> mpstat = PluginHelper.executeCommand("mpstat", "-a"); Map<String, String> tagsMap = processorStat.getTags();
List<AixProcessorStat> processorStats = processCommandOutput(mpstat); Map<String, Object> fieldsMap = processorStat.getFields();
for(AixProcessorStat stat : processorStats) { return new MetricResult("processor", new Measurement(tagsMap, fieldsMap));
Map<String, String> tagsMap = new HashMap<>();
tagsMap.put("cpu", stat.getName());
// TODO: entitlements as tag or field ?
Map<String, Object> fieldsMap = new HashMap<>();
fieldsMap.put("utilization", stat.getUtilizationPercentage());
measurementList.add(new Measurement(tagsMap, fieldsMap));
}
result.addMeasurements(measurementList);
return result;
} }
protected List<AixProcessorStat> processCommandOutput(List<String> inputLines) { protected AixProcessorStat processCommandOutput(List<String> inputLines) {
List<AixProcessorStat> processorStatList = new ArrayList<>(); return new AixProcessorStat(inputLines);
for(String line : inputLines) {
if(line.matches("^\\s+[0-9]+\\s+.*")) {
processorStatList.add(new AixProcessorStat(line));
}
}
return processorStatList;
} }

View file

@ -1,61 +1,127 @@
package org.sysmon.plugins.sysmon_aix; package org.sysmon.plugins.sysmon_aix;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AixProcessorStat { public class AixProcessorStat {
private final String name; private static final Logger log = LoggerFactory.getLogger(AixProcessorStat.class);
private final Float userTime;
private final Float systemTime;
private final Float waitTime;
private final Float idleTime;
AixProcessorStat(String procString) { private final Pattern pattern = Pattern.compile("^System configuration: type=(\\S+) mode=(\\S+) smt=(\\d+) lcpu=(\\d+) mem=(\\d+)MB psize=(\\d+) ent=(\\d+\\.?\\d*)");
// cpu min maj mpcs mpcr dev soft dec ph cs ics bound rq push S3pull S3grd S0rd S1rd S2rd S3rd S4rd S5rd sysc us sy wa id pc %ec ilcs vlcs S3hrd S4hrd S5hrd %nsp private String type;
String[] splitStr = procString.trim().split("\\s+"); private String mode;
if(splitStr.length != 35) { private Integer smt;
throw new UnsupportedOperationException("AIX mpstat CPU string error: " + procString); private Integer lcpu;
private Integer psize;
private Float ent;
private final Float user; // Indicates the percentage of the entitled processing capacity used while executing at the user level (application).
private final Float sys; // Indicates the percentage of the entitled processing capacity used while executing at the system level (kernel).
private final Float wait; // Indicates the percentage of the entitled processing capacity unused while the partition was idle and had outstanding disk I/O request(s).
private final Float idle; // Indicates the percentage of the entitled processing capacity unused while the partition was idle and did not have any outstanding disk I/O request.
private final Float physc; // Indicates the number of physical processors consumed.
private final Float entc; // Indicates the percentage of the entitled capacity consumed.
private final Float lbusy; // Indicates the percentage of logical processor(s) utilization that occurred while executing at the user and system level.
/*
System configuration: type=Shared mode=Uncapped smt=8 lcpu=8 mem=4096MB psize=19 ent=0.50
%user %sys %wait %idle physc %entc lbusy vcsw phint %nsp %utcyc
----- ----- ------ ------ ----- ----- ------ ----- ----- ----- ------
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) {
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(5));
ent = Float.parseFloat(matcher.group(7));
break;
}
} }
this.name = "cpu" + splitStr[0]; String vmstat = vmstatLines.get(vmstatLines.size() -1);
this.userTime = Float.parseFloat(splitStr[23]); String[] splitStr = vmstat.trim().split("\\s+");
this.systemTime = Float.parseFloat(splitStr[24]); if(splitStr.length != 11) {
this.waitTime = Float.parseFloat(splitStr[25]); throw new UnsupportedOperationException("vmstat string error: " + splitStr.length);
this.idleTime = Float.parseFloat(splitStr[26]); }
this.user = Float.parseFloat(splitStr[0]);
this.sys = Float.parseFloat(splitStr[1]);
this.wait = Float.parseFloat(splitStr[2]);
this.idle = Float.parseFloat(splitStr[3]);
this.physc = Float.parseFloat(splitStr[4]);
this.entc = Float.parseFloat(splitStr[5]);
this.lbusy = Float.parseFloat(splitStr[6]);
} }
public String getName() { public Float getUser() {
return name; return user;
} }
public Float getUserTime() { public Float getSys() {
return userTime; return sys;
} }
public Float getSystemTime() { public Float getIdle() {
return systemTime; return idle;
} }
public Float getIdleTime() { public Float getWait() {
return idleTime; return wait;
} }
public Float getWaitTime() { public Float getPhysc() {
return waitTime; return physc;
} }
public Float getEntc() {
public Float getCombinedWorkTime() { return entc;
return userTime + systemTime;
} }
public Float getCombinedTime() { public Float getLbusy() {
return getIdleTime() + getCombinedWorkTime(); return lbusy;
} }
public float getUtilizationPercentage() { public float getUsage() {
return 100 - idleTime; return 100 - idle;
} }
public Map<String, String> getTags() {
Map<String, String> tags = new HashMap<>();
tags.put("mode", mode);
tags.put("type", type);
return tags;
}
public Map<String, Object> getFields() {
Map<String, Object> fields = new HashMap<>();
fields.put("lcpu", lcpu);
fields.put("ent", ent);
fields.put("user", user);
fields.put("sys", sys);
fields.put("idle", idle);
fields.put("wait", wait);
fields.put("physc", physc);
fields.put("entc", entc);
fields.put("lbusy", lbusy);
return fields;
}
} }

View file

@ -4,24 +4,24 @@ import spock.lang.Specification
class AixProcessorTest extends Specification { class AixProcessorTest extends Specification {
void "test mpstat output processing"() { void "test lparstat output processing"() {
setup: setup:
def testFile = new File(getClass().getResource('/mpstat1.txt').toURI()) def testFile = new File(getClass().getResource('/lparstat.txt').toURI())
List<String> lines = testFile.readLines("UTF-8") List<String> lines = testFile.readLines("UTF-8")
when: when:
AixProcessorExtension extension = new AixProcessorExtension() AixProcessorExtension extension = new AixProcessorExtension()
List<AixProcessorStat> stats = extension.processCommandOutput(lines) AixProcessorStat stats = extension.processCommandOutput(lines)
then: then:
stats[0].getCombinedWorkTime() == 85.1f stats.getUser() == 83.7f
stats[0].getCombinedTime() == 100.0f stats.getSys() == 3.3f
stats[0].getSystemTime() == 18.4f stats.getWait() == 0.0f
stats[0].getUserTime() == 66.7f stats.getIdle() == 13.0f
stats[0].getWaitTime() == 0.0f stats.getFields().get("ent") == 0.50f
stats[0].getIdleTime() == 14.9f
} }
} }

View file

@ -0,0 +1,6 @@
System configuration: type=Shared mode=Uncapped smt=8 lcpu=8 mem=4096MB psize=19 ent=0.50
%user %sys %wait %idle physc %entc lbusy vcsw phint %nsp %utcyc
----- ----- ------ ------ ----- ----- ------ ----- ----- ----- ------
83.7 3.3 0.0 13.0 1.00 199.6 66.4 1288 0 149 32.96

View file

@ -0,0 +1,15 @@
System configuration: lcpu=8 ent=0.5 mode=Uncapped
vcpu lcpu us sy wa id pbusy pc VTB(ms)
---- ---- ---- ---- ----- ----- ----- ----- -------
0 33.51 5.62 0.11 60.77 0.00[ 39.1%] 0.00[ 0.1%] 1784440
0 13.38 3.96 0.05 4.81 0.00[ 17.3%] 0.00[ 22.2%] -
1 8.41 0.72 0.04 7.59 0.00[ 9.1%] 0.00[ 16.8%] -
2 5.19 0.35 0.01 6.45 0.00[ 5.5%] 0.00[ 12.0%] -
3 4.42 0.28 0.01 8.42 0.00[ 4.7%] 0.00[ 13.1%] -
4 0.57 0.07 0.00 7.47 0.00[ 0.6%] 0.00[ 8.1%] -
5 0.51 0.06 0.00 9.28 0.00[ 0.6%] 0.00[ 9.8%] -
6 0.49 0.07 0.00 7.49 0.00[ 0.6%] 0.00[ 8.1%] -
7 0.54 0.10 0.00 9.26 0.00[ 0.6%] 0.00[ 9.9%] -

View file

@ -1,15 +0,0 @@
System configuration: lcpu=8 ent=0.2 mode=Uncapped
cpu min maj mpcs mpcr dev soft dec ph cs ics bound rq push S3pull S3grd S0rd S1rd S2rd S3rd S4rd S5rd sysc us sy wa id pc %ec ilcs vlcs S3hrd S4hrd S5hrd
cpu min maj mpcs mpcr dev soft dec ph cs ics bound rq push S3pull S3grd S0rd S1rd S2rd S3rd S4rd S5rd sysc us sy wa id pc %ec ilcs vlcs S3hrd S4hrd S5hrd %nsp
0 22324631 12995 2450 1 117140 14071941 37427759 4 25044259 445796 1 3 0 0 0 99.9 0.1 0.0 0.0 0.0 0.0 77548535 66.7 18.4 0.0 14.9 0.00 0.1 237843 38774212 100.0 0.0 0.0 150
1 275936 176 7 350 68318 1505 3604407 41 31072 25403 0 0 0 0 0 24.5 75.5 0.0 0.0 0.0 0.0 608541 0.2 0.8 0.0 99.0 0.00 0.0 916 3701367 100.0 0.0 0.0 150
2 4713 1 0 351 58162 833 2400472 13 24152 23991 0 0 0 0 0 0.7 99.3 0.0 0.0 0.0 0.0 1445 0.0 1.0 0.0 99.0 0.00 0.0 163 2483263 100.0 0.0 0.0 150
3 4587 2 0 351 57777 836 2400544 17 24094 23987 0 0 0 0 0 0.7 99.3 0.0 0.0 0.0 0.0 1199 0.0 0.4 0.0 99.6 0.00 0.0 167 2482920 100.0 0.0 0.0 150
4 5 0 0 351 56903 784 2400095 16 23999 23965 0 0 0 0 0 0.0 100.0 0.0 0.0 0.0 0.0 7 0.0 1.0 0.0 99.0 0.00 0.0 153 2481522 100.0 0.0 0.0 150
5 13 0 0 351 57171 815 2399248 12 23965 23962 0 0 0 0 0 0.0 100.0 0.0 0.0 0.0 0.0 0 0.0 0.4 0.0 99.6 0.00 0.0 145 2480922 100.0 0.0 0.0 150
6 23529 102 0 351 56443 805 2401503 6 24217 24124 0 0 0 0 0 0.9 99.1 0.0 0.0 0.0 0.0 461 0.0 1.0 0.0 99.0 0.00 0.0 162 2482459 100.0 0.0 0.0 150
7 1523 75 0 351 56335 783 4150673 11 24209 24040 0 0 0 0 0 1.1 98.9 0.0 0.0 0.0 0.0 471 0.0 0.9 0.0 99.1 0.00 0.0 479 4231232 100.0 0.0 0.0 150
U - - - - - - - - - - - - - - - - - - - - - - - - 0.0 99.9 0.25 99.8 - - - - -
ALL 22634937 13351 2457 2457 528249 14078302 57184701 120 25219967 615268 1 3 0 0 0 99.3 0.7 0.0 0.0 0.0 0.0 78160659 0.0 0.0 0.0 99.9 0.00 0.2 240028 59117897 100.0 0.0 0.0 0

View file

@ -1,15 +0,0 @@
System configuration: lcpu=8 ent=0.2 mode=Uncapped
cpu min maj mpcs mpcr dev soft dec ph cs ics bound rq push S3pull S3grd S0rd S1rd S2rd S3rd S4rd S5rd sysc us sy wa id pc %ec ilcs vlcs S3hrd S4hrd S5hrd
cpu min maj mpcs mpcr dev soft dec ph cs ics bound rq push S3pull S3grd S0rd S1rd S2rd S3rd S4rd S5rd sysc us sy wa id pc %ec ilcs vlcs S3hrd S4hrd S5hrd %nsp
0 22334111 14138 2450 1 117391 14078152 37441241 4 25056579 446411 1 4 0 0 0 99.9 0.1 0.0 0.0 0.0 0.0 77590574 66.7 18.4 0.0 14.9 0.00 0.1 237925 38789423 100.0 0.0 0.0 150
1 275936 176 7 350 68538 1505 3605599 41 31080 25411 0 0 0 0 0 24.5 75.5 0.0 0.0 0.0 0.0 608541 0.2 0.8 0.0 99.0 0.00 0.0 916 3702787 100.0 0.0 0.0 150
2 4713 1 0 351 58375 833 2401267 13 24160 23999 0 0 0 0 0 0.7 99.3 0.0 0.0 0.0 0.0 1445 0.0 1.0 0.0 99.0 0.00 0.0 163 2484279 100.0 0.0 0.0 150
3 4587 2 0 351 57986 836 2401339 17 24102 23995 0 0 0 0 0 0.6 99.4 0.0 0.0 0.0 0.0 1199 0.0 0.4 0.0 99.6 0.00 0.0 167 2483932 100.0 0.0 0.0 150
4 5 0 0 351 57114 786 2400891 16 24007 23973 0 0 0 0 0 0.0 100.0 0.0 0.0 0.0 0.0 7 0.0 1.0 0.0 99.0 0.00 0.0 154 2482537 100.0 0.0 0.0 150
5 13 0 0 351 57379 815 2400045 12 23973 23970 0 0 0 0 0 0.0 100.0 0.0 0.0 0.0 0.0 0 0.0 0.4 0.0 99.6 0.00 0.0 145 2481936 100.0 0.0 0.0 150
6 23529 102 0 351 56651 805 2402300 6 24225 24132 0 0 0 0 0 0.9 99.1 0.0 0.0 0.0 0.0 461 0.0 1.0 0.0 99.0 0.00 0.0 162 2483472 100.0 0.0 0.0 150
7 1523 75 0 351 56544 783 4152029 11 24217 24048 0 0 0 0 0 1.1 98.9 0.0 0.0 0.0 0.0 471 0.0 0.9 0.0 99.1 0.00 0.0 479 4232805 100.0 0.0 0.0 150
U - - - - - - - - - - - - - - - - - - - - - - - - 0.0 99.9 0.25 99.8 - - - - -
ALL 22644417 14494 2457 2457 529978 14084515 57204711 120 25232343 615939 1 4 0 0 0 99.3 0.7 0.0 0.0 0.0 0.0 78202698 0.0 0.0 0.0 99.9 0.00 0.2 240111 59141171 100.0 0.0 0.0 0

View file

@ -0,0 +1,7 @@
System configuration: lcpu=8 mem=4096MB ent=0.50
kthr memory page faults cpu time
----------- --------------------- ------------------------------------ ------------------ ----------------------- --------
r b p avm fre fi fo pi po fr sr in sy cs us sy id wa pc ec hr mi se
2 1 0 633739 130144 0 13 0 0 2 2 7 969 529 0 0 99 0 0.00 0.1 07:53:28

View file

@ -47,7 +47,7 @@ public class LinuxDiskExtension implements MetricExtension {
try { try {
copyCurrentValues(); copyCurrentValues();
readProcFile(); readProcFile();
result.addMeasurements(calculate()); result.setMeasurement(calculate());
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -77,14 +77,15 @@ public class LinuxDiskExtension implements MetricExtension {
} }
private List<Measurement> calculate() { private Measurement calculate() {
List<Measurement> measurementList = new ArrayList<>();
if(previousDiskStats == null || previousDiskStats.size() != currentDiskStats.size()) { if(previousDiskStats == null || previousDiskStats.size() != currentDiskStats.size()) {
return measurementList; return null;
} }
HashMap<String, String> tagsMap = new HashMap<>();
HashMap<String, Object> fieldsMap = new HashMap<>();
for(int i = 0; i < currentDiskStats.size(); i++) { for(int i = 0; i < currentDiskStats.size(); i++) {
LinuxDiskStat curStat = currentDiskStats.get(i); LinuxDiskStat curStat = currentDiskStats.get(i);
@ -98,23 +99,16 @@ public class LinuxDiskExtension implements MetricExtension {
}); });
if(!ignore.get()) { if(!ignore.get()) {
HashMap<String, String> tagsMap = new HashMap<>(); fieldsMap.put(curStat.getDevice() + "_iotime", curStat.getTimeSpentOnIo() - preStat.getTimeSpentOnIo());
tagsMap.put("device", curStat.getDevice()); //fieldsMap.put(curStat.getDevice() + "_readtime", curStat.getTimeSpentReading() - preStat.getTimeSpentReading());
//fieldsMap.put(curStat.getDevice() + "_writetime", curStat.getTimeSpentWriting() - preStat.getTimeSpentWriting());
HashMap<String, Object> fieldsMap = new HashMap<>(); fieldsMap.put(curStat.getDevice() + "_reads", curStat.getSectorsRead() - preStat.getSectorsRead());
fieldsMap.put("iotime", curStat.getTimeSpentOnIo() - preStat.getTimeSpentOnIo()); fieldsMap.put(curStat.getDevice() + "_writes", curStat.getSectorsWritten() - preStat.getSectorsWritten());
fieldsMap.put("readtime", curStat.getTimeSpentReading() - preStat.getTimeSpentReading());
fieldsMap.put("writetime", curStat.getTimeSpentWriting() - preStat.getTimeSpentWriting());
fieldsMap.put("reads", curStat.getSectorsRead() - preStat.getSectorsRead());
fieldsMap.put("writes", curStat.getSectorsWritten() - preStat.getSectorsWritten());
measurementList.add(new Measurement(tagsMap, fieldsMap));
} }
} }
return measurementList; return new Measurement(tagsMap, fieldsMap);
} }
} }

View file

@ -42,7 +42,7 @@ public class LinuxMemoryExtension implements MetricExtension {
MetricResult result = new MetricResult("memory"); MetricResult result = new MetricResult("memory");
try { try {
result.addMeasurements(readProcFile()); result.setMeasurement(readProcFile());
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -51,9 +51,7 @@ public class LinuxMemoryExtension implements MetricExtension {
} }
private List<Measurement> readProcFile() throws IOException { private Measurement readProcFile() throws IOException {
List<Measurement> measurementList = new ArrayList<>();
Map<String, String> tagsMap = new HashMap<>(); Map<String, String> tagsMap = new HashMap<>();
Map<String, Object> fieldsMap = new HashMap<>(); Map<String, Object> fieldsMap = new HashMap<>();
@ -73,8 +71,7 @@ public class LinuxMemoryExtension implements MetricExtension {
} }
measurementList.add(new Measurement(tagsMap, fieldsMap)); return new Measurement(tagsMap, fieldsMap);
return measurementList;
} }
} }

View file

@ -44,31 +44,20 @@ public class LinuxProcessorExtension implements MetricExtension {
@Override @Override
public MetricResult getMetrics() { public MetricResult getMetrics() {
if(currentProcessorProc != null && currentProcessorProc.size() > 0) { LinuxProcessorProcLine proc1 = processFileOutput(readProcFile());
previousProcessorProc = new ArrayList<>(currentProcessorProc);
}
currentProcessorProc = processFileOutput(readProcFile());
MetricResult result = new MetricResult("processor"); try {
if(previousProcessorProc == null || previousProcessorProc.size() != currentProcessorProc.size()) { Thread.sleep(1 * 1000); // TODO: Configure sample collect time
return result; } catch (InterruptedException e) {
log.warn("getMetrics() - sleep interrupted");
return null;
} }
LinuxProcessorProcLine proc2 = processFileOutput(readProcFile());
List<Measurement> measurementList = new ArrayList<>(); LinuxProcessorStat stat = new LinuxProcessorStat(proc2, proc1);
for(int i = 0; i < currentProcessorProc.size(); i++) {
LinuxProcessorStat stat = new LinuxProcessorStat(currentProcessorProc.get(i), previousProcessorProc.get(i));
Map<String, String> tagsMap = new HashMap<>(); return new MetricResult("processor", new Measurement(stat.getTags(), stat.getFields()));
tagsMap.put("cpu", stat.getName());
Map<String, Object> fieldsMap = stat.getFields();
measurementList.add(new Measurement(tagsMap, fieldsMap));
}
result.addMeasurements(measurementList);
return result;
} }
@ -86,16 +75,15 @@ public class LinuxProcessorExtension implements MetricExtension {
} }
protected List<LinuxProcessorProcLine> processFileOutput(List<String> inputLines) { protected LinuxProcessorProcLine processFileOutput(List<String> inputLines) {
List<LinuxProcessorProcLine> processorStats = new ArrayList<>();
for(String line : inputLines) { for(String line : inputLines) {
if(line.matches("^cpu\\d+.*")) { if(line.matches("^cpu\\S+.*")) {
processorStats.add(new LinuxProcessorProcLine(line)); return new LinuxProcessorProcLine(line);
} }
} }
return processorStats; return null;
} }

View file

@ -6,7 +6,11 @@ import java.util.Map;
public class LinuxProcessorStat { public class LinuxProcessorStat {
private final String cpuName; private final String cpuName;
private final float utilizationPercentage; //private final float user;
//private final float sys;
//private final float wait;
//private final float idle;
private final float busy;
public LinuxProcessorStat(LinuxProcessorProcLine current, LinuxProcessorProcLine previous) { public LinuxProcessorStat(LinuxProcessorProcLine current, LinuxProcessorProcLine previous) {
cpuName = current.getCpuName(); cpuName = current.getCpuName();
@ -15,7 +19,9 @@ public class LinuxProcessorStat {
long idleTimeDiff = current.getCombinedIdleTime() - previous.getCombinedIdleTime(); long idleTimeDiff = current.getCombinedIdleTime() - previous.getCombinedIdleTime();
float utilization = (float) (workTimeDiff - idleTimeDiff) / workTimeDiff; float utilization = (float) (workTimeDiff - idleTimeDiff) / workTimeDiff;
utilizationPercentage = (utilization * 100); busy = (utilization * 100);
// TODO: Calculate user, system, idle and wait diff times into percentage.
} }
@ -24,13 +30,18 @@ public class LinuxProcessorStat {
} }
public Float getBusy() {
return busy;
}
public Map<String, String> getTags() {
return new HashMap<>();
}
public Map<String, Object> getFields() { public Map<String, Object> getFields() {
Map<String, Object> fields = new HashMap<>();
HashMap<String, Object> fieldsMap = new HashMap<>(); fields.put("busy", busy);
fieldsMap.put("utilization", utilizationPercentage); return fields;
return fieldsMap;
} }

View file

@ -13,13 +13,13 @@ class LinuxProcessorTest extends Specification {
when: when:
LinuxProcessorExtension extension = new LinuxProcessorExtension() LinuxProcessorExtension extension = new LinuxProcessorExtension()
List<LinuxProcessorProcLine> procLines = extension.processFileOutput(lines) LinuxProcessorProcLine procLine = extension.processFileOutput(lines)
then: then:
procLines[0].getSystemTime() == 4686l procLine.getSystemTime() == 4686l
procLines[0].getUserTime() == 27477l procLine.getUserTime() == 27477l
procLines[0].getIdleTime() == 281276l procLine.getIdleTime() == 281276l
procLines[0].getIoWaitTime() == 252l procLine.getIoWaitTime() == 252l
} }
@ -29,15 +29,14 @@ class LinuxProcessorTest extends Specification {
setup: setup:
def testFile1 = new File(getClass().getResource('/proc1.txt').toURI()) def testFile1 = new File(getClass().getResource('/proc1.txt').toURI())
def testFile2 = new File(getClass().getResource('/proc2.txt').toURI()) def testFile2 = new File(getClass().getResource('/proc2.txt').toURI())
LinuxProcessorProcLine processorProcLine1 = new LinuxProcessorProcLine(testFile1.readLines().get(1)) LinuxProcessorProcLine processorProcLine1 = new LinuxProcessorProcLine(testFile1.readLines().get(0))
LinuxProcessorProcLine processorProcLine2 = new LinuxProcessorProcLine(testFile2.readLines().get(1)) LinuxProcessorProcLine processorProcLine2 = new LinuxProcessorProcLine(testFile2.readLines().get(0))
when: when:
LinuxProcessorStat processorStat = new LinuxProcessorStat(processorProcLine1, processorProcLine2) LinuxProcessorStat processorStat = new LinuxProcessorStat(processorProcLine1, processorProcLine2)
then: then:
processorStat.getName() == "cpu0" processorStat.getBusy() == 38.001614f
processorStat.getFields().get("utilization") == 42.13362f
} }

View file

@ -3,7 +3,7 @@ plugins {
id "com.github.johnrengelman.shadow" version "6.1.0" id "com.github.johnrengelman.shadow" version "6.1.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 {
@ -64,10 +64,15 @@ buildRpm {
os = "LINUX" os = "LINUX"
} }
buildDeb { buildDeb {
dependsOn startShadowScripts dependsOn startShadowScripts
} }
task aixRpm(type: Rpm) {
os "AIX"
}
jar { jar {
manifest { manifest {
attributes( attributes(

View file

@ -2,6 +2,7 @@ package org.sysmon.server;
import org.apache.camel.Exchange; import org.apache.camel.Exchange;
import org.apache.camel.Processor; import org.apache.camel.Processor;
import org.influxdb.dto.BatchPoints;
import org.influxdb.dto.Point; import org.influxdb.dto.Point;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -20,37 +21,32 @@ public class MetricResultToPointProcessor implements Processor {
public void process(Exchange exchange) throws Exception { public void process(Exchange exchange) throws Exception {
MetricResult metricResult = exchange.getIn().getBody(MetricResult.class); MetricResult metricResult = exchange.getIn().getBody(MetricResult.class);
Measurement measurement = metricResult.getMeasurement();
Point.Builder builder = Point.measurement(metricResult.getName()) Point.Builder builder = Point.measurement(metricResult.getName())
.time(metricResult.getTimestamp(), TimeUnit.MILLISECONDS) .time(metricResult.getTimestamp(), TimeUnit.MILLISECONDS)
.tag("hostname", metricResult.getHostname()); .tag("hostname", metricResult.getHostname());
List<Measurement> measurements = metricResult.getMeasurements(); for (Map.Entry<String,String> entry : measurement.getTags().entrySet()) {
for(Measurement measurement : measurements) { log.debug("process() - tag: " + entry.getKey() + "=" + entry.getValue());
builder.tag(entry.getKey(), entry.getValue());
for (Map.Entry<String,String> entry : measurement.getTags().entrySet()) {
log.debug("process() - tag: " + entry.getKey() + "=" + entry.getValue());
builder.tag(entry.getKey(), entry.getValue());
}
for (Map.Entry<String,Object> entry : measurement.getFields().entrySet()) {
log.debug("process() - field: " + entry.getKey() + "=" + entry.getValue());
if(entry.getValue() instanceof Number) {
Number num = (Number) entry.getValue();
builder.addField(entry.getKey(), num);
} else if(entry.getValue() instanceof Boolean) {
Boolean bol = (Boolean) entry.getValue();
builder.addField(entry.getKey(), bol);
} else {
String str = (String) entry.getValue();
builder.addField(entry.getKey(), str);
}
}
} }
for (Map.Entry<String,Object> entry : measurement.getFields().entrySet()) {
log.debug("process() - field: " + entry.getKey() + "=" + entry.getValue());
if(entry.getValue() instanceof Number) {
Number num = (Number) entry.getValue();
builder.addField(entry.getKey(), num);
} else if(entry.getValue() instanceof Boolean) {
Boolean bol = (Boolean) entry.getValue();
builder.addField(entry.getKey(), bol);
} else {
String str = (String) entry.getValue();
builder.addField(entry.getKey(), str);
}
}
exchange.getIn().setBody(builder.build()); exchange.getIn().setBody(builder.build());
} }

View file

@ -36,10 +36,9 @@ public class ServerRouteBuilder extends RouteBuilder {
//from("seda:inbound").log("Got metric from: ${header.component}").to("mock:sink"); //from("seda:inbound").log("Got metric from: ${header.component}").to("mock:sink");
from("seda:inbound") from("seda:inbound")
.log(">>> metric: ${header.hostname} - ${header.metric}") .log(">>> metric: ${header.hostname} - ${body}")
.doTry() .doTry()
.process(new MetricResultToPointProcessor()) .process(new MetricResultToPointProcessor())
.log("${body}")
.to("influxdb://myInfluxConnection?databaseName=sysmon&retentionPolicy=autogen") .to("influxdb://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}")

View file

@ -2,6 +2,7 @@ package org.sysmon.shared;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
public class Measurement { public class Measurement {
@ -13,8 +14,8 @@ public class Measurement {
} }
public Measurement(Map<String, String> tags, Map<String, Object> fields) { public Measurement(Map<String, String> tags, Map<String, Object> fields) {
this.tags = tags; this.tags = Objects.requireNonNull(tags);
this.fields = fields; this.fields = Objects.requireNonNull(fields);
} }
public Map<String, String> getTags() { public Map<String, String> getTags() {
@ -26,10 +27,12 @@ public class Measurement {
} }
public void setTags(Map<String, String> tags) { public void setTags(Map<String, String> tags) {
Objects.requireNonNull(tags);
this.tags = tags; this.tags = tags;
} }
public void setFields(Map<String, Object> fields) { public void setFields(Map<String, Object> fields) {
Objects.requireNonNull(fields);
this.fields = fields; this.fields = fields;
} }

View file

@ -2,8 +2,6 @@ package org.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.List;
import java.util.Map; import java.util.Map;
public class MetricResult implements Serializable { public class MetricResult implements Serializable {
@ -11,9 +9,9 @@ public class MetricResult implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private String name; private String name;
private Long timestamp; // epoch milli
private String hostname; private String hostname;
private List<Measurement> measurements = new ArrayList<>(); private Long timestamp; // epoch milli
private Measurement measurement;
public MetricResult() { public MetricResult() {
} }
@ -23,12 +21,14 @@ public class MetricResult implements Serializable {
this.timestamp = Instant.now().toEpochMilli(); this.timestamp = Instant.now().toEpochMilli();
} }
public void addMeasurements(List<Measurement> measurementList) { public MetricResult(String name, Measurement measurement) {
this.measurements = measurementList; this.name = name;
this.timestamp = Instant.now().toEpochMilli();
this.measurement = measurement;
} }
public void addMeasurement(Measurement measurement) { public void setMeasurement(Measurement measurement) {
measurements.add(measurement); this.measurement = measurement;
} }
public void setHostname(String hostname) { public void setHostname(String hostname) {
@ -55,24 +55,24 @@ public class MetricResult implements Serializable {
return hostname; return hostname;
} }
public List<Measurement> getMeasurements() { public Measurement getMeasurement() {
return measurements; return measurement;
} }
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(String.format("%s - %s\n", timestamp.toString(), name)); StringBuilder sb = new StringBuilder(String.format("%s - %s {", timestamp.toString(), name));
for(Measurement m : measurements) {
for (Map.Entry<String,String> entry : m.getTags().entrySet()) if(measurement != null && measurement.getTags() != null) {
sb.append(entry.getKey() + " : " + entry.getValue()); for (Map.Entry<String, String> entry : measurement.getTags().entrySet())
sb.append(" [").append(entry.getKey()).append(": ").append(entry.getValue()).append("]");
for (Map.Entry<String,Object> entry : m.getFields().entrySet())
sb.append(entry.getKey() + " : " + entry.getValue());
sb.append(m.toString()).append("\n");
} }
return sb.toString(); if(measurement != null && measurement.getFields() != null) {
for (Map.Entry<String,Object> entry : measurement.getFields().entrySet())
sb.append(" [").append(entry.getKey()).append(": ").append(entry.getValue()).append("]");
}
return sb.append(" }").toString();
} }
} }

View file

@ -1,5 +1,8 @@
package org.sysmon.shared; package org.sysmon.shared;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -9,6 +12,8 @@ import java.util.List;
public class PluginHelper { public class PluginHelper {
private static final Logger log = LoggerFactory.getLogger(PluginHelper.class);
final static boolean isWindows = System.getProperty("os.name") final static boolean isWindows = System.getProperty("os.name")
.toLowerCase().startsWith("windows"); .toLowerCase().startsWith("windows");
@ -29,11 +34,9 @@ public class PluginHelper {
} }
builder.directory(new File(System.getProperty("user.home"))); builder.directory(new File(System.getProperty("user.home")));
try { try {
Process process = builder.start(); Process process = builder.start();
BufferedReader reader = BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream())); new BufferedReader(new InputStreamReader(process.getInputStream()));
@ -43,7 +46,9 @@ public class PluginHelper {
} }
int exitCode = process.waitFor(); int exitCode = process.waitFor();
System.out.println("\nExited with error code : " + exitCode); if(exitCode > 0) {
log.warn("executeCommand() - exit code: " + exitCode);
}
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
e.printStackTrace(); e.printStackTrace();