采用highchart js+flot+rrd生成cpu、mem状态监控图

HTML

             <script type="text/javascript" src="../static/js/jquery-1.8.0.min.js"></script>
            <script src="../static/js/highcharts.js"></script>
            <script language='javascript' src='../../src/lib/binaryXHR.js'></script>
            <script language='javascript' src='../../src/lib/rrdFile.js'></script>
            <script type="text/javascript" src="../static/js/get_cpu_mem_data.js"></script>
            <script src="../static/js/highcharts.js"></script>
            <script type="text/javascript" src="../static/js/cpu_memory.js"></script>
            <div class="clearfix">
                <div id="container" ></div>
            </div>

js

binaryXHR.js


/*
 * BinaryFile over XMLHttpRequest
 * Part of the javascriptRRD package
 * Copyright (c) 2009 Frank Wuerthwein, fkw@ucsd.edu
 * MIT License [http://www.opensource.org/licenses/mit-license.php]
 *
 * Original repository: http://javascriptrrd.sourceforge.net/
 *
 * Based on:
 *   Binary Ajax 0.1.5
 *   Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com, http://blog.nihilogic.dk/
 *   MIT License [http://www.opensource.org/licenses/mit-license.php]
 */

// ============================================================
// Exception class
function InvalidBinaryFile(msg) {
  this.message=msg;
  this.name="Invalid BinaryFile";
}

// pretty print
InvalidBinaryFile.prototype.toString = function() {
  return this.name + ': "' + this.message + '"';
}

