基於JRobin的磁盤IO監控

基於JRobin的磁盤IO監控

作者:終南   <[email protected]>

 

先列以下以前寫過的文章作爲參考:

1。JRobin簡介

2。基於JRobin的網絡監控管理,以及基於JRobin的CPU使用率監控

3。磁盤IO性能監控(Linux 和 Windows)

這些文章介紹了JRobin、利用JRobin以及WIndows腳本技術監控網絡和CPU使用率,以及如何獲取Linux以及Windows下磁盤IO性能數據。將這些結合在一起,於是就有了使用Java語言寫成的基於JRobin的磁盤IO監控代碼。

監控程序的代碼與利用ping監控網絡和監控CPU基本類似,但是還是有一些不同:

1。由於可能有多個邏輯磁盤,因此需要先獲取磁盤列表,然後才即每個磁盤的IO數據。

2。出於性能考慮,特別是在Windows下,在獲取磁盤IO數據時,可以在執行腳本時一次性採集這些數據,根據磁盤名稱保存,不用分別獲取,這樣可以提高性能。

3。數據的單位和顯示在圖形上的格式不同。

4。JRobin對數據源名稱及其程度有要求,因此需要對磁盤名稱進行一定的變更。

成果:

35d00c51c2571f06377abe5d.jpg

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();
}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章