Work on AIX disk stats.

This commit is contained in:
Mark Nellemann 2021-05-13 21:53:28 +02:00
parent 888cdf8dad
commit 66cd7c735b
12 changed files with 144 additions and 23 deletions

View file

@ -11,12 +11,10 @@ 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.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; 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 {
@ -48,7 +46,8 @@ public class ClientRouteBuilder extends RouteBuilder {
providers.add(provides); providers.add(provides);
// Setup Camel route for this extension // Setup Camel route for this extension
from("timer:collect?fixedRate=true&period=30s") // a unique timer name gives the timer it's own thread, otherwise it's a shared thread for other timers with same name.
from("timer:"+provides+"?fixedRate=true&period=10s")
.bean(ext, "getMetrics") .bean(ext, "getMetrics")
//.doTry() //.doTry()
.process(new MetricEnrichProcessor(registry)) .process(new MetricEnrichProcessor(registry))

View file

@ -1,17 +1,35 @@
package org.sysmon.plugins.sysmon_aix; package org.sysmon.plugins.sysmon_aix;
import org.pf4j.Extension; import org.pf4j.Extension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sysmon.shared.Measurement;
import org.sysmon.shared.MetricExtension; import org.sysmon.shared.MetricExtension;
import org.sysmon.shared.MetricResult; import org.sysmon.shared.MetricResult;
import org.sysmon.shared.PluginHelper;
import java.util.List;
import java.util.Map;
@Extension @Extension
public class AixDiskExtension implements MetricExtension { public class AixDiskExtension implements MetricExtension {
private static final Logger log = LoggerFactory.getLogger(AixProcessorExtension.class);
@Override @Override
public boolean isSupported() { public boolean isSupported() {
// TODO: Implement
//return System.getProperty("os.name").toLowerCase().contains("aix"); if(!System.getProperty("os.name").toLowerCase().contains("aix")) {
return false; log.warn("Requires AIX.");
return false;
}
if(!PluginHelper.canExecute("iostat")) {
log.warn("Requires the 'iostat' command.");
return false;
}
return true;
} }
@Override @Override
@ -26,12 +44,25 @@ public class AixDiskExtension implements MetricExtension {
@Override @Override
public String getDescription() { public String getDescription() {
return "AIX Disk Metrics (TODO)"; return "AIX Disk Metrics";
} }
@Override @Override
public MetricResult getMetrics() { public MetricResult getMetrics() {
return new MetricResult("disk");
List<String> iostat = PluginHelper.executeCommand("iostat -d");
AixDiskStat diskStat = processCommandOutput(iostat);
Map<String, String> tagsMap = diskStat.getTags();
Map<String, Object> fieldsMap = diskStat.getFields();
return new MetricResult("disk", new Measurement(tagsMap, fieldsMap));
} }
protected AixDiskStat processCommandOutput(List<String> inputLines) {
return new AixDiskStat(inputLines);
}
} }

View file

@ -0,0 +1,65 @@
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 AixDiskStat {
private static final Logger log = LoggerFactory.getLogger(AixProcessorStat.class);
// Disks: % tm_act Kbps tps Kb_read Kb_wrtn
// hdisk0 1.0 752.0 81.0 740 12
private final Pattern pattern = Pattern.compile("^(hdisk\\d+)\\s+(\\d+\\.?\\d*)\\s+\\s+(\\d+\\.?\\d*)\\s+\\s+(\\d+\\.?\\d*)\\s+(\\d+)\\s+(\\d+)");
private String device;
private Float tmAct; // Indicates the percentage of time the physical disk/tape was active (bandwidth utilization for the drive).
private Float kbps; // Indicates the amount of data transferred (read or written) to the drive in KB per second.
private Float tps; // Indicates the number of transfers per second that were issued to the physical disk/tape. A transfer is an I/O request to the physical disk/tape. Multiple logical requests can be combined into a single I/O request to the disk. A transfer is of indeterminate size.
private Long kbRead; // The total number of KB read.
private Long kbWritten; // The total number of KB written.
AixDiskStat(List<String> lines) {
for (String line : lines) {
if (line.startsWith("hdisk")) {
Matcher matcher = pattern.matcher(line);
if (matcher.find() && matcher.groupCount() == 6) {
device = matcher.group(1);
tmAct = Float.parseFloat(matcher.group(2));
kbps = Float.parseFloat(matcher.group(3));
tps = Float.parseFloat(matcher.group(4));
kbRead = Long.parseLong(matcher.group(5));
kbWritten = Long.parseLong(matcher.group(6));
break;
}
}
}
}
public Map<String, String> getTags() {
Map<String, String> tags = new HashMap<>();
tags.put("device", device);
return tags;
}
public Map<String, Object> getFields() {
Map<String, Object> fields = new HashMap<>();
fields.put("reads", kbRead * 1024); // from Kb to b
fields.put("writes", kbWritten * 1024); // from Kb to b
return fields;
}
}

View file

@ -38,11 +38,9 @@ public class AixProcessorStat {
AixProcessorStat(List<String> lines) { AixProcessorStat(List<String> lines) {
Pattern p;
for (String line : lines) { for (String line : lines) {
if (line.startsWith("System configuration:")) { if (line.startsWith("System configuration:")) {
p = patternAix;
Matcher matcher = patternAix.matcher(line); Matcher matcher = patternAix.matcher(line);
if (matcher.find() && matcher.groupCount() == 7) { if (matcher.find() && matcher.groupCount() == 7) {
type = matcher.group(1); type = matcher.group(1);

View file

@ -0,0 +1,24 @@
import org.sysmon.plugins.sysmon_aix.AixDiskExtension
import org.sysmon.plugins.sysmon_aix.AixDiskStat
import spock.lang.Specification
class AixDiskTest extends Specification {
void "test AIX iostat output processing"() {
setup:
def testFile = new File(getClass().getResource('/iostat.txt').toURI())
List<String> lines = testFile.readLines("UTF-8")
when:
AixDiskExtension extension = new AixDiskExtension()
AixDiskStat stats = extension.processCommandOutput(lines)
then:
stats.getTags().get("device") == "hdisk0"
stats.getFields().get("reads") == 757760l
stats.getFields().get("writes") == 12288l
}
}

View file

@ -53,7 +53,7 @@ public class LinuxDiskExtension implements MetricExtension {
} }
LinuxDiskProcLine proc2 = processFileOutput(readProcFile()); LinuxDiskProcLine proc2 = processFileOutput(readProcFile());
LinuxDiskStat stat = new LinuxDiskStat(proc2, proc1); LinuxDiskStat stat = new LinuxDiskStat(proc1, proc2);
System.err.println("FOOBAR"); System.err.println("FOOBAR");
return new MetricResult("disk", new Measurement(stat.getTags(), stat.getFields())); return new MetricResult("disk", new Measurement(stat.getTags(), stat.getFields()));
} }

View file

@ -1,6 +1,10 @@
package org.sysmon.plugins.sysmon_linux; package org.sysmon.plugins.sysmon_linux;
public class LinuxDiskProcLine { public class LinuxDiskProcLine {
// Sectors to bytes - each sector is 512 bytes - https://lkml.org/lkml/2015/8/17/269
static final private int SECTOR_BYTE_SIZE = 512;
/* /*
== =================================== == ===================================
1 major number 1 major number
@ -113,12 +117,12 @@ public class LinuxDiskProcLine {
return timeSpentOnIo; return timeSpentOnIo;
} }
public Long getSectorsRead() { public Long getBytesRead() {
return sectorsRead; return sectorsRead * SECTOR_BYTE_SIZE;
} }
public Long getSectorsWritten() { public Long getBytesWritten() {
return sectorsWritten; return sectorsWritten * SECTOR_BYTE_SIZE;
} }
public Long getTimeSpentReading() { public Long getTimeSpentReading() {

View file

@ -21,8 +21,8 @@ public class LinuxDiskStat {
device = proc1.getDevice(); device = proc1.getDevice();
iotime = proc2.getTimeSpentOnIo() - proc1.getTimeSpentOnIo(); iotime = proc2.getTimeSpentOnIo() - proc1.getTimeSpentOnIo();
writes = proc2.getSectorsWritten() - proc1.getSectorsWritten(); writes = proc2.getBytesWritten() - proc1.getBytesWritten();
reads = proc2.getSectorsRead() - proc1.getSectorsRead(); reads = proc2.getBytesRead() - proc1.getBytesRead();
} }

View file

@ -60,7 +60,7 @@ public class LinuxProcessorExtension implements MetricExtension {
LinuxProcessorProcLine proc2 = processFileOutput(readProcFile()); LinuxProcessorProcLine proc2 = processFileOutput(readProcFile());
LinuxProcessorStat stat = new LinuxProcessorStat(proc2, proc1); LinuxProcessorStat stat = new LinuxProcessorStat(proc1, proc2);
return new MetricResult("processor", new Measurement(stat.getTags(), stat.getFields())); return new MetricResult("processor", new Measurement(stat.getTags(), stat.getFields()));
} }

View file

@ -11,7 +11,7 @@ public class LinuxProcessorStat {
private final float idle; private final float idle;
private final float busy; private final float busy;
public LinuxProcessorStat(LinuxProcessorProcLine current, LinuxProcessorProcLine previous) { public LinuxProcessorStat(LinuxProcessorProcLine previous, LinuxProcessorProcLine current) {
long workTime = current.getCombinedTime() - previous.getCombinedTime(); long workTime = current.getCombinedTime() - previous.getCombinedTime();

View file

@ -36,8 +36,8 @@ class LinuxDiskTest extends Specification {
then: then:
diskStat.getTags().get("device") == "nvme0n1" diskStat.getTags().get("device") == "nvme0n1"
diskStat.getFields().get("iotime") == 272l diskStat.getFields().get("iotime") == 272l
diskStat.getFields().get("writes") == 78920l diskStat.getFields().get("writes") == 40407040l
diskStat.getFields().get("reads") == 0l diskStat.getFields().get("reads") == 80896l
} }
} }

View file

@ -6,7 +6,7 @@
7 5 loop5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 5 loop5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
7 6 loop6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 6 loop6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
7 7 loop7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 7 loop7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
259 0 nvme0n1 89537 20714 7233785 14446 44354 46795 4305594 42289 0 79832 58659 0 0 0 0 2078 1923 259 0 nvme0n1 89537 20714 7233943 14446 44354 46795 4305594 42289 0 79832 58659 0 0 0 0 2078 1923
259 1 nvme0n1p1 126 510 7421 38 2 0 2 0 0 84 38 0 0 0 0 0 0 259 1 nvme0n1p1 126 510 7421 38 2 0 2 0 0 84 38 0 0 0 0 0 0
259 2 nvme0n1p2 100 0 7383 20 14 13 216 12 0 100 32 0 0 0 0 0 0 259 2 nvme0n1p2 100 0 7383 20 14 13 216 12 0 100 32 0 0 0 0 0 0
259 3 nvme0n1p3 89207 20204 7213629 14363 42263 46782 4305376 40338 0 79728 54701 0 0 0 0 0 0 259 3 nvme0n1p3 89207 20204 7213629 14363 42263 46782 4305376 40338 0 79728 54701 0 0 0 0 0 0