Object execute() throws IOException { gdef = new RrdGraphDef(); // OPTIONS // START, END String t1 = getOptionValue("s", "start", DEFAULT_START), t2 = getOptionValue("e", "end", DEFAULT_END); gdef.setTimeSpan(Util.getTimestamps(t1, t2)); // X-GRID parseXGrid(getOptionValue("x", "x-grid")); // Y-GRID parseYGrid(getOptionValue("y", "y-grid")); // ALT-Y-GRID gdef.setAltYGrid(getBooleanOption("Y", "alt-y-grid")); // NO_MINOR gdef.setNoMinorGrid(getBooleanOption(null, "no-minor")); // ALT-Y-MRTG gdef.setAltYMrtg(getBooleanOption("R", "alt-y-mrtg")); // ALT-AUTOSCALE gdef.setAltAutoscale(getBooleanOption("A", "alt-autoscale")); // ALT-AUTOSCALE-MAX gdef.setAltAutoscaleMax(getBooleanOption("M", "alt-autoscale-max")); // UNITS-EXPONENT String opt = getOptionValue("X", "units-exponent"); if (opt != null) { gdef.setUnitsExponent(parseInt(opt)); } // UNITS-LENGTH opt = getOptionValue("L", "units-length"); if (opt != null) { gdef.setUnitsLength(parseInt(opt)); } // VERTICAL LABEL opt = getOptionValue("v", "vertical-label"); if (opt != null) { gdef.setVerticalLabel(opt); } // WIDTH opt = getOptionValue("w", "width"); if (opt != null) { gdef.setWidth(parseInt(opt)); } // HEIGHT opt = getOptionValue("h", "height"); if (opt != null) { gdef.setHeight(parseInt(opt)); } // INTERLACED gdef.setInterlaced(getBooleanOption("i", "interlaced")); // IMGINFO opt = getOptionValue("f", "imginfo"); if (opt != null) { gdef.setImageInfo(opt); } // IMGFORMAT opt = getOptionValue("a", "imgformat"); if (opt != null) { gdef.setImageFormat(opt); } // BACKGROUND opt = getOptionValue("B", "background"); if (opt != null) { gdef.setBackgroundImage(opt); } // OVERLAY opt = getOptionValue("O", "overlay"); if (opt != null) { gdef.setOverlayImage(opt); } // UNIT opt = getOptionValue("U", "unit"); if (opt != null) { gdef.setUnit(opt); } // LAZY gdef.setLazy(getBooleanOption("z", "lazy")); // UPPER-LIMIT opt = getOptionValue("u", "upper-limit"); if (opt != null) { gdef.setMaxValue(parseDouble(opt)); } // LOWER-LIMIT opt = getOptionValue("l", "lower-limit"); if (opt != null) { gdef.setMinValue(parseDouble(opt)); } // RIGID gdef.setRigid(getBooleanOption("r", "rigid")); // BASE opt = getOptionValue("b", "base"); if (opt != null) { gdef.setBase(parseDouble(opt)); } // LOGARITHMIC gdef.setLogarithmic(getBooleanOption("o", "logarithmic")); // COLORS parseColors(getMultipleOptionValues("c", "color")); // NO-LEGEND gdef.setNoLegend(getBooleanOption("g", "no-legend")); // ONLY_GRAPH gdef.setOnlyGraph(getBooleanOption("j", "only-graph")); // FORCE-RULES-LEGEND gdef.setForceRulesLegend(getBooleanOption("F", "force-rules-legend")); // TITLE opt = getOptionValue("t", "title"); if (opt != null) { gdef.setTitle(opt); } // STEP opt = getOptionValue("S", "step"); if (opt != null) { gdef.setStep(parseLong(opt)); } // NON-OPTIONS String[] words = getRemainingWords(); // the first word must be a filename if (words.length < 2) { throw new IllegalArgumentException("Image filename must be specified"); } gdef.setFilename(words[1]); // parse remaining words, in no particular order for (int i = 2; i < words.length; i++) { if (words[i].startsWith("DEF:")) { parseDef(words[i]); } else if (words[i].startsWith("CDEF:")) { parseCDef(words[i]); } else if (words[i].startsWith("PRINT:")) { parsePrint(words[i]); } else if (words[i].startsWith("GPRINT:")) { parseGPrint(words[i]); } else if (words[i].startsWith("COMMENT:")) { parseComment(words[i]); } else if (words[i].startsWith("HRULE:")) { parseHRule(words[i]); } else if (words[i].startsWith("VRULE:")) { parseVRule(words[i]); } else if (words[i].startsWith("LINE1:") || words[i].startsWith("LINE2:") || words[i].startsWith("LINE3:")) { parseLine(words[i]); } else if (words[i].startsWith("AREA:")) { parseArea(words[i]); } else if (words[i].startsWith("STACK:")) { parseStack(words[i]); } else { throw new IllegalArgumentException("Unexpected GRAPH token encountered: " + words[i]); } } // create diagram finally RrdGraphInfo info = new RrdGraph(gdef).getRrdGraphInfo(); if (info.getFilename().equals(RrdGraphConstants.IN_MEMORY_IMAGE)) { println(new String(info.getBytes())); } else { println(info.getWidth() + "x" + info.getHeight()); String[] plines = info.getPrintLines(); for (String pline : plines) { println(pline); } if (info.getImgInfo() != null && info.getImgInfo().length() > 0) { println(info.getImgInfo()); } } return info; }
@Override public byte[] createGraph( String metricName, String rrdFilename, long startTime, long endTime, String verticalAxisLabel, String title) throws IOException, MetricsGraphException { // Create RRD DB in read-only mode for the specified RRD file RrdDb rrdDb = new RrdDb(rrdFilename, true); // Extract the data source (should always only be one data source per RRD file - otherwise we // have a problem) if (rrdDb.getDsCount() != 1) { throw new MetricsGraphException( "Only one data source per RRD file is supported - RRD file " + rrdFilename + " has " + rrdDb.getDsCount() + " data sources."); } // Define attributes of the graph to be created for this metric RrdGraphDef graphDef = new RrdGraphDef(); graphDef.setTimeSpan(startTime, endTime); graphDef.setImageFormat("PNG"); graphDef.setShowSignature(false); graphDef.setStep(60); graphDef.setVerticalLabel(verticalAxisLabel); graphDef.setHeight(500); graphDef.setWidth(1000); graphDef.setTitle(title); DsType dataSourceType = rrdDb.getDatasource(0).getType(); // Determine if the Data Source for this RRD file is a COUNTER or GAUGE // (Need to know this because COUNTER data is averaged across samples and the vertical axis of // the // generated graph by default will show data per rrdStep interval) if (dataSourceType == DsType.COUNTER) { // If we ever needed to adjust the metric's data collected by RRD by the archive step // (which is the rrdStep * archiveSampleCount) this is how to do it. // FetchRequest fetchRequest = rrdDb.createFetchRequest(ConsolFun.AVERAGE, // startTime, endTime); // Archive archive = rrdDb.findMatchingArchive(fetchRequest); // long archiveStep = archive.getArcStep(); // LOGGER.debug("archiveStep = " + archiveStep); long rrdStep = rrdDb.getRrdDef().getStep(); LOGGER.debug("rrdStep = " + rrdStep); // Still TBD if we want to graph the AVERAGE data on the same graph // graphDef.comment(metricName + " "); // graphDef.datasource("myAverage", rrdFilename, "data", ConsolFun.AVERAGE); // graphDef.datasource("realAverage", "myAverage," + rrdStep + ",*"); // graphDef.line("realAverage", Color.GREEN, "Average", 2); // Multiplied by the rrdStep to "undo" the automatic averaging that RRD does // when it collects TOTAL data - we want the actual totals for the step, not // the average of the totals. graphDef.datasource("myTotal", rrdFilename, "data", ConsolFun.TOTAL); graphDef.datasource("realTotal", "myTotal," + rrdStep + ",*"); graphDef.line("realTotal", Color.BLUE, convertCamelCase(metricName), 2); // Add some spacing between the graph and the summary stats shown beneath the graph graphDef.comment("\\s"); graphDef.comment("\\s"); graphDef.comment("\\c"); // Average, Min, and Max over all of the TOTAL data - displayed at bottom of the graph graphDef.gprint("realTotal", ConsolFun.AVERAGE, "Average = %.3f%s"); graphDef.gprint("realTotal", ConsolFun.MIN, "Min = %.3f%s"); graphDef.gprint("realTotal", ConsolFun.MAX, "Max = %.3f%s"); } else if (dataSourceType == DsType.GAUGE) { graphDef.datasource("myAverage", rrdFilename, "data", ConsolFun.AVERAGE); graphDef.line("myAverage", Color.RED, convertCamelCase(metricName), 2); // Add some spacing between the graph and the summary stats shown beneath the graph graphDef.comment("\\s"); graphDef.comment("\\s"); graphDef.comment("\\c"); // Average, Min, and Max over all of the AVERAGE data - displayed at bottom of the graph graphDef.gprint("myAverage", ConsolFun.AVERAGE, "Average = %.3f%s"); graphDef.gprint("myAverage", ConsolFun.MIN, "Min = %.3f%s"); graphDef.gprint("myAverage", ConsolFun.MAX, "Max = %.3f%s"); } else { rrdDb.close(); throw new MetricsGraphException( "Unsupported data source type " + dataSourceType.name() + " in RRD file " + rrdFilename + ", only COUNTER and GAUGE data source types supported."); } rrdDb.close(); // Use "-" as filename so that RRD creates the graph only in memory (no file is // created, hence no file locking problems due to race conditions between multiple clients) graphDef.setFilename("-"); RrdGraph graph = new RrdGraph(graphDef); return graph.getRrdGraphInfo().getBytes(); }