package org.rrd4j;
import static org.rrd4j.ConsolFun.AVERAGE;
import static org.rrd4j.ConsolFun.MAX;
import static org.rrd4j.DsType.GAUGE;
import java.awt.Color;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Random;
import java.util.TimeZone;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.rrd4j.core.FetchData;
import org.rrd4j.core.FetchRequest;
import org.rrd4j.core.RrdDb;
import org.rrd4j.core.RrdDef;
import org.rrd4j.core.Sample;
import org.rrd4j.core.Util;
import org.rrd4j.data.Variable;
import org.rrd4j.graph.RrdGraph;
import org.rrd4j.graph.RrdGraphConstants;
import org.rrd4j.graph.RrdGraphDef;
import org.rrd4j.graph.RrdGraphInfo;
import org.rrd4j.graph.TimeLabelFormat;
import eu.bengreen.data.utility.LargestTriangleThreeBuckets;
public class TestDemo {
@Rule
public TemporaryFolder testFolder = new TemporaryFolder();
static final long SEED = 1909752002L;
static final Random RANDOM = new Random(SEED);
static final String FILE = "demo";
static final long START;
static final long END;
static {
Calendar c1 = new GregorianCalendar(TimeZone.getTimeZone("CET"), Locale.US);
c1.setTimeInMillis(0);
c1.set(2010, 4, 1, 0, 0, 0);
START = Util.getTimestamp(c1);
Calendar c2 = new GregorianCalendar(TimeZone.getTimeZone("CET"), Locale.US);
c2.setTimeInMillis(0);
c2.set(2010, 6, 1, 0, 0, 0);
END = Util.getTimestamp(c2);
}
static final int MAX_STEP = 300;
static final int IMG_WIDTH = 500;
static final int IMG_HEIGHT = 300;
@Test
public void main() throws IOException {
System.out.println("== Starting demo");
long startMillis = System.currentTimeMillis();
long start = START;
long end = END;
String rrdPath = testFolder.getRoot().getCanonicalPath() + "FILE" + ".rrd";
String xmlPath = testFolder.getRoot().getCanonicalPath() + "FILE" + ".xml";
String rrdRestoredPath = testFolder.getRoot().getCanonicalPath() + "FILE" + "_restored.rrd";
String imgPath = testFolder.getRoot().getCanonicalPath() + "FILE" + ".png";
String logPath = testFolder.getRoot().getCanonicalPath() + "FILE" + ".log";
PrintWriter log = new PrintWriter(new BufferedOutputStream(new FileOutputStream(logPath, false)));
// creation
System.out.println("== Creating RRD file " + rrdPath);
RrdDef rrdDef = new RrdDef(rrdPath, start - 1, 300);
rrdDef.setVersion(2);
rrdDef.addDatasource("sun", GAUGE, 600, 0, Double.NaN);
rrdDef.addDatasource("shade", GAUGE, 600, 0, Double.NaN);
rrdDef.addArchive(AVERAGE, 0.5, 1, 600);
rrdDef.addArchive(AVERAGE, 0.5, 6, 700);
rrdDef.addArchive(AVERAGE, 0.5, 24, 775);
rrdDef.addArchive(AVERAGE, 0.5, 288, 797);
rrdDef.addArchive(MAX, 0.5, 1, 600);
rrdDef.addArchive(MAX, 0.5, 6, 700);
rrdDef.addArchive(MAX, 0.5, 24, 775);
rrdDef.addArchive(MAX, 0.5, 288, 797);
System.out.println(rrdDef.dump());
log.println(rrdDef.dump());
System.out.println("Estimated file size: " + rrdDef.getEstimatedSize());
RrdDb rrdDb = new RrdDb(rrdDef);
System.out.println("== RRD file created.");
Assert.assertTrue(rrdDb.getRrdDef().equals(rrdDef));
rrdDb.close();
System.out.println("== RRD file closed.");
// update database
GaugeSource sunSource = new GaugeSource(1200, 20);
GaugeSource shadeSource = new GaugeSource(300, 10);
System.out.println("== Simulating one month of RRD file updates with step not larger than " +
MAX_STEP + " seconds (* denotes 1000 updates)");
long t = start;
int n = 0;
rrdDb = new RrdDb(rrdPath);
Sample sample = rrdDb.createSample();
while (t <= end + 172800L) {
sample.setTime(t);
sample.setValue("sun", sunSource.getValue());
sample.setValue("shade", shadeSource.getValue());
log.println(sample.dump());
sample.update();
t += RANDOM.nextDouble() * MAX_STEP + 1;
}
rrdDb.close();
System.out.println("== Finished. RRD file updated " + n + " times");
// test read-only access!
rrdDb = new RrdDb(rrdPath, true);
System.out.println("File reopen in read-only mode");
Calendar c = new GregorianCalendar(TimeZone.getTimeZone("CET"), Locale.US);
c.setTimeInMillis(rrdDb.getLastUpdateTime() * 1000);
System.out.println("== Last update time was: " + String.format(Locale.US, "%tF %tT", c, c));
System.out.println("== Last info was: " + rrdDb.getInfo());
// fetch data
System.out.println("== Fetching data for the whole month");
FetchRequest request = rrdDb.createFetchRequest(AVERAGE, start, end);
System.out.println(request.dump());
log.println(request.dump());
FetchData fetchData = request.fetchData();
System.out.println("== Data fetched. " + fetchData.getRowCount() + " points obtained");
System.out.println(fetchData.toString());
System.out.println("== Dumping fetched data to XML format");
System.out.println("== Fetch completed");
// dump to XML file
System.out.println("== Dumping RRD file to XML file " + xmlPath + " (can be restored with RRDTool)");
rrdDb.exportXml(xmlPath);
System.out.println("== Creating RRD file " + rrdRestoredPath + " from XML file " + xmlPath);
RrdDb rrdRestoredDb = new RrdDb(rrdRestoredPath, xmlPath);
// close files
System.out.println("== Closing both RRD files");
rrdDb.close();
System.out.println("== First file closed");
rrdRestoredDb.close();
System.out.println("== Second file closed");
// create graph
System.out.println("Creating graph " + Util.getLapTime());
System.out.println("== Creating graph from the second file");
RrdGraphDef gDef = new RrdGraphDef();
gDef.setLocale(Locale.US);
gDef.setTimeZone(TimeZone.getTimeZone("CET"));
gDef.setWidth(IMG_WIDTH);
gDef.setHeight(IMG_HEIGHT);
gDef.setFilename(imgPath);
gDef.setStartTime(start);
gDef.setEndTime(end);
gDef.setTitle("Temperatures in May-June 2010");
gDef.setVerticalLabel("temperature");
gDef.setColor(RrdGraphConstants.COLOR_XAXIS, Color.BLUE);
gDef.setColor(RrdGraphConstants.COLOR_YAXIS, new Color(0, 255, 0, 40));
gDef.setTimeLabelFormat(new CustomTimeLabelFormat());
gDef.setDownsampler(new LargestTriangleThreeBuckets(IMG_WIDTH));
gDef.datasource("sun", rrdRestoredPath, "sun", AVERAGE);
gDef.datasource("shade", rrdRestoredPath, "shade", AVERAGE);
gDef.datasource("median", "sun,shade,+,2,/");
gDef.datasource("diff", "sun,shade,-,ABS,-1,*");
gDef.datasource("sine", "TIME," + start + ",-," + (end - start) + ",/,2,PI,*,*,SIN,1000,*");
gDef.line("sun", Color.GREEN, "sun temp");
gDef.line("shade", Color.BLUE, "shade temp");
gDef.line("median", Color.MAGENTA, "median value");
gDef.area("diff", Color.YELLOW, "difference");
gDef.line("diff", Color.RED, null);
gDef.line("sine", Color.CYAN, "sine fun");
gDef.hrule(2568, Color.GREEN, "hrule");
gDef.vrule((start + 2 * end) / 3, Color.MAGENTA, "vrule\\c");
gDef.comment("\\r");
Variable sunmax = new Variable.MAX();
Variable sunaverage = new Variable.AVERAGE();
gDef.datasource("sunmax", "sun", sunmax);
gDef.datasource("sunaverage", "sun", sunaverage);
gDef.gprint("sunmax", "maxSun = %.3f%s");
gDef.gprint("sunaverage", "avgSun = %.3f%S\\c");
gDef.print("sunmax", "maxSun = %.3f%s");
gDef.print("sunmax", "maxSun time = %ts", true);
gDef.print("sunaverage", "avgSun = %.3f%S\\c");
gDef.datasource("shademax", "shade", new Variable.MAX());
gDef.datasource("shadeverage", "shade", new Variable.AVERAGE());
gDef.gprint("shademax", "maxShade = %.3f%S");
gDef.gprint("shadeverage", "avgShade = %.3f%S\\c");
gDef.print("shademax", "maxShade = %.3f%S");
gDef.print("shadeverage", "avgShade = %.3f%S\\c");
gDef.setImageInfo("<img src='%s' width='%d' height = '%d'>");
gDef.setPoolUsed(false);
gDef.setImageFormat("png");
System.out.println("Rendering graph " + Util.getLapTime());
// create graph finally
RrdGraph graph = new RrdGraph(gDef);
System.out.println(graph.getRrdGraphInfo().dump());
System.out.println("== Graph created " + Util.getLapTime());
// demo ends
log.close();
System.out.println("== Demo completed in " +
((System.currentTimeMillis() - startMillis) / 1000.0) + " sec");
RrdGraphInfo graphinfo = graph.getRrdGraphInfo();
String[] lines = graphinfo.getPrintLines();
Assert.assertEquals("maxSun = 4.285k", lines[0]);
Assert.assertEquals("maxSun time = 1277467200", lines[1]);
Assert.assertEquals("avgSun = 3.000k", lines[2]);
Assert.assertEquals("maxShade = 0.878k", lines[3]);
Assert.assertEquals("avgShade = 0.404k", lines[4]);
Assert.assertEquals(412, graphinfo.getHeight());
Assert.assertEquals(591, graphinfo.getWidth());
Assert.assertTrue(graphinfo.getFilename().endsWith(".png"));
Assert.assertEquals(1277467200, sunmax.getValue().timestamp);
Assert.assertEquals(4284.9218056, sunmax.getValue().value, 1e-15);
}
static class GaugeSource {
private double value;
private double step;
GaugeSource(double value, double step) {
this.value = value;
this.step = step;
}
long getValue() {
double oldValue = value;
double increment = RANDOM.nextDouble() * step;
if (RANDOM.nextDouble() > 0.5) {
increment *= -1;
}
value += increment;
if (value <= 0) {
value = 0;
}
return Math.round(oldValue);
}
}
static class CustomTimeLabelFormat implements TimeLabelFormat {
public String format(Calendar c, Locale locale) {
if (c.get(Calendar.MILLISECOND) != 0) {
return String.format(locale, "%1$tH:%1$tM:%1$tS.%1$tL", c);
} else if (c.get(Calendar.SECOND) != 0) {
return String.format(locale, "%1$tH:%1$tM:%1$tS", c);
} else if (c.get(Calendar.MINUTE) != 0) {
return String.format(locale, "%1$tH:%1$tM", c);
} else if (c.get(Calendar.HOUR_OF_DAY) != 0) {
return String.format(locale, "%1$tH:%1$tM", c);
} else if (c.get(Calendar.DAY_OF_MONTH) != 1) {
return String.format(locale, "%1$td %1$tb", c);
} else if (c.get(Calendar.DAY_OF_YEAR) != 1) {
return String.format(locale, "%1$td %1$tb", c);
} else {
return String.format(locale, "%1$tY", c);
}
}
}
}