// =====================================================================
// BinaryFile class
//   Allows access to element inside a binary stream
function BinaryFile(strData, iDataOffset, iDataLength) {
    var data = strData;
    var dataOffset = iDataOffset || 0;
    var dataLength = 0;
    // added 
    var doubleMantExpHi=Math.pow(2,-28);
    var doubleMantExpLo=Math.pow(2,-52);
    var doubleMantExpFast=Math.pow(2,-20);

    var switch_endian = false;

    this.getRawData = function() {
        return data;
    }

    if (typeof strData == "string") {
        dataLength = iDataLength || data.length;

        this.getByteAt = function(iOffset) {
            return data.charCodeAt(iOffset + dataOffset) & 0xFF;
        }
    } else if (typeof strData == "unknown") {
        dataLength = iDataLength || IEBinary_getLength(data);

        this.getByteAt = function(iOffset) {
            return IEBinary_getByteAt(data, iOffset + dataOffset);
        }
    } else {
      throw new InvalidBinaryFile("Unsupported type " + (typeof strData));
    }

    this.getEndianByteAt = function(iOffset,width,delta) {
      if (this.switch_endian) 
        return this.getByteAt(iOffset+width-delta-1);
      else
        return this.getByteAt(iOffset+delta);
    }

    this.getLength = function() {
        return dataLength;
    }

    this.getSByteAt = function(iOffset) {
        var iByte = this.getByteAt(iOffset);
        if (iByte > 127)
            return iByte - 256;
        else
            return iByte;
    }

    this.getShortAt = function(iOffset) {
            var iShort = (this.getEndianByteAt(iOffset,2,1) << 8) + this.getEndianByteAt(iOffset,2,0)
        if (iShort < 0) iShort += 65536;
        return iShort;
    }
    this.getSShortAt = function(iOffset) {
        var iUShort = this.getShortAt(iOffset);
        if (iUShort > 32767)
            return iUShort - 65536;
        else
            return iUShort;
    }
    this.getLongAt = function(iOffset) {
            var iByte1 = this.getEndianByteAt(iOffset,4,0),
                 iByte2 = this.getEndianByteAt(iOffset,4,1),
                 iByte3 = this.getEndianByteAt(iOffset,4,2),
                 iByte4 = this.getEndianByteAt(iOffset,4,3);

        var iLong = (((((iByte4 << 8) + iByte3) << 8) + iByte2) << 8) + iByte1;
        if (iLong < 0) iLong += 4294967296;
        return iLong;
    }
    this.getSLongAt = function(iOffset) {
        var iULong = this.getLongAt(iOffset);
        if (iULong > 2147483647)
            return iULong - 4294967296;
        else
            return iULong;
    }
    this.getStringAt = function(iOffset, iLength) {
        var aStr = [];
        for (var i=iOffset,j=0;i<iOffset+iLength;i++,j++) {
            aStr[j] = String.fromCharCode(this.getByteAt(i));
        }
        return aStr.join("");
    }

    // Added
    this.getCStringAt = function(iOffset, iMaxLength) {
        var aStr = [];
        for (var i=iOffset,j=0;(i<iOffset+iMaxLength) && (this.getByteAt(i)>0);i++,j++) {
            aStr[j] = String.fromCharCode(this.getByteAt(i));
        }
        return aStr.join("");
    }

    // Added
    this.getDoubleAt = function(iOffset) {
            var iByte1 = this.getEndianByteAt(iOffset,8,0),
                 iByte2 = this.getEndianByteAt(iOffset,8,1),
                 iByte3 = this.getEndianByteAt(iOffset,8,2),
                 iByte4 = this.getEndianByteAt(iOffset,8,3),
                 iByte5 = this.getEndianByteAt(iOffset,8,4),
                 iByte6 = this.getEndianByteAt(iOffset,8,5),
                 iByte7 = this.getEndianByteAt(iOffset,8,6),
                 iByte8 = this.getEndianByteAt(iOffset,8,7);
        var iSign=iByte8 >> 7;
        var iExpRaw=((iByte8 & 0x7F)<< 4) + (iByte7 >> 4);
        var iMantHi=((((((iByte7 & 0x0F) << 8) + iByte6) << 8) + iByte5) << 8) + iByte4;
        var iMantLo=((((iByte3) << 8) + iByte2) << 8) + iByte1;

        if (iExpRaw==0) return 0.0;
        if (iExpRaw==0x7ff) return undefined;

        var iExp=(iExpRaw & 0x7FF)-1023;

        var dDouble = ((iSign==1)?-1:1)*Math.pow(2,iExp)*(1.0 + iMantLo*doubleMantExpLo + iMantHi*doubleMantExpHi);
        return dDouble;
    }
    // added
    // Extracts only 4 bytes out of 8, loosing in precision (20 bit mantissa)
    this.getFastDoubleAt = function(iOffset) {
            var iByte5 = this.getEndianByteAt(iOffset,8,4),
             iByte6 = this.getEndianByteAt(iOffset,8,5),
             iByte7 = this.getEndianByteAt(iOffset,8,6),
             iByte8 = this.getEndianByteAt(iOffset,8,7);
        var iSign=iByte8 >> 7;
        var iExpRaw=((iByte8 & 0x7F)<< 4) + (iByte7 >> 4);
        var iMant=((((iByte7 & 0x0F) << 8) + iByte6) << 8) + iByte5;

        if (iExpRaw==0) return 0.0;
        if (iExpRaw==0x7ff) return undefined;

        var iExp=(iExpRaw & 0x7FF)-1023;

        var dDouble = ((iSign==1)?-1:1)*Math.pow(2,iExp)*(1.0 + iMant*doubleMantExpFast);
        return dDouble;
    }

    this.getCharAt = function(iOffset) {
        return String.fromCharCode(this.getByteAt(iOffset));
    }
}


document.write(
    "<script type='text/vbscript'> "
    + "Function IEBinary_getByteAt(strBinary, iOffset) "
    + "    IEBinary_getByteAt = AscB(MidB(strBinary,iOffset+1,1)) "
    + "End Function "
    + "Function IEBinary_getLength(strBinary) "
    + "    IEBinary_getLength = LenB(strBinary) "
    + "End Function "
    + "</script> "
);



