/** * The 'closes' the rrd file. This is where the actual work of writing the RRD files takes place. * The passed in rrd is actually an rrd command string containing updates. This method executes * this command. * * @param rrd a {@link java.lang.StringBuffer} object. * @throws java.lang.Exception if any. */ @Override public void closeFile(StringBuffer rrd) throws Exception { String command = rrd.toString(); String[] results = Interface.launch(command); if (results[0] != null) { throw new Exception(results[0]); } }
/** * Creates a the rrd file from the rrdDefinition. Since this definition is really just the create * command string it just executes it. * * @param createCommand a {@link java.lang.String} object. * @throws java.lang.Exception if any. */ @Override public void createFile(CreateCommand createCommand, Map<String, String> attributeMappings) throws Exception { if (createCommand == null) { LOG.debug("createRRD: skipping RRD file"); return; } LOG.debug("Executing: rrdtool {}", createCommand.toString()); Interface.launch(createCommand.toString()); String filenameWithoutExtension = createCommand.filename.replace(RrdUtils.getExtension(), ""); int lastIndexOfSeparator = filenameWithoutExtension.lastIndexOf(File.separator); RrdUtils.createMetaDataFile( filenameWithoutExtension.substring(0, lastIndexOfSeparator), filenameWithoutExtension.substring(lastIndexOfSeparator), attributeMappings); }
/** {@inheritDoc} */ @Override public Double fetchLastValueInRange(String rrdFile, String ds, int interval, int range) throws NumberFormatException, RrdException { // Generate rrd_fetch() command through jrrd JNI interface in order to // retrieve // LAST pdp for the datasource stored in the specified RRD file // // String array returned from launch() native method format: // String[0] - If success is null, otherwise contains reason for failure // String[1] - All data source names contained in the RRD (space // delimited) // String[2]...String[n] - RRD fetch data in the following format: // <timestamp> <value1> <value2> ... <valueX> where X is // the total number of data sources // // NOTE: Specifying start time of 'now-<interval>' and // end time of 'now-<interval>' where <interval> is the // configured thresholding interval (and should be the // same as the RRD step size) in order to guarantee that // we don't get a 'NaN' value from the fetch command. This // is necessary because the collection is being done by collectd // and there is nothing keeping us in sync. // // interval argument is in milliseconds so must convert to seconds // // TODO: Combine fetchLastValueInRange and fetchLastValue long now = System.currentTimeMillis(); long latestUpdateTime = (now - (now % interval)) / 1000L; long earliestUpdateTime = ((now - (now % interval)) - range) / 1000L; LOG.debug("fetchInRange: fetching data from {} to {}", earliestUpdateTime, latestUpdateTime); String fetchCmd = "fetch " + rrdFile + " AVERAGE -s " + earliestUpdateTime + " -e " + latestUpdateTime; String[] fetchStrings = Interface.launch(fetchCmd); // Sanity check the returned string array if (fetchStrings == null) { LOG.error( "fetchInRange: Unexpected error issuing RRD 'fetch' command, no error text available."); return null; } // Check error string at index 0, will be null if 'fetch' was successful if (fetchStrings[0] != null) { LOG.error("fetchInRange: RRD database 'fetch' failed, reason: {}", fetchStrings[0]); return null; } // Sanity check if (fetchStrings[1] == null || fetchStrings[2] == null) { LOG.error("fetchInRange: RRD database 'fetch' failed, no data retrieved."); return null; } int numFetched = fetchStrings.length; LOG.debug("fetchInRange: got {} strings from RRD", numFetched); // String at index 1 contains the RRDs datasource names // String[] dsNames = fetchStrings[1].split("\\s"); int dsIndex = 0; for (int i = 0; i < dsNames.length; i++) { if (dsNames[i].equals(ds)) dsIndex = i; } String dsName = dsNames[dsIndex].trim(); Double dsValue; // Back through the RRD output until I get something interesting for (int i = fetchStrings.length - 2; i > 1; i--) { String[] dsValues = fetchStrings[i].split("\\s"); if (dsValues[dsIndex].trim().equalsIgnoreCase("nan")) { LOG.debug("fetchInRange: Got a NaN value - continuing back in time"); } else { try { dsValue = new Double(dsValues[dsIndex].trim()); LOG.debug("fetchInRange: fetch successful: {}= {}", dsName, dsValue); return dsValue; } catch (NumberFormatException nfe) { LOG.warn( "fetchInRange: Unable to convert fetched value ({}) to Double for data source {}", dsValues[dsIndex].trim(), dsName); throw nfe; } } } return null; }
/** {@inheritDoc} */ @Override public Double fetchLastValue( String rrdFile, String ds, String consolidationFunction, int interval) { /* * Generate rrd_fetch() command through jrrd JNI interface in order to * retrieve LAST pdp for the datasource stored in the specified RRD * file. * * String array returned from launch() native method format: * String[0] - If success is null, otherwise contains reason * for failure * String[1] - All data source names contained in the RRD (space * delimited) * String[2 ... n] - RRD fetch data in the following format: * <timestamp> <value1> <value2> ... <valueX> * X is the total number of data sources. * * NOTE: Specifying start time of 'now-<interval>' and end time of * 'now-<interval>' where <interval> is the configured thresholding * interval (and should be the same as the RRD step size) in order to * guarantee that we don't get a 'NaN' value from the fetch command. * This is necessary because the collection is being done by collectd at * effectively random times and there is nothing keeping us in sync. * * interval argument is in milliseconds so must convert to seconds */ // TODO: Combine fetchLastValueInRange and fetchLastValue String fetchCmd = "fetch " + rrdFile + " " + consolidationFunction + " -s now-" + interval / 1000 + " -e now-" + interval / 1000; LOG.debug("fetch: Issuing RRD command: {}", fetchCmd); String[] fetchStrings = Interface.launch(fetchCmd); // Sanity check the returned string array if (fetchStrings == null) { LOG.error("fetch: Unexpected error issuing RRD 'fetch' command, no error text available."); return null; } // Check error string at index 0, will be null if 'fetch' was successful if (fetchStrings[0] != null) { LOG.error("fetch: RRD database 'fetch' failed, reason: {}", fetchStrings[0]); return null; } // Sanity check if (fetchStrings[1] == null || fetchStrings[2] == null) { LOG.error("fetch: RRD database 'fetch' failed, no data retrieved."); return null; } // String at index 1 contains the RRDs datasource names // String[] dsNames = fetchStrings[1].split("\\s"); int dsIndex = 0; for (int i = 0; i < dsNames.length; i++) { if (dsNames[i].equals(ds)) dsIndex = i; } String dsName = dsNames[dsIndex].trim(); // String at index 2 contains fetched values for the current time // Convert value string into a Double // String[] dsValues = fetchStrings[2].split("\\s"); Double dsValue = null; if (dsValues[dsIndex].trim().equalsIgnoreCase("nan")) { dsValue = new Double(Double.NaN); } else { try { dsValue = new Double(dsValues[dsIndex].trim()); } catch (NumberFormatException nfe) { LOG.warn( "fetch: Unable to convert fetched value ({}) to Double for data source {}", dsValues[dsIndex].trim(), dsName); throw nfe; } } LOG.debug("fetch: fetch successful: {}={}", dsName, dsValue); return dsValue; }