基於JRobin的網絡監控管理

基於JRobin的網絡監控管理

 

作者:終南   <[email protected]>

 

在網絡環境下,Ping是一個很重要的命令,通常用來檢測遠程的機器是否能夠連通以及連接的質量如何。如果定時Ping一些機器,然後將響應時間在時間軸上畫成圖像,那就能非常直觀的顯示出網絡信息,達到減脂網絡的目的。

JRobin是一個很好的存儲和用圖形展示基於時間序列數據的工具。可以使用Java編寫代碼將操作系統中的Ping命令與JRobin結合起來,通過Ping命令獲取數據信息,用JRobin保存和以圖形方式顯示Ping的響應時間,從而開發出一個簡單的網絡監視工具。

 

1、Ping

Ping命令的用法很簡單,一般在其後接目標機器的域名或IP地址。不過Windows和Linux下的用法有所不同:

(1)在Windows下,執行 ping www.baidu.com 命令後,連續Ping四次,然後返回結果;在Linux下,執行同樣的命令好,一直Ping下去,直到使用Ctrl+C終止該命令。

(2)在Windows下,通過 -n 來指定Ping的次數;在Linux下,使用 -c 選項。

 

2、JRobin

JRobin的介紹可以參考:

(1)JRobin網站:http://www.jrobin.org/

(2)JRobin簡介:http://hi.baidu.com/li_zhongnan/blog/item/6fef0499a408940d6e068cbf.html

 

3、在Java中的實現機制:

(1)獲取Ping響應時間:通過ProcessBuilder創建一個代表外部Ping命令的Process,啓動Process執行Ping命令,獲取Ping命令的標準輸出,對標準輸出進行解析,取出響應時間數據。如果需要能在Windows和Linux平臺上執行,可以通過環境變量判斷平臺然後選擇針對不同的平臺、帶不同的參數、執行不同的命令、用不同的方法解析命令輸出,最終輸出相同的結果。

在Java中執行外部命令可以參考:http://hi.baidu.com/li_zhongnan/blog/item/318effa9611d2bf91f17a26a.html

(2)保存歷史數據:使用JRobin的機制來保存Ping的歷史數據。

(3)定時執行:將執行Ping命令獲取響應時間、保存相應時間數據到JRobin封裝在一個函數,在TimerTask中調用該函數,通過Timer調度來定時執行。

(4)生成圖形:使用JRobin來生成Ping響應時間圖形。

(5)擴展性考慮:

a. 通過參數設置多個需要監視的對象,可以對多個域名或IP地址進行監視並將數據畫在衣服圖上;

b. 可以指定數據和圖形的保存目錄;

c. 提供啓動和停止監視的功能;

d. 可以隨時調用生成圖形的操作,從而可以實現實時監控的功能。

 

4、看看成果:

 

 

5、事例代碼:

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.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 PingMonitor {

public static String[] execute(String command) {
   String[] strs = null;
   File scriptFile = null;
   try {   
    List<String> cmdList = new ArrayList<String>();
    String osName = System.getProperty("os.name");
    if (osName.indexOf("Windows") > -1) {
     cmdList.add("CMD.EXE");
     cmdList.add("/C");
     cmdList.add(command);
    } else {
     scriptFile = File.createTempFile("monitor", ".sh");
     cmdList.add("/bin/bash");

     String fileName = scriptFile.getCanonicalPath();
     PrintWriter writer = new PrintWriter(scriptFile);
     writer.println(command);

     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.1f ms";
private Logger logger = Logger.getLogger(this.getClass().getName());
private String monitorName = "ping";
private String[] hosts = null;
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 PingMonitor(String[] hosts, String dataDir, int step) {
   this.hosts = hosts;
   this.dataDir = dataDir;
   this.step = step;
   this.rrdPath = this.dataDir + File.separator + monitorName + ".rrd";
}

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("Ping 命令響應時間");
    gDef.setVerticalLabel("毫秒");

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

private double getReplyTime(String[] strs) {
   double value = Double.NaN;
   if (strs != null) {
    for (int j = 0; j < strs.length; j++) {
     String str = strs[j];
     int n1 = str.indexOf("time=");
     int n2 = str.indexOf("ms", n1);
     if (n1 > 0 && n2 > n1) {
      String s = str.substring(n1 + "time=".length(), n2).trim();
      try {
       value = Double.parseDouble(s);
      } catch (Exception e) {
      }
      break;
     }
    }
   }
   return value;
}

/**
* Return a HashMap which contains the current value of each data source.
*
* @return the current value of each data source.
*/
public double getValue(String host) {
   String command = "";
   String osName = System.getProperty("os.name");
   if (osName.indexOf("Windows") > -1) {
    command = "ping " + host + " -n 1";

   } else {
    command = "ping " + host + " -c 1";
   }
   return getReplyTime(execute(command));
}

/**
* 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 < hosts.length; i++)
     rrdDef
       .addDatasource(hosts[i], "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);
     for (int i = 0; i < dsNames.length; i++) {
      String dsName = dsNames[i];
      Double value = getValue(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();
     }
   }
}

public static void main(String[] args) {
   String[] hosts = new String[] { "
www.baidu.com", "www.google.cn" };
   PingMonitor p = new PingMonitor(hosts, ".", 10);
   p.start();

   try {
    Thread.sleep(10 * 60 * 1000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }

   p.stop();
   p.generateGraph();
}
}

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