// ===============================================================
// Load a binary file from the specified URL 
// Will return an object of type BinaryFile
function FetchBinaryURL(url) {
  var request =  new XMLHttpRequest();
  request.open("GET", url,false);
  try {
    request.overrideMimeType('text/plain; charset=x-user-defined');
  } catch (err) {
    // ignore any error, just to make both FF and IE work
  }
  request.send(null);

  var response=request.responseBody;
  if (response==undefined){ // responseBody is non standard, but the only way to make it work in IE
    response=request.responseText;
  }
  var bf=new BinaryFile(response);
  return bf;
}


// ===============================================================
// Asyncronously load a binary file from the specified URL 
//
// callback must be a function with one or two arguments:
//  - bf = an object of type BinaryFile
//  - optional argument object (used only if callback_arg not undefined) 
function FetchBinaryURLAsync(url, callback, callback_arg) {
  var callback_wrapper = function() {
    if(this.readyState == 4) {
      var response=this.responseBody;
      if (response==undefined){ // responseBody is non standard, but the only way to make it work in IE
    response=this.responseText;
      }
      var bf=new BinaryFile(response);
      if (callback_arg!=null) {
    callback(bf,callback_arg);
      } else {
    callback(bf);
      }
    }
  }

  var request =  new XMLHttpRequest();
  request.onreadystatechange = callback_wrapper;
  request.open("GET", url,true);
  try {
    request.overrideMimeType('text/plain; charset=x-user-defined');
  } catch (err) {
    // ignore any error, just to make both FF and IE work
  }
  request.send(null);
  return request
}
rrdFile.js

/*
 * Client library for access to RRD archive files
 * Part of the javascriptRRD package
 * Copyright (c) 2009-2010 Frank Wuerthwein, fkw@ucsd.edu
 *                         Igor Sfiligoi, isfiligoi@ucsd.edu
 *
 * Original repository: http://javascriptrrd.sourceforge.net/
 * 
 * MIT License [http://www.opensource.org/licenses/mit-license.php]
 *
 */

/*
 *
 * RRDTool has been developed and is maintained by
 * Tobias Oether [http://oss.oetiker.ch/rrdtool/]
 *
 * This software can be used to read files produced by the RRDTool
 * but has been developed independently.
 * 
 * Limitations:
 *
 * This version of the module assumes RRD files created on linux 
 * with intel architecture and supports both 32 and 64 bit CPUs.
 * All integers in RRD files are suppoes to fit in 32bit values.
 *
 * Only versions 3 and 4 of the RRD archive are supported.
 *
 * Only AVERAGE,MAXIMUM,MINIMUM and LAST consolidation functions are
 * supported. For all others, the behaviour is at the moment undefined.
 *
 */

/*
 * Dependencies:
 *   
 * The data provided to this module require an object of a class
 * that implements the following methods:
 *   getByteAt(idx)            - Return a 8 bit unsigned integer at offset idx
 *   getLongAt(idx)            - Return a 32 bit unsigned integer at offset idx
 *   getDoubleAt(idx)          - Return a double float at offset idx
 *   getFastDoubleAt(idx)      - Similar to getDoubleAt but with less precision
 *   getCStringAt(idx,maxsize) - Return a string of at most maxsize characters
 *                               that was 0-terminated in the source
 *
 * The BinaryFile from binaryXHR.js implements this interface.
 *
 */


// ============================================================
// Exception class
function InvalidRRD(msg) {
  this.message=msg;
  this.name="Invalid RRD";
}

// pretty print
InvalidRRD.prototype.toString = function() {
  return this.name + ': "' + this.message + '"';
}


// ============================================================
// RRD DS Info class
function RRDDS(rrd_data,rrd_data_idx,my_idx) {
  this.rrd_data=rrd_data;
  this.rrd_data_idx=rrd_data_idx;
  this.my_idx=my_idx;
}

