基於JRobin的磁盤IO監控
作者:終南 <[email protected]>
先列以下以前寫過的文章作爲參考:
1。JRobin簡介
2。基於JRobin的網絡監控管理,以及基於JRobin的CPU使用率監控
這些文章介紹了JRobin、利用JRobin以及WIndows腳本技術監控網絡和CPU使用率,以及如何獲取Linux以及Windows下磁盤IO性能數據。將這些結合在一起,於是就有了使用Java語言寫成的基於JRobin的磁盤IO監控代碼。
監控程序的代碼與利用ping監控網絡和監控CPU基本類似,但是還是有一些不同:
1。由於可能有多個邏輯磁盤,因此需要先獲取磁盤列表,然後才即每個磁盤的IO數據。
2。出於性能考慮,特別是在Windows下,在獲取磁盤IO數據時,可以在執行腳本時一次性採集這些數據,根據磁盤名稱保存,不用分別獲取,這樣可以提高性能。
3。數據的單位和顯示在圖形上的格式不同。
4。JRobin對數據源名稱及其程度有要求,因此需要對磁盤名稱進行一定的變更。
成果:
Java代碼:
import java.awt.Color;
import java.awt.Font;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Logger;
import org.jrobin.core.RrdDb;
import org.jrobin.core.RrdDef;
import org.jrobin.core.Sample;
import org.jrobin.graph.RrdGraph;
import org.jrobin.graph.RrdGraphDef;
public class DiskIoMonitor {
String[] disks = null;
public static String[] execute(String[] commands) {
String[] strs = null;
File scriptFile = null;
try {
List<String> cmdList = new ArrayList<String>();
String osName = System.getProperty("os.name");
if (osName.indexOf("Windows") > -1) {
scriptFile = File.createTempFile("monitor", ".vbs");
cmdList.add("CMD.EXE");
cmdList.add("/C");
cmdList.add("CSCRIPT.EXE");
cmdList.add("//NoLogo");
} else {
scriptFile = File.createTempFile("monitor", ".sh");
cmdList.add("/bin/bash");
}
String fileName = scriptFile.getCanonicalPath();
PrintWriter writer = new PrintWriter(scriptFile);
for (int i = 0; i < commands.length; i++) {
writer.println(commands[i]);
}
writer.flush();
writer.close();
cmdList.add(fileName);
writer.flush();
writer.close();
cmdList.add(fileName);
ProcessBuilder pb = new ProcessBuilder(cmdList);
Process p = pb.start();
p.waitFor();
String line = null;
BufferedReader stdout = new BufferedReader(new InputStreamReader(p
.getInputStream()));
List<String> stdoutList = new ArrayList<String>();
while ((line = stdout.readLine()) != null) {
stdoutList.add(line);
}
BufferedReader stderr = new BufferedReader(new InputStreamReader(p
.getErrorStream()));
List<String> stderrList = new ArrayList<String>();
while ((line = stderr.readLine()) != null) {
stderrList.add(line);
}
strs = stdoutList.toArray(new String[0]);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (scriptFile != null)
scriptFile.delete();
}
return strs;
}
private String dataFormat = "%5.1lf%sB";
private Logger logger = Logger.getLogger(this.getClass().getName());
private String monitorName = "diskio";
private String dataDir = ".";
private int step = 10;
private String rrdPath = "";
private Timer timer = new Timer();
private long timeStart = 0;
protected int width = 600;
protected int height = 150;
public DiskIoMonitor() {
this(null);
}
public DiskIoMonitor(String diskName) {
this.rrdPath = this.dataDir + File.separator + monitorName + ".rrd";
disks = getDisks();
if (diskName != null) {
for (int i = 0; i < disks.length; i++) {
if (diskName.equals(disks[i])) {
disks = new String[] { diskName };
break;
}
}
}
if (disks == null)
disks = new String[0];
}
public String generateGraph() {
long timeCur = org.jrobin.core.Util.getTimestamp();
return generateGraph(timeStart, timeCur);
}
public String generateGraph(long start, long end) {
RrdDb rrdDb = null;
try {
Color[] colors = new Color[] { Color.GREEN, Color.BLUE,
Color.MAGENTA, Color.YELLOW, Color.RED, Color.CYAN,
Color.ORANGE, Color.PINK, Color.BLACK };
String graphPath = this.dataDir + File.separator + monitorName
+ ".png";
// create graph
logger.info("Creating graph");
RrdGraphDef gDef = new RrdGraphDef();
gDef.setWidth(width);
gDef.setHeight(height);
gDef.setFilename(graphPath);
gDef.setStartTime(start);
gDef.setEndTime(end);
gDef.setTitle("Disk IO");
gDef.setVerticalLabel("Byte/s");
String[] dsNames = null;
rrdDb = new RrdDb(rrdPath);
dsNames = rrdDb.getDsNames();
for (int i = 0; i < dsNames.length; i++) {
String dsName = dsNames[i];
String legend = dsName;
if (legend == null || legend.equals(""))
legend = dsName;
gDef.datasource(dsName, rrdPath, dsName, "AVERAGE");
gDef.line(dsName, colors[i % colors.length], legend, 2);
gDef.gprint(dsName, "MIN", dataFormat + " Min");
gDef.gprint(dsName, "AVERAGE", dataFormat + " Avg");
gDef.gprint(dsName, "MAX", dataFormat + " Max");
gDef.gprint(dsName, "LAST", dataFormat + " Last//r");
gDef.print(dsName, "MIN", "min" + dsName + " = %.3f");
gDef.print(dsName, "AVERAGE", "avg" + dsName + " = %.3f");
gDef.print(dsName, "MAX", "max" + dsName + " = %.3f");
gDef.print(dsName, "LAST", "last" + dsName + " = %.3f");
}
gDef.setImageInfo("<img src='%s' width='%d' height = '%d'>");
gDef.setPoolUsed(false);
gDef.setImageFormat("png");
gDef.setSmallFont(new Font("Monospaced", Font.PLAIN, 11));
gDef.setLargeFont(new Font("SansSerif", Font.BOLD, 14));
// gDef.setAltYMrtg(true);
// create graph finally
RrdGraph graph = new RrdGraph(gDef);
// logger.info(graph.getRrdGraphInfo().dump());
logger.info("Graph created");
return graph.getRrdGraphInfo().getFilename();
} catch (Exception e) {
logger.warning("Error in generating graph: " + e.getMessage());
} finally {
if (rrdDb != null)
try {
rrdDb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
/**
* Return a HashMap which contains the current value of each data source.
*
* @return the current value of each data source.
*/
public HashMap<String, Double> getValues() {
String osName = System.getProperty("os.name");
if (osName.indexOf("Windows") > -1) {
return getWinDSValues();
} else {
return getLinuxDSValues();
}
}
/**
* Initialization.
*/
public void initialize() throws Exception {
RrdDb rrdDb = null;
try {
rrdDb = new RrdDb(rrdPath);
} catch (Exception e) {
}
if (rrdDb == null) {
logger.info("RRD data is not located in " + rrdPath
+ ", create a new one");
RrdDef rrdDef = new RrdDef(rrdPath, timeStart - 1, step);
for (int i = 0; i < disks.length; i++)
{
rrdDef.addDatasource(disks[i] + "read", "GAUGE", 2 * step, 0, Double.NaN);
rrdDef.addDatasource(disks[i] + "write", "GAUGE", 2 * step, 0, Double.NaN);
}
rrdDef.addArchive("AVERAGE", 0.5, 1, 24 * 3600 / step);
rrdDef.addArchive("AVERAGE", 0.5, 300 / step, 7 * 288);
logger.info("Estimated file size: " + rrdDef.getEstimatedSize());
rrdDb = new RrdDb(rrdDef);
logger.info("RRD file created.");
}
logger.info(monitorName + " RRD Db Defs: " + rrdDb.getRrdDef().dump());
if (rrdDb != null)
rrdDb.close();
}
/**
* Start monitor.
*
* @return true if succeed, else false.
*/
public boolean start() {
logger.info("start to monitor " + monitorName);
try {
timeStart = org.jrobin.core.Util.getTimestamp();
initialize();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
try {
updateData();
} catch (Exception e) {
e.printStackTrace();
logger.severe("Timer running error: " + e.getMessage());
}
}
}, 0, step * 1000);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* Stop monitor.
*/
public void stop() {
timer.cancel();
}
private void updateData() throws Exception {
RrdDb rrdDb = null;
try {
logger.info("update rrd data for " + monitorName);
rrdDb = new RrdDb(rrdPath);
String[] dsNames = rrdDb.getDsNames();
long lastUpdateTime = rrdDb.getLastUpdateTime();
long t = org.jrobin.core.Util.getTimestamp();
if (t > lastUpdateTime) {
rrdDb.setInfo("T=" + t);
Sample sample = rrdDb.createSample();
sample.setTime(t);
HashMap<String, Double> hm = getValues();
System.out.println(hm);
for (int i = 0; i < dsNames.length; i++) {
String dsName = dsNames[i];
Double value = hm.get(dsName);
logger.fine(dsName + " = " + value);
if (value == null)
value = Double.NaN;
sample.setValue(dsName, value);
}
sample.update();
} else {
logger.warning("Bad sample time " + t + "("
+ new Date(t * 1000L) + ")" + new Date()
+ ", the last update time was " + lastUpdateTime + "("
+ new Date(lastUpdateTime * 1000L) + ") - "
+ monitorName);
}
} finally {
if (rrdDb != null)
try {
rrdDb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private String[] getDisks() {
String[] scripts = null;
String osName = System.getProperty("os.name");
if (osName.indexOf("Windows") > -1) {
scripts = new String[] {
"strComputer = /"./"",
"Set objWMIService = GetObject(/"winmgmts:/" _",
" & /"{impersonationLevel=impersonate}!/////" & strComputer & /"//root//cimv2/")",
"Const HARD_DISK = 3",
"Set colDisks = objWMIService.ExecQuery _",
" (/"Select * from Win32_LogicalDisk Where DriveType = /" & HARD_DISK)",
"For Each objDisk in colDisks",
" Wscript.Echo objDisk.DeviceID", "Next" };
} else {
scripts = new String[] { "df | grep /"^//" | awk '{print $1}'" };
}
String[] strs = execute(scripts);
if (strs == null) {
logger.fine("not get disk information");
} else {
logger.fine(strs.length + " disks:");
for (int i = 0; i < strs.length; i++) {
strs[i] = normalizeDiskName(strs[i]);
logger.fine("disk " + i + ": " + strs[i]);
}
}
return strs;
}
private HashMap<String, Double> getWinDSValues() {
HashMap<String, Double> dsValues = new HashMap<String, Double>();
String[] scripts = new String[] {
"strComputer = /"./"",
"Set objWMIService = GetObject(/"winmgmts:/" _",
" & /"{impersonationLevel=impersonate}!/////" & strComputer & /"//root//cimv2/")",
"set objRefresher = CreateObject(/"WbemScripting.SWbemRefresher/")",
"Set colDisks = objRefresher.AddEnum(objWMIService, /"Win32_PerfFormattedData_PerfDisk_LogicalDisk/").objectSet",
"objRefresher.Refresh",
"Wscript.Sleep 2000",
"objRefresher.Refresh",
"For Each objDisk in colDisks",
" Wscript.Echo objDisk.Name & /" /" & objDisk.DiskReadBytesPerSec & /" /" & objDisk.DiskWriteBytesPerSec",
"Next" };
String[] strs = execute(scripts);
if (strs != null && strs.length > 0) {
for (int i = 0; i < strs.length; i++) {
String strValue = strs[i].trim();
String[] values = strValue.split(" ");
if (values.length == 3) {
String diskName = normalizeDiskName(values[0]);
long read = Long.parseLong(values[1]);
long write = Long.parseLong(values[2]);
dsValues.put(diskName + "read", (double) read);
dsValues.put(diskName + "write", (double) write);
}
}
}
return dsValues;
}
private HashMap<String, Double> getLinuxDSValues() {
HashMap<String, Double> dsValues = new HashMap<String, Double>();
String[] scripts = new String[] { "iostat -d -k 2 2" };
String[] strs = execute(scripts);
int count = 0;
if (strs != null && strs.length > 0) {
for (int i = 0; i < strs.length; i++) {
String strValue = replaceSpaces(strs[i].trim());
if (strValue.startsWith("Device:")) {
count++;
continue;
}
if (count == 2) {
String[] values = strValue.split(" ");
if (values.length == 6) {
String diskName = normalizeDiskName(values[0]);
long read = (long) (Double.parseDouble(values[2]) * 1024);
long write = (long) (Double.parseDouble(values[3]) * 1024);
dsValues.put(diskName + "read", (double) read);
dsValues.put(diskName + "write", (double) write);
}
}
}
}
return dsValues;
}
private String replaceSpaces(String str) {
if (str == null)
return "";
String str1;
do {
str1 = str;
str = str.replace("/t", " ");
str = str.replace(" ", " ");
} while (!str1.equals(str));
return str;
}
private String normalizeDiskName(String name) {
String str = "";
str = name.replace(":", "");
String[] strs = str.split("/");
str = strs[strs.length - 1];
str = str.replaceAll("VolGroup", "vg");
str = str.replaceAll("LogVol", "lv");
return str;
}
public static void main(String[] args) {
DiskIoMonitor p = new DiskIoMonitor();
p.start();
try {
Thread.sleep(5 * 60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
p.stop();
p.generateGraph();
}
}