![]() |
|||||||||||||||||
|
Working exampleThe following application monitors the CPU load of a workstation (or any other SNMP capable device) and stores its data in a single RRD file (named load.rrd). At the same time this application creates four different graphs (load-daily.png, load-weekly.png, load-monthly.png and load-yearly.png) showing the CPU load for the last day, week, month and year. Once started it runs until the end of the world and recreates all graphs every five minutes. RRD file and graphs will be created under jrobin-demo subdirectory of your home directory:
Since Java has no API to read CPU load directly, it has to get it from somewhere else. This application obtains CPU load from a SNMP agent running on the same machine (localhost). Without this agent the demo will genereate only a huge number of IOExceptions. If you don't know how to install and run a SNMP agent, download the code and documentation from the NET-SNMP project. Be sure that the constants SNMP_HOST, SNMP_PORT and SNMP_COMMUNITY match the configuration of your running agent. Application assumes that the CPU load is available at OID enterprises.ucdavis.laTable.laEntry.laLoad.1 (1.3.6.1.4.1.2021.10.1.3.1). Adjust this OID if necessary by setting appropriate value for the SNMP_CPU_LOAD_OID constant. The code is quite self-explanatory with many comments: it should demonstrate how easy it is to establish a bacis JRobin framework for complex everyday tasks. Put the following code in a file named CpuLoadMonitor.java: import snmp.*; import java.net.*; import java.io.*; import java.awt.*; import java.util.Date; import org.jrobin.core.*; import org.jrobin.graph.*; public class CpuLoadMonitor { // SNMP access parameters public static final String SNMP_HOST = "localhost"; public static final int SNMP_PORT = 161; public static final String SNMP_COMMUNITY = "public"; // CPU Load OID: enterprises.ucdavis.laTable.laEntry.laLoad.1 public static final String SNMP_CPU_LOAD_OID = "1.3.6.1.4.1.2021.10.1.3.1"; // All files and graphs will be created in jrobin-demo subdirectory // of your HOME directory. // // On Linux: ~/jrobin-demo // On Windows: C:\Documents and Settings\Administrator\jrobin-demo // RRD file path public static final String RRD_FILE = "load.rrd"; // Image file paths public static final String IMAGE_DAILY = "load-daily.png"; public static final String IMAGE_WEEKLY = "load-weekly.png"; public static final String IMAGE_MONTHLY = "load-monthly.png"; public static final String IMAGE_YEARLY = "load-yearly.png"; // SNMP sampling resolution public static final int SNMP_RESOLUTION = 60; // seconds // Graph will be recreated each 5 minutes (300 seconds) public static final int GRAPH_RESOLUTION = 300; // seconds // SNMP communicator object SNMPv1CommunicationInterface comm; // pool of open RRD files (we have just a single one, but who cares) RrdDbPool rrdPool = RrdDbPool.getInstance(); public CpuLoadMonitor() throws IOException, RrdException { createSnmpCommObject(); createRrdFileIfNecessary(); startSnmpThread(); startGraphingThread(); } // creates SNMP communicator object private void createSnmpCommObject() throws IOException { InetAddress snmpHost = InetAddress.getByName(SNMP_HOST); comm = new SNMPv1CommunicationInterface(0, snmpHost, SNMP_COMMUNITY, SNMP_PORT); } // creates RRD file only if it does not exist private void createRrdFileIfNecessary() throws RrdException, IOException { String rrdPath = Util.getJRobinDemoPath(RRD_FILE); File rrdFile = new File(rrdPath); if(!rrdFile.exists()) { // create RRD file since it does not exist RrdDef rrdDef = new RrdDef(rrdPath, SNMP_RESOLUTION); // single gauge datasource, named 'load' rrdDef.addDatasource("load", "GAUGE", 5 * SNMP_RESOLUTION, 0, Double.NaN); // several archives rrdDef.addArchive("AVERAGE", 0.5, 1, 4000); rrdDef.addArchive("AVERAGE", 0.5, 6, 4000); rrdDef.addArchive("AVERAGE", 0.5, 24, 4000); rrdDef.addArchive("AVERAGE", 0.5, 288, 4000); // create RRD file in the pool RrdDb rrdDb = rrdPool.requestRrdDb(rrdDef); rrdPool.release(rrdDb); } } // creates and starts SNMP thread private void startSnmpThread() { // create thread Runnable snmpThread = new Runnable() { public void run() { // until the end of the world for(;;) { try { // read SNMP value SNMPVarBindList varList = comm.getMIBEntry(SNMP_CPU_LOAD_OID); SNMPSequence pair = (SNMPSequence)(varList.getSNMPObjectAt(0)); // get CPU load as a string String cpuLoadString = pair.getSNMPObjectAt(1).toString().trim(); // convert CPU load to double double cpuLoad = Double.parseDouble(cpuLoadString); // request RRD database reference from the pool RrdDb rrdDb = rrdPool.requestRrdDb( Util.getJRobinDemoPath(RRD_FILE)); // create sample with the current timestamp Sample sample = rrdDb.createSample(); // set value for load datasource sample.setValue("load", cpuLoad); // update database sample.update(); // release RRD database reference rrdPool.release(rrdDb); // wait for a while Thread.sleep(SNMP_RESOLUTION * 1000L); } catch (IOException e) { reportException(e); } catch (SNMPBadValueException e) { reportException(e); } catch (SNMPGetException e) { reportException(e); } catch (RrdException e) { reportException(e); } catch (InterruptedException e) { reportException(e); } } } }; // start SNMP thread new Thread(snmpThread).start(); } private void startGraphingThread() throws RrdException { // create common part of graph definition // time span will be set later final RrdGraphDef graphDef = new RrdGraphDef(); graphDef.datasource("load", Util.getJRobinDemoPath(RRD_FILE), "load", "AVERAGE"); graphDef.area("load", Color.RED, "CPU load@L"); graphDef.gprint("load", "AVERAGE", "Average CPU load: @3@r"); graphDef.comment("JRobin :: RRDTool Choice for the Java World@l"); // create graphing thread Runnable graphThread = new Runnable() { public void run() { // until the end of the world for(;;) { // ending timestamp is the current timestamp // starting timestamp will be adjusted for each graph long startTime, endTime = Util.getTime(); RrdGraph rrdGraph; try { // daily graph startTime = endTime - 86400; graphDef.setTimePeriod(startTime, endTime); graphDef.setTitle("CPU Load - 1 day"); rrdGraph = new RrdGraph(graphDef, true); // uses pool rrdGraph.saveAsPNG(Util.getJRobinDemoPath(IMAGE_DAILY)); // weekly graph startTime = endTime - 86400 * 7; graphDef.setTimePeriod(startTime, endTime); graphDef.setTitle("CPU Load - 1 week"); rrdGraph = new RrdGraph(graphDef, true); // uses pool rrdGraph.saveAsPNG(Util.getJRobinDemoPath(IMAGE_WEEKLY)); // monthly graph startTime = endTime - 86400 * 31; graphDef.setTimePeriod(startTime, endTime); graphDef.setTitle("CPU Load - 1 month"); rrdGraph = new RrdGraph(graphDef, true); // uses pool rrdGraph.saveAsPNG(Util.getJRobinDemoPath(IMAGE_MONTHLY)); // yearly graph startTime = endTime - 86400 * 366; graphDef.setTimePeriod(startTime, endTime); graphDef.setTitle("CPU Load - 1 year"); rrdGraph = new RrdGraph(graphDef, true); // uses pool rrdGraph.saveAsPNG(Util.getJRobinDemoPath(IMAGE_YEARLY)); // sleep for a while Thread.sleep(GRAPH_RESOLUTION * 1000L); } catch (RrdException e) { reportException(e); } catch (IOException e) { reportException(e); } catch (InterruptedException e) { reportException(e); } } } }; // start graphing thread new Thread(graphThread).start(); } // reports exception by printing it on the stderr device private static void reportException(Exception e) { System.err.println("ERROR [" + new Date() + "]: " + e); } public static void main(String[] args) throws IOException, RrdException { new CpuLoadMonitor(); } } To compile this code, you have to specify two external libraries in the classpath:
Both libraries are provided with the latest JRobin distribution. Compile the code by executing the following command from the command line: javac -classpath jrobin-{version}.jar:snmp-1.3.jar CpuLoadMonitor.java To run the application, execute: nohup java \ -Djava.awt.headless=true \ -cp .:jrobin-{version}.jar:snmp-1.3.jar \ CpuLoadMonitor & The second line (-D switch) is necessary only if you run this application without X-windows up and running (common situation on many newtwork servers). Once application is started, give it some time to produce some meaningful graphs (half an hour should be fair enough). If everything runs as expected, the daily graph should look like this one: That Linux box is obviously idle most of the time :)
Copyright © 2003, 2004 Sasa Markovic & Arne Vandamme. All Rights Reserved. |