RRDDS.prototype.getIdx = function() {
  return this.my_idx;
}
RRDDS.prototype.getName = function() {
  return this.rrd_data.getCStringAt(this.rrd_data_idx,20);
}
RRDDS.prototype.getType = function() {
  return this.rrd_data.getCStringAt(this.rrd_data_idx+20,20);
}
RRDDS.prototype.getMin = function() {
  return this.rrd_data.getDoubleAt(this.rrd_data_idx+48);
}
RRDDS.prototype.getMax = function() {
  return this.rrd_data.getDoubleAt(this.rrd_data_idx+56);
}


// ============================================================
// RRD RRA Info class
function RRDRRAInfo(rrd_data,rra_def_idx,
            int_align,row_cnt,pdp_step,my_idx) {
  this.rrd_data=rrd_data;
  this.rra_def_idx=rra_def_idx;
  this.int_align=int_align;
  this.row_cnt=row_cnt;
  this.pdp_step=pdp_step;
  this.my_idx=my_idx;

  // char nam[20], uint row_cnt, uint pdp_cnt
  this.rra_pdp_cnt_idx=rra_def_idx+Math.ceil(20/int_align)*int_align+int_align;
}

RRDRRAInfo.prototype.getIdx = function() {
  return this.my_idx;
}

// Get number of rows
RRDRRAInfo.prototype.getNrRows = function() {
  return this.row_cnt;
}

// Get number of slots used for consolidation
// Mostly for internal use
RRDRRAInfo.prototype.getPdpPerRow = function() {
  return this.rrd_data.getLongAt(this.rra_pdp_cnt_idx);
}

// Get RRA step (expressed in seconds)
RRDRRAInfo.prototype.getStep = function() {
  return this.pdp_step*this.getPdpPerRow();
}

// Get consolidation function name
RRDRRAInfo.prototype.getCFName = function() {
  return this.rrd_data.getCStringAt(this.rra_def_idx,20);
}


// ============================================================
// RRD RRA handling class
function RRDRRA(rrd_data,rra_ptr_idx,
        rra_info,
        header_size,prev_row_cnts,ds_cnt) {
  this.rrd_data=rrd_data;
  this.rra_info=rra_info;
  this.row_cnt=rra_info.row_cnt;
  this.ds_cnt=ds_cnt;

  var row_size=ds_cnt*8;

  this.base_rrd_db_idx=header_size+prev_row_cnts*row_size;

  // get imediately, since it will be needed often
  this.cur_row=rrd_data.getLongAt(rra_ptr_idx);

  // calculate idx relative to base_rrd_db_idx
  // mostly used internally
  this.calc_idx = function(row_idx,ds_idx) {
    if ((row_idx>=0) && (row_idx<this.row_cnt)) {
      if ((ds_idx>=0) && (ds_idx<ds_cnt)){
    // it is round robin, starting from cur_row+1
    var real_row_idx=row_idx+this.cur_row+1;
    if (real_row_idx>=this.row_cnt) real_row_idx-=this.row_cnt;
    return row_size*real_row_idx+ds_idx*8;
      } else {
    throw RangeError("DS idx ("+ row_idx +") out of range [0-" + ds_cnt +").");
      }
    } else {
      throw RangeError("Row idx ("+ row_idx +") out of range [0-" + this.row_cnt +").");
    }    
  }
}

RRDRRA.prototype.getIdx = function() {
  return this.rra_info.getIdx();
}

// Get number of rows/columns
RRDRRA.prototype.getNrRows = function() {
  return this.row_cnt;
}
RRDRRA.prototype.getNrDSs = function() {
  return this.ds_cnt;
}

// Get RRA step (expressed in seconds)
RRDRRA.prototype.getStep = function() {
  return this.rra_info.getStep();
}

// Get consolidation function name
RRDRRA.prototype.getCFName = function() {
  return this.rra_info.getCFName();
}

RRDRRA.prototype.getEl = function(row_idx,ds_idx) {
  return this.rrd_data.getDoubleAt(this.base_rrd_db_idx+this.calc_idx(row_idx,ds_idx));
}

