More work on plugins and added some tests.

This commit is contained in:
Mark Nellemann 2021-05-04 12:08:24 +02:00
parent afbf506749
commit 15cf1963b7
14 changed files with 232 additions and 124 deletions

View file

@ -37,7 +37,7 @@ public class Application {
pluginManager.loadPlugins();
pluginManager.startPlugins();
*/
*/
/*
List<PluginWrapper> plugins = pluginManager.getPlugins();

View file

@ -0,0 +1,9 @@
package org.sysmon.agent
import spock.lang.Specification
class AppTest extends Specification {
}

View file

@ -1,12 +0,0 @@
/*
* This Spock specification was generated by the Gradle 'init' task.
*/
package org.sysmon.test
import spock.lang.Specification
class AppTest extends Specification {
}

View file

@ -1,5 +1,21 @@
subprojects {
apply plugin: 'java-library'
apply plugin: 'java'
apply plugin: 'groovy'
dependencies {
testImplementation 'org.spockframework:spock-core:2.0-M4-groovy-3.0'
testImplementation "org.slf4j:slf4j-api:${slf4jVersion}"
testImplementation project(':shared')
implementation project(':shared')
implementation(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}") {
exclude(group: "org.slf4j")
}
annotationProcessor(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}")
implementation "org.slf4j:slf4j-api:${slf4jVersion}"
}
jar {
manifest {
@ -22,6 +38,13 @@ subprojects {
copyJar
}
test {
useJUnitPlatform()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
task customCleanUp(type:Delete) {

View file

@ -1,10 +0,0 @@
dependencies {
// compileOnly important!!! We do not want to put the api into the zip file since the main program has it already!
implementation project(':shared')
implementation(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}") {
exclude(group: "org.slf4j")
}
annotationProcessor(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}")
implementation "org.slf4j:slf4j-api:${slf4jVersion}"
}

View file

@ -1,12 +1,21 @@
package org.sysmon.plugins.sysmon_aix;
import org.pf4j.Extension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sysmon.shared.MetricExtension;
import org.sysmon.shared.MetricMeasurement;
import org.sysmon.shared.MetricResult;
import org.sysmon.shared.PluginHelper;
import java.util.ArrayList;
import java.util.List;
@Extension
public class AixProcessorExtension implements MetricExtension {
private static final Logger log = LoggerFactory.getLogger(AixProcessorExtension.class);
@Override
public boolean isSupported() {
return System.getProperty("os.name").toLowerCase().contains("aix");
@ -19,59 +28,30 @@ public class AixProcessorExtension implements MetricExtension {
@Override
public MetricResult getMetrics() {
return null;
MetricResult result = new MetricResult("processor");
List<String> mpstat = PluginHelper.executeCommand("mpstat", "-a");
List<AixProcessorStat> processorStats = processCommandOutput(mpstat);
for(AixProcessorStat stat : processorStats) {
result.addMetricMeasurement(new MetricMeasurement(String.format("cpu%d", stat.getCpuNum()), stat.getUtilizationPercentage()));
}
return result;
}
protected List<AixProcessorStat> processCommandOutput(List<String> inputLines) {
List<AixProcessorStat> processorStatList = new ArrayList<>();
for(String line : inputLines) {
if(line.matches("^\\s+[0-9]+\\s+.*")) {
processorStatList.add(new AixProcessorStat(line));
}
}
return processorStatList;
}
}
/*
# mpstat -v
System configuration: lcpu=8 ent=0.5 mode=Uncapped
vcpu lcpu us sy wa id pbusy pc VTB(ms)
---- ---- ---- ---- ----- ----- ----- ----- -------
0 12.26 10.89 0.11 76.74 0.00[ 23.1%] 0.00[ 0.0%] 121967
0 10.58 8.53 0.04 5.71 0.00[ 19.1%] 0.00[ 24.9%] -
1 1.32 1.21 0.05 11.16 0.00[ 2.5%] 0.00[ 13.7%] -
2 0.22 0.28 0.01 8.24 0.00[ 0.5%] 0.00[ 8.8%] -
3 0.11 0.19 0.01 11.63 0.00[ 0.3%] 0.00[ 11.9%] -
4 0.01 0.10 0.00 8.34 0.00[ 0.1%] 0.00[ 8.5%] -
5 0.00 0.07 0.00 11.69 0.00[ 0.1%] 0.00[ 11.8%] -
6 0.00 0.13 0.00 8.33 0.00[ 0.1%] 0.00[ 8.5%] -
7 0.01 0.37 0.00 11.63 0.00[ 0.4%] 0.00[ 12.0%] -
# mpstat
System configuration: lcpu=8 ent=0.5 mode=Uncapped
cpu min maj mpc int cs ics rq mig lpa sysc us sy wa id pc %ec lcs
0 1489677 9337 2633 2146943 1160666 30547 3 2951 100 8361624 43 35 0 23 0.00 0.0 1646908
1 336156 2711 383 266244 25376 5494 0 3401 100 1042507 10 9 0 80 0.00 0.0 230605
2 45820 829 377 116004 5984 2326 0 1889 100 474631 3 3 0 94 0.00 0.0 117923
3 46812 699 377 115297 6217 2306 0 1746 100 58549 1 2 0 97 0.00 0.0 117011
4 2786 39 377 112634 1485 1124 0 1143 100 7432 0 1 0 99 0.00 0.0 114271
5 1233 45 377 112032 1369 1111 0 1147 100 7591 0 1 0 99 0.00 0.0 113674
6 25415 238 377 112763 1519 1235 0 1126 100 2403 0 2 0 98 0.00 0.0 114479
7 3596 124 377 193193 1615 1181 0 1123 100 2572 0 3 0 97 0.00 0.0 195104
U - - - - - - - - - - - - 0 100 0.50 100.0 -
ALL 1951495 14022 5278 3175110 1204231 45324 3 14526 100 9957309 0 0 0 100 0.00 0.0 2649975
%ec
(Default, -a flag) The percentage of entitled capacity consumed by the logical processor.
The %ec of the ALL CPU row represents the percentage of entitled capacity consumed.
Because the time base over which this data is computed can vary, the entitled capacity
percentage can sometimes exceed 100%. This excess is noticeable only with small sampling intervals.
The attribute is displayed only in a shared partition.
*/

View file

@ -0,0 +1,61 @@
package org.sysmon.plugins.sysmon_aix;
public class AixProcessorStat {
private final Integer cpuNum;
private final Float userTime;
private final Float systemTime;
private final Float waitTime;
private final Float idleTime;
AixProcessorStat(String procString) {
// 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
String[] splitStr = procString.trim().split("\\s+");
if(splitStr.length != 35) {
throw new UnsupportedOperationException("AIX mpstat CPU string error: " + procString);
}
this.cpuNum = Integer.parseInt(splitStr[0]);
this.userTime = Float.parseFloat(splitStr[23]);
this.systemTime = Float.parseFloat(splitStr[24]);
this.waitTime = Float.parseFloat(splitStr[25]);
this.idleTime = Float.parseFloat(splitStr[26]);
}
public Integer getCpuNum() {
return cpuNum;
}
public Float getUserTime() {
return userTime;
}
public Float getSystemTime() {
return systemTime;
}
public Float getIdleTime() {
return idleTime;
}
public Float getWaitTime() {
return waitTime;
}
public Float getCombinedWorkTime() {
return userTime + systemTime;
}
public Float getCombinedTime() {
return getIdleTime() + getCombinedWorkTime();
}
public float getUtilizationPercentage() {
return 100 - idleTime;
}
}

View file

@ -1,10 +0,0 @@
dependencies {
// compileOnly important!!! We do not want to put the api into the zip file since the main program has it already!
implementation project(':shared')
implementation(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}") {
exclude(group: "org.slf4j")
}
annotationProcessor(group: 'org.pf4j', name: 'pf4j', version: "${pf4jVersion}")
implementation "org.slf4j:slf4j-api:${slf4jVersion}"
}

View file

@ -35,7 +35,7 @@ public class LinuxDiskExtension implements MetricExtension {
try {
copyCurrentValues();
readProcFile();
result.setMeasurementList(calculate());
result.setMetricMeasurementList(calculate());
} catch (IOException e) {
e.printStackTrace();
}

View file

@ -35,7 +35,7 @@ public class LinuxMemoryExtension implements MetricExtension {
MetricResult result = new MetricResult("memory");
try {
result.setMeasurementList(readProcFile());
result.setMetricMeasurementList(readProcFile());
} catch (IOException e) {
e.printStackTrace();
}

View file

@ -2,6 +2,8 @@ package org.sysmon.plugins.sysmon_linux;
import org.pf4j.Extension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sysmon.shared.MetricExtension;
import org.sysmon.shared.MetricMeasurement;
import org.sysmon.shared.MetricResult;
@ -16,58 +18,40 @@ import java.util.List;
@Extension
public class LinuxProcessorExtension implements MetricExtension {
private static final Logger log = LoggerFactory.getLogger(LinuxProcessorExtension.class);
private List<LinuxProcessorStat> currentProcessorStats;
private List<LinuxProcessorStat> previousProcessorStats;
@Override
public boolean isSupported() {
return System.getProperty("os.name").toLowerCase().contains("linux");
}
@Override
public String getGreeting() {
return "Welcome from Linux ProcessorMetric";
}
@Override
public MetricResult getMetrics() {
MetricResult result = new MetricResult("processor");
try {
copyCurrentValues();
readProcFile();
result.setMeasurementList(calculate());
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
private void readProcFile() throws IOException {
currentProcessorStats = new ArrayList<>();
List<String> allLines = Files.readAllLines(Paths.get("/proc/stat"), StandardCharsets.UTF_8);
for(String line : allLines) {
if(line.startsWith("cpu")) {
currentProcessorStats.add(new LinuxProcessorStat(line));
}
}
}
private void copyCurrentValues() {
if(currentProcessorStats != null && currentProcessorStats.size() > 0) {
previousProcessorStats = new ArrayList<>(currentProcessorStats);
}
MetricResult result = new MetricResult("processor");
currentProcessorStats = processFileOutput(readProcFile());
result.setMetricMeasurementList(calculateDifference());
return result;
}
private List<MetricMeasurement> calculate() {
private List<MetricMeasurement> calculateDifference() {
List<MetricMeasurement> measurementList = new ArrayList<>();
@ -92,6 +76,34 @@ public class LinuxProcessorExtension implements MetricExtension {
return measurementList;
}
protected List<String> readProcFile() {
List<String> allLines = new ArrayList<>();
try {
allLines = Files.readAllLines(Paths.get("/proc/stat"), StandardCharsets.UTF_8);
} catch (IOException e) {
log.error(e.getMessage());
}
return allLines;
}
protected List<LinuxProcessorStat> processFileOutput(List<String> inputLines) {
List<LinuxProcessorStat> processorStats = new ArrayList<>();
for(String line : inputLines) {
if(line.matches("^cpu\\d+.*")) {
processorStats.add(new LinuxProcessorStat(line));
}
}
return processorStats;
}
}

View file

@ -1,5 +0,0 @@
package org.sysmon.shared;
public interface AixPlugin {
}

View file

@ -14,10 +14,13 @@ public class MetricResult {
this.timestamp = Instant.now();
}
public void setMeasurementList(List<MetricMeasurement> measurementList) {
public void setMetricMeasurementList(List<MetricMeasurement> measurementList) {
this.measurementList = measurementList;
}
public void addMetricMeasurement(MetricMeasurement measurement) {
measurementList.add(measurement);
}
public String toString() {
StringBuilder sb = new StringBuilder(String.format("%s - %s\n", timestamp.toString(), name));

View file

@ -0,0 +1,57 @@
package org.sysmon.shared;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class PluginHelper {
final static boolean isWindows = System.getProperty("os.name")
.toLowerCase().startsWith("windows");
public static List<String> executeCommand(String... cmd) {
List<String> outputLines = new ArrayList<>();
ProcessBuilder builder = new ProcessBuilder();
if (isWindows) {
builder.command("cmd.exe", "/c");
} else {
builder.command("sh", "-c");
}
for(String c : cmd) {
builder.command().add(c);
}
builder.directory(new File(System.getProperty("user.home")));
try {
Process process = builder.start();
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
outputLines.add(line);
}
int exitCode = process.waitFor();
System.out.println("\nExited with error code : " + exitCode);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return outputLines;
}
}