/* * Copyright 2011 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.facebook.tsdb.tsdash.server.gnuplot; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Random; import com.facebook.tsdb.tsdash.server.TsdbServlet; import com.facebook.tsdb.tsdash.server.model.Metric; public abstract class GnuplotProcess { public static final String OUTPUT_DIR_ENV = "TSDASH_PLOT_DIR"; public static final String PIPES_DIR = "/tmp/plotter"; public static final String BASH = "/bin/bash"; public static final String GNUPLOT = "/usr/local/bin/gnuplot"; private static Random rand = new Random(); protected Process gnuplot; protected BufferedWriter gnuplotStdin; protected BufferedReader gnuplotStderr; protected ArrayList<String> dataPipes = new ArrayList<String>(); protected int id; protected int plotNo = 0; public GnuplotProcess() throws Exception { id = rand.nextInt(); if (id < 0) { id = -id; } ProcessBuilder processBuilder = new ProcessBuilder(GNUPLOT); gnuplot = processBuilder.start(); gnuplotStdin = new BufferedWriter(new OutputStreamWriter( gnuplot.getOutputStream())); gnuplotStderr = new BufferedReader(new InputStreamReader( gnuplot.getErrorStream())); } protected String getPipeFilename(int pipeNo) { return String.format("%s/%d-%d", PIPES_DIR, id, pipeNo); } protected static String noDataFilename() { return TsdbServlet.plotsDir + "/no_data.jpg"; } protected String getOutputFilename(GnuplotOptions options) { return String.format("%s/%d-%d.%s", TsdbServlet.plotsDir, id, plotNo, options.getTerminal()); } protected void createPipes(int pipesCount) throws IOException, InterruptedException { String bashCommand = String.format("mkdir -p %s;", PIPES_DIR); dataPipes.clear(); for (int i = 0; i < pipesCount; i++) { String pipeFilename = getPipeFilename(i); File pipe = new File(pipeFilename); if (!pipe.exists()) { bashCommand += String.format("mkfifo %s;", pipeFilename); } dataPipes.add(pipeFilename); } ProcessBuilder bashBuilder = new ProcessBuilder(BASH); Process bash = bashBuilder.start(); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( bash.getOutputStream())); writer.write(bashCommand); writer.newLine(); writer.close(); bash.waitFor(); } private String getGnuplotError() throws IOException { if (!gnuplotStderr.ready()) { return ""; } System.err.println("Reading error: "); String error = "Gnuplot Error: "; String line; while ((line = gnuplotStderr.readLine()) != null) { error += line; } System.err.println(error); return error; } public String plot(Metric metric, GnuplotOptions options) throws Exception { Metric[] metrics = new Metric[1]; metrics[0] = metric; return plot(metrics, options); } public abstract String plot(Metric[] metrics, GnuplotOptions options) throws Exception; public void close() throws InterruptedException { // delete all pipes for (String pipeFilename : dataPipes) { File pipe = new File(pipeFilename); if (pipe.exists()) { pipe.delete(); } } gnuplot.waitFor(); gnuplot.destroy(); } public static GnuplotProcess create(boolean surface) throws Exception { if (surface) { return new Gnuplot3D(); } return new Gnuplot2D(); } }