// Low precision version of getEl
// Uses getFastDoubleAt
RRDRRA.prototype.getElFast = function(row_idx,ds_idx) {
  return this.rrd_data.getFastDoubleAt(this.base_rrd_db_idx+this.calc_idx(row_idx,ds_idx));
}

// ============================================================
// RRD Header handling class
function RRDHeader(rrd_data) {
  this.rrd_data=rrd_data;
  this.validate_rrd();
  this.calc_idxs();
}

// Internal, used for initialization
RRDHeader.prototype.validate_rrd = function() {
  if (this.rrd_data.getLength()<1) throw new InvalidRRD("Empty file.");
  if (this.rrd_data.getLength()<16) throw new InvalidRRD("File too short.");
  if (this.rrd_data.getCStringAt(0,4)!=="RRD") throw new InvalidRRD("Wrong magic id.");

  this.rrd_version=this.rrd_data.getCStringAt(4,5);
  if ((this.rrd_version!=="0003")&&(this.rrd_version!=="0004")&&(this.rrd_version!=="0001")) {
    throw new InvalidRRD("Unsupported RRD version "+this.rrd_version+".");
  }

  this.float_width=8;
  if (this.rrd_data.getLongAt(12)==0) {
    // not a double here... likely 64 bit
    this.float_align=8;
    if (! (this.rrd_data.getDoubleAt(16)==8.642135e+130)) {
      // uhm... wrong endian?
      this.rrd_data.switch_endian=true;
    }
    if (this.rrd_data.getDoubleAt(16)==8.642135e+130) {
      // now, is it all 64bit or only float 64 bit?
      if (this.rrd_data.getLongAt(28)==0) {
    // true 64 bit align
    this.int_align=8;
    this.int_width=8;
      } else {
    // integers are 32bit aligned
    this.int_align=4;
    this.int_width=4;
      }
    } else {
      throw new InvalidRRD("Magic float not found at 16.");
    }
  } else {
    /// should be 32 bit alignment
    if (! (this.rrd_data.getDoubleAt(12)==8.642135e+130)) {
      // uhm... wrong endian?
      this.rrd_data.switch_endian=true;
    }
    if (this.rrd_data.getDoubleAt(12)==8.642135e+130) {
      this.float_align=4;
      this.int_align=4;
      this.int_width=4;
    } else {
      throw new InvalidRRD("Magic float not found at 12.");
    }
  }
  this.unival_width=this.float_width;
  this.unival_align=this.float_align;

  // process the header here, since I need it for validation

  // char magic[4], char version[5], double magic_float

  // long ds_cnt, long rra_cnt, long pdp_step, unival par[10]
  this.ds_cnt_idx=Math.ceil((4+5)/this.float_align)*this.float_align+this.float_width;
  this.rra_cnt_idx=this.ds_cnt_idx+this.int_width;
  this.pdp_step_idx=this.rra_cnt_idx+this.int_width;

  //always get only the low 32 bits, the high 32 on 64 bit archs should always be 0
  this.ds_cnt=this.rrd_data.getLongAt(this.ds_cnt_idx);
  if (this.ds_cnt<1) {
    throw new InvalidRRD("ds count less than 1.");
  }

  this.rra_cnt=this.rrd_data.getLongAt(this.rra_cnt_idx);
  if (this.ds_cnt<1) {
    throw new InvalidRRD("rra count less than 1.");
  }

  this.pdp_step=this.rrd_data.getLongAt(this.pdp_step_idx);
  if (this.pdp_step<1) {
    throw new InvalidRRD("pdp step less than 1.");
  }

  // best guess, assuming no weird align problems
  this.top_header_size=Math.ceil((this.pdp_step_idx+this.int_width)/this.unival_align)*this.unival_align+10*this.unival_width;
  var t=this.rrd_data.getLongAt(this.top_header_size);
  if (t==0) {
    throw new InvalidRRD("Could not find first DS name.");
  }
}

// Internal, used for initialization
RRDHeader.prototype.calc_idxs = function() {
  this.ds_def_idx=this.top_header_size;
  // char ds_nam[20], char dst[20], unival par[10]
  this.ds_el_size=Math.ceil((20+20)/this.unival_align)*this.unival_align+10*this.unival_width;

  this.rra_def_idx=this.ds_def_idx+this.ds_el_size*this.ds_cnt;
  // char cf_nam[20], uint row_cnt, uint pdp_cnt, unival par[10]
  this.row_cnt_idx=Math.ceil(20/this.int_align)*this.int_align;
  this.rra_def_el_size=Math.ceil((this.row_cnt_idx+2*this.int_width)/this.unival_align)*this.unival_align+10*this.unival_width;

  this.live_head_idx=this.rra_def_idx+this.rra_def_el_size*this.rra_cnt;
  // time_t last_up, int last_up_usec
  this.live_head_size=2*this.int_width;

  this.pdp_prep_idx=this.live_head_idx+this.live_head_size;
  // char last_ds[30], unival scratch[10]
  this.pdp_prep_el_size=Math.ceil(30/this.unival_align)*this.unival_align+10*this.unival_width;

  this.cdp_prep_idx=this.pdp_prep_idx+this.pdp_prep_el_size*this.ds_cnt;
  // unival scratch[10]
  this.cdp_prep_el_size=10*this.unival_width;

  this.rra_ptr_idx=this.cdp_prep_idx+this.cdp_prep_el_size*this.ds_cnt*this.rra_cnt;
  // uint cur_row
  this.rra_ptr_el_size=1*this.int_width;
  
  this.header_size=this.rra_ptr_idx+this.rra_ptr_el_size*this.rra_cnt;
}

// Optional initialization
// Read and calculate row counts
RRDHeader.prototype.load_row_cnts = function() {
  this.rra_def_row_cnts=[];
  this.rra_def_row_cnt_sums=[]; // how many rows before me
  for (var i=0; i<this.rra_cnt; i++) {
    this.rra_def_row_cnts[i]=this.rrd_data.getLongAt(this.rra_def_idx+i*this.rra_def_el_size+this.row_cnt_idx,false);
    if (i==0) {
      this.rra_def_row_cnt_sums[i]=0;
    } else {
      this.rra_def_row_cnt_sums[i]=this.rra_def_row_cnt_sums[i-1]+this.rra_def_row_cnts[i-1];
    }
  }
}

// ---------------------------
// Start of user functions

RRDHeader.prototype.getMinStep = function() {
  return this.pdp_step;
}
RRDHeader.prototype.getLastUpdate = function() {
  return this.rrd_data.getLongAt(this.live_head_idx,false);
}

RRDHeader.prototype.getNrDSs = function() {
  return this.ds_cnt;
}
RRDHeader.prototype.getDSNames = function() {
  var ds_names=[]
  for (var idx=0; idx<this.ds_cnt; idx++) {
    var ds=this.getDSbyIdx(idx);
    var ds_name=ds.getName()
    ds_names.push(ds_name);
  }
  return ds_names;
}
RRDHeader.prototype.getDSbyIdx = function(idx) {
  if ((idx>=0) && (idx<this.ds_cnt)) {
    return new RRDDS(this.rrd_data,this.ds_def_idx+this.ds_el_size*idx,idx);
  } else {
    throw RangeError("DS idx ("+ idx +") out of range [0-" + this.ds_cnt +").");
  }    
}
RRDHeader.prototype.getDSbyName = function(name) {
  for (var idx=0; idx<this.ds_cnt; idx++) {
    var ds=this.getDSbyIdx(idx);
    var ds_name=ds.getName()
    if (ds_name==name)
      return ds;
  }
  throw RangeError("DS name "+ name +" unknown.");
}

RRDHeader.prototype.getNrRRAs = function() {
  return this.rra_cnt;
}
RRDHeader.prototype.getRRAInfo = function(idx) {
  if ((idx>=0) && (idx<this.rra_cnt)) {
    return new RRDRRAInfo(this.rrd_data,
              this.rra_def_idx+idx*this.rra_def_el_size,
              this.int_align,this.rra_def_row_cnts[idx],this.pdp_step,
              idx);
  } else {
    throw RangeError("RRA idx ("+ idx +") out of range [0-" + this.rra_cnt +").");
  }    
}

// ============================================================
// RRDFile class
//   Given a BinaryFile, gives access to the RRD archive fields
// 
// Arguments:
//   bf must be an object compatible with the BinaryFile interface
//   file_options - currently no semantics... introduced for future expandability
function RRDFile(bf,file_options) {
  this.file_options=file_options;

  var rrd_data=bf

  this.rrd_header=new RRDHeader(rrd_data);
  this.rrd_header.load_row_cnts();

  // ===================================
  // Start of user functions

  this.getMinStep = function() {
    return this.rrd_header.getMinStep();
  }
  this.getLastUpdate = function() {
    return this.rrd_header.getLastUpdate();
  }

  this.getNrDSs = function() {
    return this.rrd_header.getNrDSs();
  }
  this.getDSNames = function() {
    return this.rrd_header.getDSNames();
  }
  this.getDS = function(id) {
    if (typeof id == "number") {
      return this.rrd_header.getDSbyIdx(id);
    } else {
      return this.rrd_header.getDSbyName(id);
    }
  }

  this.getNrRRAs = function() {
    return this.rrd_header.getNrRRAs();
  }

  this.getRRAInfo = function(idx) {
    return this.rrd_header.getRRAInfo(idx);
  }

  this.getRRA = function(idx) {
    rra_info=this.rrd_header.getRRAInfo(idx);
    return new RRDRRA(rrd_data,
              this.rrd_header.rra_ptr_idx+idx*this.rrd_header.rra_ptr_el_size,
              rra_info,
              this.rrd_header.header_size,
              this.rrd_header.rra_def_row_cnt_sums[idx],
              this.rrd_header.ds_cnt);
  }

}

get_cpu_mem_data.js

      rrd_data=undefined;
      var cpu_value,mem_value;
      function get_cpu_mem_val(bf) {
          var i_rrd_data=undefined;
          if (bf.getLength()<1) {
            alert("File is empty (possibly loading failed)!");
            return 1;
          }
          
          try {
            var i_rrd_data=new RRDFile(bf);            
          } catch(err) {
            alert("File is not a valid RRD archive! "+err);
          }
          if (i_rrd_data!=undefined) {
            rrd_data=i_rrd_data;
            var rra=rrd_data.getRRA(0);
            var cpu=rra.getElFast(60-1,0);
            var mem=rra.getElFast(60-1,1);
            if (cpu ==undefined){
                cpu=0;    
            }
            if (mem ==undefined){
                mem=0;    
            }
            cpu_value=cpu;
            mem_value=mem;
           //alert("cpu:"+cpu+"mem:"+mem); 
          }
          else
          {
            var cpu=0;
            var mem=0;
          }
      }

      function get_cpu_mem(){
        fname="../sysstatus.rrd?rand="+Math.random();
        try {
          FetchBinaryURLAsync(fname,get_cpu_mem_val);
            var  data=[{cpu_value:cpu_value,mem_value:mem_value}];
            return data; 
        } catch (err) {
           alert("Failed loading "+fname+" "+err);
        }
      }
      
     function get_cpu_mem_vals(bf) {
          var i_rrd_data=undefined;
          if (bf.getLength()<1) {
            alert("File is empty (possibly loading failed)!");
            return 1;
          }
          
          try {
            var i_rrd_data=new RRDFile(bf);            
          } catch(err) {
            alert("File is not a valid RRD archive! "+err);
          }
          if (i_rrd_data!=undefined) {
            rrd_data=i_rrd_data;
          }
          
          var rra=rrd_data.getRRA(0);
          var rows=rra.getNrRows();
          for (var i=0; i<rows;i++) {
            var cpu=rra.getElFast(i,0);
            var mem=rra.getElFast(i,1);
          }
      }
      function get_cpu_mems(){
        fname="./sysstatus.rrd";
        try {
          FetchBinaryURLAsync(fname,get_cpu_mem_vals);
        } catch (err) {
           alert("Failed loading "+fname+" "+err);
        }
      }

cpu_memory.js

           $(function() {
                Highcharts.setOptions({
                    global: {
                        useUTC: false
                    }
                });
                   var chart;
                $('#container').highcharts({
                    credits:{enabled:false},//不显示Highcharts的链接
                    chart: {
                        type: 'spline',
                        marginRight: 150,
                        marginLeft: 50,
                        marginBottom: 25,
                        animation: Highcharts.svg,
                        
                        events: {
                            load: function() {

                                // 若有第3条线,则添加
                                // var series_other_property = this.series[2]
                                // 并在 series: [] 中添加相应的 (name, data) 对
                                var series_cpu = this.series[0];
                                var series_mem = this.series[1];

                                // 定时器,每隔1000ms刷新曲线一次
                                setInterval(function() {
                                get_cpu_mem();
                            
                                    // 使用JQuery从后台Servlet获取
                                    // JSON格式的数据,
                                    // 如 "{"cpu": 80,"mem": 10}"
                                    //alert('cpu_value'+cpu_value+',mem_value'+mem_value);
                                //$.getJSON("", null,function(data) {
                                        // 当前时间,为x轴数据
                                        var x = (new Date()).getTime();
                                        
                                        // y轴数据
                                        var cpu = cpu_value;
                                        var mem = mem_value;

                                        // 更新曲线数据
                                        series_cpu.addPoint([x, cpu], true, true);
                                        series_mem.addPoint([x, mem], true, true);
                                   // });
                                },
                                1000/*启动间隔,单位ms*/
                                );
                            }
                        }
                    },
                    title: {
                        text: 'CPU 内存使用率(%)',
                        x: -20
                    },
                    xAxis: {
                        type: 'datetime',
                        tickPixelInterval: 150
                    },
                    yAxis: {
                        title: {
                            text: 'CPU 内存使用率(%)'
                        },
                        plotLines: [{
                            value: 0,
                            1,
                            color: '#808080'
                        }]
                    },
                    tooltip: {
                           formatter: function() 
                           {
                                return '<b>'+ this.series.name +'</b><br/>'+
                                Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) +'<br/>'+
                                Highcharts.numberFormat(this.y, 2);
                           }
                           //valueSuffix: '%'
                    },
                    legend: {
                        layout: 'vertical',
                        align: 'right',
                        verticalAlign: 'top',
                        x: -10,
                        y: 100,
                        borderWidth: 0
                    },
                    series: [
                    // 第1条曲线的(name, data)对
                    {
                        name: 'CPU',
                        data: (function() {
                            var data = [],
                            time = (new Date()).getTime(),
                             
                             i;
                            // 给曲线y值赋初值0
                            for (i = -9; i <= 0; i++) {
                                data.push({
                                    x: time + i * 1000,
                                    cpu: 0
                                });
                            }
                            return data;
                        })()
                    },

                    // 第2条曲线的(name, data)对
                    {
                        name: '内存',
                        data: (function() {
                            var data = [],
                            time = (new Date()).getTime(),
                                                     
                             i;
                            // 给曲线y值赋初值0
                            for (i = -9; i <= 0; i++) {
                                data.push({
                                    x: time + i * 1000,
                                    y: 0
                                });
                            }
                            return data;
                        })()
                    },
                    ]
                });
            });

原文地址:https://www.cnblogs.com/qingsong/p/5031351.html