CHUKWA-745. Improved chart configuration management. (Eric Yang)
Project: http://git-wip-us.apache.org/repos/asf/chukwa/repo Commit: http://git-wip-us.apache.org/repos/asf/chukwa/commit/a6e0cbad Tree: http://git-wip-us.apache.org/repos/asf/chukwa/tree/a6e0cbad Diff: http://git-wip-us.apache.org/repos/asf/chukwa/diff/a6e0cbad Branch: refs/heads/master Commit: a6e0cbad7cd52cc04a5363c04bc0fbd5b78f66be Parents: 16927ce Author: Eric Yang <[email protected]> Authored: Sun Apr 26 14:52:58 2015 -0700 Committer: Eric Yang <[email protected]> Committed: Sun Apr 26 17:25:26 2015 -0700 ---------------------------------------------------------------------- CHANGES.txt | 2 + bin/chukwa | 1 + conf/hbase.schema | 3 +- pom.xml | 11 + .../writer/hbase/HBaseWriter.java | 15 +- .../chukwa/datastore/ChukwaHBaseStore.java | 174 +++++++- .../extraction/hbase/AbstractProcessor.java | 2 - .../apache/hadoop/chukwa/hicc/BarOptions.java | 30 ++ .../org/apache/hadoop/chukwa/hicc/Chart.java | 446 ++++--------------- .../hadoop/chukwa/hicc/HiccWebServer.java | 19 + .../apache/hadoop/chukwa/hicc/LineOptions.java | 25 ++ .../apache/hadoop/chukwa/hicc/PointOptions.java | 27 ++ .../org/apache/hadoop/chukwa/hicc/Series.java | 121 +++++ .../hadoop/chukwa/hicc/SeriesOptions.java | 33 ++ .../apache/hadoop/chukwa/hicc/bean/Series.java | 4 + .../chukwa/hicc/rest/ChartController.java | 187 ++++++++ .../chukwa/hicc/rest/MetricsController.java | 7 +- .../chukwa/hicc/rest/VelocityResolver.java | 86 ++++ .../apache/hadoop/chukwa/util/HBaseUtil.java | 17 + src/main/web/hicc/WEB-INF/vm/chart.vm | 106 +++++ .../web/hicc/WEB-INF/vm/unit-bytes-binary.vm | 27 ++ .../web/hicc/WEB-INF/vm/unit-bytes-decimal.vm | 27 ++ src/main/web/hicc/WEB-INF/vm/unit-generic.vm | 20 + src/main/web/hicc/WEB-INF/vm/unit-ops.vm | 20 + src/main/web/hicc/WEB-INF/vm/unit-percent.vm | 20 + src/main/web/hicc/css/default.css | 11 +- src/main/web/hicc/css/iframe.css | 91 +++- src/main/web/hicc/js/flot.extend.js | 170 +++---- src/main/web/hicc/jsp/graph_explorer.jsp | 204 ++++----- .../apache/hadoop/chukwa/hicc/TestChart.java | 84 ++-- 30 files changed, 1321 insertions(+), 669 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index dd3f642..5e3e93c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -10,6 +10,8 @@ Trunk (unreleased changes) IMPROVEMENTS + CHUKWA-745. Improved chart configuration management. (Eric Yang) + CHUKWA-744. Implemented new parsers for extract and transform data to HBase format. (Eric Yang) CHUKWA-667. Optimize HBase metrics schema. (Eric Yang) http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/bin/chukwa ---------------------------------------------------------------------- diff --git a/bin/chukwa b/bin/chukwa index 1a3a341..db77200 100755 --- a/bin/chukwa +++ b/bin/chukwa @@ -153,6 +153,7 @@ fi pid="$CHUKWA_PID_DIR/chukwa-$CHUKWA_IDENT_STRING-$COMMAND.pid" if [ "$1" = "start" ]; then + shift if [ -f $pid ]; then TARGET_PID=`cat $pid` if kill -0 `cat $pid` > /dev/null 2>&1; then http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/conf/hbase.schema ---------------------------------------------------------------------- diff --git a/conf/hbase.schema b/conf/hbase.schema index 5e32f90..54e5b01 100644 --- a/conf/hbase.schema +++ b/conf/hbase.schema @@ -1,5 +1,6 @@ create "chukwa_meta", -{NAME=>"k"} +{NAME=>"k"}, +{NAME=>"c"} create "chukwa", {NAME=>"t"}, {NAME=>"a"} http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 6beaef8..1c8d26c 100644 --- a/pom.xml +++ b/pom.xml @@ -109,6 +109,16 @@ <version>1.8.1</version> </dependency> <dependency> + <groupId>org.apache.velocity</groupId> + <artifactId>velocity</artifactId> + <version>1.7</version> + </dependency> + <dependency> + <groupId>org.apache.velocity</groupId> + <artifactId>velocity-tools</artifactId> + <version>2.0</version> + </dependency> + <dependency> <groupId>edu.berkeley.confspell</groupId> <artifactId>confspellcheck</artifactId> <version>1.0</version> @@ -481,6 +491,7 @@ <exclude>**/JobLog.java</exclude> <exclude>**/TestJobLogEntry.java</exclude> <exclude>**/TestDemuxManager.java</exclude> + <exclude>**/TestFSMBuilder.java</exclude> </testExcludes> </configuration> </execution> http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/datacollection/writer/hbase/HBaseWriter.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/datacollection/writer/hbase/HBaseWriter.java b/src/main/java/org/apache/hadoop/chukwa/datacollection/writer/hbase/HBaseWriter.java index 34c82e1..e5a8083 100644 --- a/src/main/java/org/apache/hadoop/chukwa/datacollection/writer/hbase/HBaseWriter.java +++ b/src/main/java/org/apache/hadoop/chukwa/datacollection/writer/hbase/HBaseWriter.java @@ -37,10 +37,14 @@ import org.apache.hadoop.chukwa.extraction.hbase.UnknownRecordTypeException; import org.apache.hadoop.chukwa.util.ExceptionUtil; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Connection; +import org.apache.hadoop.hbase.client.ConnectionFactory; import org.apache.hadoop.hbase.client.HConnection; import org.apache.hadoop.hbase.client.HConnectionManager; import org.apache.hadoop.hbase.client.HTableInterface; import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Table; import org.apache.log4j.Logger; public class HBaseWriter extends PipelineableWriter { @@ -54,7 +58,7 @@ public class HBaseWriter extends PipelineableWriter { private Reporter reporter; private ChukwaConfiguration conf; String defaultProcessor; - private HConnection connection; + private static Connection connection; private class StatReportingTask extends TimerTask { private long lastTs = System.currentTimeMillis(); @@ -105,7 +109,9 @@ public class HBaseWriter extends PipelineableWriter { } catch (NoSuchAlgorithmException e) { throw new IOException("Can not register hashing algorithm."); } - connection = HConnectionManager.createConnection(hconf); + if (connection == null) { + connection = ConnectionFactory.createConnection(hconf); + } } public void close() { @@ -121,8 +127,8 @@ public class HBaseWriter extends PipelineableWriter { public CommitStatus add(List<Chunk> chunks) throws WriterException { CommitStatus rv = ChukwaWriter.COMMIT_OK; try { - HTableInterface hbase = connection.getTable(CHUKWA_TABLE); - HTableInterface meta = connection.getTable(CHUKWA_META_TABLE); + Table hbase = connection.getTable(TableName.valueOf(CHUKWA_TABLE)); + Table meta = connection.getTable(TableName.valueOf(CHUKWA_META_TABLE)); for(Chunk chunk : chunks) { synchronized (this) { try { @@ -140,6 +146,7 @@ public class HBaseWriter extends PipelineableWriter { } } hbase.close(); + meta.close(); } catch (Exception e) { log.error(ExceptionUtil.getStackTrace(e)); throw new WriterException("Failed to store data to HBase."); http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/datastore/ChukwaHBaseStore.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/datastore/ChukwaHBaseStore.java b/src/main/java/org/apache/hadoop/chukwa/datastore/ChukwaHBaseStore.java index d9c32d6..7494aa8 100644 --- a/src/main/java/org/apache/hadoop/chukwa/datastore/ChukwaHBaseStore.java +++ b/src/main/java/org/apache/hadoop/chukwa/datastore/ChukwaHBaseStore.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -29,11 +30,13 @@ import java.util.Map.Entry; import java.util.NavigableMap; import java.util.Set; import java.util.TimeZone; +import java.util.UUID; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.hadoop.chukwa.hicc.Chart; import org.apache.hadoop.chukwa.hicc.bean.HeatMapPoint; import org.apache.hadoop.chukwa.hicc.bean.Heatmap; import org.apache.hadoop.chukwa.hicc.bean.Series; @@ -48,6 +51,7 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.ConnectionFactory; import org.apache.hadoop.hbase.client.Get; +import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; @@ -56,16 +60,37 @@ import org.apache.log4j.Logger; import org.json.simple.JSONObject; import org.json.simple.JSONValue; +import com.google.gson.Gson; + public class ChukwaHBaseStore { private static Configuration hconf = HBaseConfiguration.create(); static Logger LOG = Logger.getLogger(ChukwaHBaseStore.class); static byte[] COLUMN_FAMILY = "t".getBytes(); static byte[] ANNOTATION_FAMILY = "a".getBytes(); static byte[] KEY_NAMES = "k".getBytes(); + static byte[] CHART_TYPE = "chart_meta".getBytes(); + static byte[] CHART_FAMILY = "c".getBytes(); private static final String CHUKWA = "chukwa"; private static final String CHUKWA_META = "chukwa_meta"; private static long MILLISECONDS_IN_DAY = 86400000L; + private static Connection connection = null; + public static void getHBaseConnection() throws IOException { + if (connection == null || connection.isClosed()) { + connection = ConnectionFactory.createConnection(hconf); + } + } + + public static void closeHBase() { + try { + if(connection != null) { + connection.close(); + } + } catch(IOException e) { + LOG.warn("Unable to release HBase connection."); + } + } + /** * Scan chukwa table for a particular metric group and metric name based on * time ranges. @@ -93,7 +118,7 @@ public class ChukwaHBaseStore { * @param endTime * @return */ - public static Series getSeries(String metric, String source, long startTime, + public static synchronized Series getSeries(String metric, String source, long startTime, long endTime) { String seriesName = new StringBuilder(metric).append(":").append(source).toString(); Series series = new Series(seriesName); @@ -104,7 +129,7 @@ public class ChukwaHBaseStore { startTime = endTime; endTime = temp; } - Connection connection = ConnectionFactory.createConnection(hconf); + getHBaseConnection(); Table table = connection.getTable(TableName.valueOf(CHUKWA)); Scan scan = new Scan(); Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC")); @@ -144,6 +169,7 @@ public class ChukwaHBaseStore { } table.close(); } catch (Exception e) { + closeHBase(); LOG.error(ExceptionUtil.getStackTrace(e)); } return series; @@ -152,7 +178,7 @@ public class ChukwaHBaseStore { public static Set<String> getMetricNames(String metricGroup) { Set<String> familyNames = new CopyOnWriteArraySet<String>(); try { - Connection connection = ConnectionFactory.createConnection(hconf); + getHBaseConnection(); Table table = connection.getTable(TableName.valueOf(CHUKWA_META)); Get get = new Get(metricGroup.getBytes()); Result result = table.get(get); @@ -163,8 +189,8 @@ public class ChukwaHBaseStore { } } table.close(); - connection.close(); } catch (Exception e) { + closeHBase(); LOG.error(ExceptionUtil.getStackTrace(e)); } return familyNames; @@ -174,7 +200,7 @@ public class ChukwaHBaseStore { public static Set<String> getMetricGroups() { Set<String> metricGroups = new CopyOnWriteArraySet<String>(); try { - Connection connection = ConnectionFactory.createConnection(hconf); + getHBaseConnection(); Table table = connection.getTable(TableName.valueOf(CHUKWA_META)); Scan scan = new Scan(); scan.addFamily(KEY_NAMES); @@ -185,8 +211,8 @@ public class ChukwaHBaseStore { metricGroups.add(new String(result.getRow(), "UTF-8")); } table.close(); - connection.close(); } catch (Exception e) { + closeHBase(); LOG.error(ExceptionUtil.getStackTrace(e)); } return metricGroups; @@ -195,7 +221,7 @@ public class ChukwaHBaseStore { public static Set<String> getSourceNames(String dataType) { Set<String> pk = new HashSet<String>(); try { - Connection connection = ConnectionFactory.createConnection(hconf); + getHBaseConnection(); Table table = connection.getTable(TableName.valueOf(CHUKWA_META)); Scan scan = new Scan(); scan.addFamily(KEY_NAMES); @@ -211,8 +237,8 @@ public class ChukwaHBaseStore { } } table.close(); - connection.close(); } catch (Exception e) { + closeHBase(); LOG.error(ExceptionUtil.getStackTrace(e)); } return pk; @@ -227,7 +253,7 @@ public class ChukwaHBaseStore { List<Get> series = new ArrayList<Get>(); String fullName = new StringBuilder(metricGroup).append(".").append(metric).toString(); try { - Connection connection = ConnectionFactory.createConnection(hconf); + getHBaseConnection(); Table table = connection.getTable(TableName.valueOf(CHUKWA)); Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC")); c.setTimeInMillis(startTime); @@ -288,6 +314,7 @@ public class ChukwaHBaseStore { heatmap.putRadius(radius); heatmap.putSeries(index); } catch (IOException e) { + closeHBase(); LOG.error(ExceptionUtil.getStackTrace(e)); } return heatmap; @@ -304,7 +331,7 @@ public class ChukwaHBaseStore { public static Set<String> getClusterNames(long startTime, long endTime) { Set<String> clusters = new HashSet<String>(); try { - Connection connection = ConnectionFactory.createConnection(hconf); + getHBaseConnection(); Table table = connection.getTable(TableName.valueOf(CHUKWA_META)); Scan scan = new Scan(); scan.addFamily(KEY_NAMES); @@ -320,11 +347,136 @@ public class ChukwaHBaseStore { } } table.close(); - connection.close(); } catch (Exception e) { + closeHBase(); LOG.error(ExceptionUtil.getStackTrace(e)); } return clusters; } + public static Chart getChart(String id) { + Chart chart = null; + try { + getHBaseConnection(); + Table table = connection.getTable(TableName.valueOf(CHUKWA_META)); + Get get = new Get(CHART_TYPE); + Result r = table.get(get); + byte[] value = r.getValue(CHART_FAMILY, id.getBytes()); + Gson gson = new Gson(); + if(value!=null) { + chart = gson.fromJson(new String(value), Chart.class); + } + table.close(); + } catch (Exception e) { + closeHBase(); + LOG.error(ExceptionUtil.getStackTrace(e)); + } + return chart; + } + + public static void putChart(String id, Chart chart) { + try { + getHBaseConnection(); + Table table = connection.getTable(TableName.valueOf(CHUKWA_META)); + Put put = new Put(CHART_TYPE); + Gson gson = new Gson(); + String buffer = gson.toJson(chart); + put.add(CHART_FAMILY, id.getBytes(), buffer.getBytes()); + table.put(put); + table.close(); + } catch (Exception e) { + closeHBase(); + LOG.error(ExceptionUtil.getStackTrace(e)); + } + + } + + public static String createChart(Chart chart) throws IOException { + getHBaseConnection(); + String id = chart.getId(); + if(id!=null) { + // Check if there is existing chart with same id. + Chart test = getChart(id); + if(test!=null) { + // If id already exists, randomly generate an id. + id = String.valueOf(UUID.randomUUID()); + } + } else { + // If id is not provided, randomly generate an id. + id = String.valueOf(UUID.randomUUID()); + } + chart.setId(id); + Table table = connection.getTable(TableName.valueOf(CHUKWA_META)); + Put put = new Put(CHART_TYPE); + Gson gson = new Gson(); + String buffer = gson.toJson(chart); + put.add(CHART_FAMILY, id.getBytes(), buffer.getBytes()); + table.put(put); + table.close(); + return id; + } + + public static synchronized ArrayList<org.apache.hadoop.chukwa.hicc.Series> getChartSeries(ArrayList<org.apache.hadoop.chukwa.hicc.Series> series, long startTime, long endTime) { + ArrayList<org.apache.hadoop.chukwa.hicc.Series> list = new ArrayList<org.apache.hadoop.chukwa.hicc.Series>(); + try { + // Swap start and end if the values are inverted. + if (startTime > endTime) { + long temp = endTime; + startTime = endTime; + endTime = temp; + } + getHBaseConnection(); + Table table = connection.getTable(TableName.valueOf(CHUKWA)); + Scan scan = new Scan(); + Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + c.setTimeInMillis(startTime); + int startDay = c.get(Calendar.DAY_OF_YEAR); + c.setTimeInMillis(endTime); + int endDay = c.get(Calendar.DAY_OF_YEAR); + for (org.apache.hadoop.chukwa.hicc.Series s : series) { + org.apache.hadoop.chukwa.hicc.Series clone = (org.apache.hadoop.chukwa.hicc.Series) s.clone(); + long currentDay = startTime; + String[] parts = s.getUrl().toString().split("/"); + String metric = parts[5]; + String source = parts[6]; + ArrayList<ArrayList<Number>> data = new ArrayList<ArrayList<Number>>(); + for (int i = startDay; i <= endDay; i++) { + byte[] rowKey = HBaseUtil.buildKey(currentDay, metric, source); + scan.addFamily(COLUMN_FAMILY); + scan.setStartRow(rowKey); + scan.setStopRow(rowKey); + scan.setTimeRange(startTime, endTime); + scan.setBatch(10000); + + ResultScanner results = table.getScanner(scan); + Iterator<Result> it = results.iterator(); + // TODO: Apply discrete wavelet transformation to limit the output + // size to 1000 data points for graphing optimization. (i.e jwave) + while (it.hasNext()) { + Result result = it.next(); + for (KeyValue kv : result.raw()) { + byte[] key = kv.getQualifier(); + long timestamp = ByteBuffer.wrap(key).getLong(); + double value = Double.parseDouble(new String(kv.getValue(), + "UTF-8")); + ArrayList<Number> points = new ArrayList<Number>(); + points.add(timestamp); + points.add(value); + data.add(points); + } + } + results.close(); + currentDay = currentDay + (i * MILLISECONDS_IN_DAY); + } + clone.setData(data); + list.add(clone); + } + table.close(); + } catch (Exception e) { + closeHBase(); + LOG.error(ExceptionUtil.getStackTrace(e)); + } + return list; + } + } http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/extraction/hbase/AbstractProcessor.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/extraction/hbase/AbstractProcessor.java b/src/main/java/org/apache/hadoop/chukwa/extraction/hbase/AbstractProcessor.java index b39c789..eb79cd7 100644 --- a/src/main/java/org/apache/hadoop/chukwa/extraction/hbase/AbstractProcessor.java +++ b/src/main/java/org/apache/hadoop/chukwa/extraction/hbase/AbstractProcessor.java @@ -22,8 +22,6 @@ import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; -import java.util.Calendar; -import java.util.TimeZone; import org.apache.hadoop.chukwa.Chunk; import org.apache.hadoop.chukwa.datacollection.writer.hbase.Reporter; http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/BarOptions.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/BarOptions.java b/src/main/java/org/apache/hadoop/chukwa/hicc/BarOptions.java new file mode 100644 index 0000000..9ab686d --- /dev/null +++ b/src/main/java/org/apache/hadoop/chukwa/hicc/BarOptions.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.hadoop.chukwa.hicc; + +public class BarOptions extends SeriesOptions { + public boolean zero; + public boolean stepByStep = true; + public int barWidth = 4; + public String align; + public boolean horizontal; + + public BarOptions() { + fill = true; + } +} http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/Chart.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/Chart.java b/src/main/java/org/apache/hadoop/chukwa/hicc/Chart.java index 76ba919..ab6dc4e 100644 --- a/src/main/java/org/apache/hadoop/chukwa/hicc/Chart.java +++ b/src/main/java/org/apache/hadoop/chukwa/hicc/Chart.java @@ -19,27 +19,13 @@ package org.apache.hadoop.chukwa.hicc; -import java.util.ArrayList; -import java.util.Map; -import java.util.TreeMap; import java.util.HashMap; import java.util.List; -import java.util.Map.Entry; -import java.text.SimpleDateFormat; -import javax.servlet.http.HttpServletRequest; -import javax.swing.text.html.HTMLDocument.Iterator; -import org.apache.hadoop.chukwa.util.XssFilter; -import org.json.JSONArray; - -@SuppressWarnings("unused") public class Chart { private String id; private String title; - private String graphType; - private ArrayList<TreeMap<String, TreeMap<String, Double>>> dataset; - private ArrayList<String> chartType; - private ArrayList<String> restData; + private List<Series> series; private boolean xLabelOn; private boolean yLabelOn; private boolean yRightLabelOn; @@ -47,45 +33,27 @@ public class Chart { private int height; private List<String> xLabelRange; private HashMap<String, Long> xLabelRangeHash; - private HttpServletRequest request = null; - private boolean legend; + private boolean legend = true; private String xLabel = ""; private String yLabel = ""; private String yRightLabel = ""; - private int datasetCounter = 0; private double max = 0; private double min = 0; - private int seriesCounter = 0; - private List<String> rightList; - private boolean userDefinedMax = false; - private boolean userDefinedMin = false; - private boolean displayPercentage = false; - private String[] seriesOrder = null; - private XssFilter xf = null; - - public Chart(HttpServletRequest request) { - xf = new XssFilter(request); - if (request != null && xf.getParameter("boxId") != null) { - this.id = xf.getParameter("boxId"); - } else { - this.id = "0"; - } + private boolean userDefinedMax = true; + private boolean userDefinedMin = true; + private String yUnitType = ""; + + public Chart(String id) { + this.id = id; this.title = "Untitled Chart"; - this.graphType = "image"; this.xLabelOn = true; this.yLabelOn = true; - this.width = 400; - this.height = 200; - this.request = request; + this.width = 100; + this.height = 100; this.legend = true; this.max = 0; - this.datasetCounter = 0; - this.seriesCounter = 0; - this.rightList = new ArrayList<String>(); this.userDefinedMax = false; this.userDefinedMin = false; - this.displayPercentage = false; - this.seriesOrder = null; } public void setYMax(double max) { @@ -93,13 +61,25 @@ public class Chart { this.userDefinedMax = true; } + public double getYMax() { + return this.max; + } + + public boolean getUserDefinedMax() { + return this.userDefinedMax; + } + public void setYMin(double min) { this.min = min; this.userDefinedMin = true; } - public void setDisplayPercentage(boolean percentage) { - this.displayPercentage = percentage; + public double getYMin() { + return this.min; + } + + public boolean getUserDefinedMin() { + return this.userDefinedMin; } public void setSize(int width, int height) { @@ -107,71 +87,86 @@ public class Chart { this.height = height; } - public void setGraphType(String graphType) { - if (graphType != null) { - this.graphType = graphType; - } + public int getWidth() { + return this.width; + } + + public int getHeight() { + return this.height; } public void setTitle(String title) { this.title = title; } + public String getTitle() { + return this.title; + } + public void setId(String id) { this.id = id; } - public void setDataSet(String chartType, - TreeMap<String, TreeMap<String, Double>> data) { - if (this.dataset == null) { - this.dataset = new ArrayList<TreeMap<String, TreeMap<String, Double>>>(); - this.chartType = new ArrayList<String>(); - } - this.dataset.add(data); - this.chartType.add(chartType); + public String getId() { + return this.id; } - public void setDataSet(String chartType, String series, String data) { - if (this.dataset == null) { - this.restData = new ArrayList<String>(); - this.dataset = new ArrayList<TreeMap<String, TreeMap<String, Double>>>(); - this.chartType = new ArrayList<String>(); - } - this.chartType.add(chartType); - this.restData.add(data); - TreeMap<String, TreeMap<String, Double>> tree = new TreeMap<String, TreeMap<String, Double>>(); - tree.put(series, new TreeMap<String, Double>()); - this.dataset.add(tree); + public void SetSeries(List<Series> series) { + this.series = series; } - - public void setSeriesOrder(String[] metrics) { - this.seriesOrder = (String[]) metrics.clone(); + + public List<Series> getSeries() { + return this.series; } - - public void setXAxisLabels(boolean toggle) { + + public void setXAxisLabelsOn(boolean toggle) { xLabelOn = toggle; } + public boolean isXAxisLabelsOn() { + return xLabelOn; + } + public void setYAxisLabels(boolean toggle) { yLabelOn = toggle; } + public boolean isYAxisLabelsOn() { + return yLabelOn; + } + public void setYAxisRightLabels(boolean toggle) { yRightLabelOn = toggle; } + public boolean isYAxisRightLabelsOn() { + return yRightLabelOn; + } + public void setXAxisLabel(String label) { xLabel = label; } + public String getXAxisLabel() { + return xLabel; + } + public void setYAxisLabel(String label) { yLabel = label; } + public String getYAxisLabel() { + return yLabel; + } + public void setYAxisRightLabel(String label) { yRightLabel = label; } + public String getYAxisRightLabel() { + return yRightLabel; + } + public void setXLabelsRange(List<String> range) { xLabelRange = range; xLabelRangeHash = new HashMap<String, Long>(); @@ -182,302 +177,23 @@ public class Chart { } } + public List<String> getXLabelsRange() { + return xLabelRange; + } + public void setLegend(boolean toggle) { legend = toggle; } - public String plot() { - StringBuilder output = new StringBuilder(); - if (dataset == null && restData == null) { - output.append("No Data available."); - return output.toString(); - } - String dateFormat = "%H:%M"; - if (xLabel.intern() == "Time".intern()) { -// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); -// try { -// long xMin = 0; -// long xMax = 0; -// if(xLabelRange!=null && xLabelRange.size()>0) { -// xMin = Long.parseLong(xLabelRange.get(0)); -// xMax = Long.parseLong(xLabelRange.get(xLabelRange.size() - 1)); -// } -// if (xMax - xMin > 31536000000L) { -// dateFormat = "%y"; -// } else if (xMax - xMin > 2592000000L) { -// dateFormat = "%y-%m"; -// } else if (xMax - xMin > 604800000L) { -// dateFormat = "%m-%d"; -// } else if (xMax - xMin > 86400000L) { -// dateFormat = "%m-%d %H:%M"; -// } -// } catch (NumberFormatException e) { -// dateFormat = "%y-%m-%d %H:%M"; -// } - } - StringBuilder xAxisOptions = new StringBuilder(); - if (xLabel.intern() == "Time".intern()) { -// if(this.restData==null) { -// xAxisOptions.append("timeformat: \""); -// xAxisOptions.append(dateFormat); -// xAxisOptions.append("\","); -// } - xAxisOptions.append("mode: \"time\""); - } else { - xAxisOptions - .append("tickFormatter: function (val, axis) { if(val!=0) { return xLabels[Math.round(val)]; } else { return \" \"; }; }, ticks: 5"); - } - if (request != null && xf.getParameter("format") == null) { - output - .append("<html><link href=\"/hicc/css/default.css\" rel=\"stylesheet\" type=\"text/css\">\n"); - output - .append("<html><link href=\"/hicc/css/iframe.css\" rel=\"stylesheet\" type=\"text/css\">\n"); - output - .append("<html><link href=\"/hicc/css/flexigrid/flexigrid.css\" rel=\"stylesheet\" type=\"text/css\">\n"); - output - .append("<body><script type=\"text/javascript\" src=\"/hicc/js/jquery-1.2.6.min.js\"></script>\n"); - output - .append("<script type=\"text/javascript\" src=\"/hicc/js/jquery.flot.pack.js\"></script>\n"); - output - .append("<script type=\"text/javascript\" src=\"/hicc/js/flexigrid.pack.js\"></script>\n"); - output - .append("<script type=\"text/javascript\" src=\"/hicc/js/excanvas.pack.js\"></script>\n"); - output - .append("<script type=\"text/javascript\" src=\"/hicc/js/base64.js\"></script>\n"); - output - .append("<script type=\"text/javascript\" src=\"/hicc/js/canvas2image.js\"></script>\n"); - output.append("<div id=\"placeholderTitle\"><center>" + title - + "</center></div>\n"); - output.append("<div id=\"placeholder\" style=\"width:" + this.width - + "px;height:" + this.height + "px;\"></div>\n"); - output.append("<center><div id=\"placeholderLegend\" style=\"display:"+(legend?"block":"none")+";\"></div></center>\n"); - output.append("<center><div id=\"statisLegend\" style=\"display:"+(legend?"block":"none")+";\"></div></center>\n"); - output.append("<center><div id=\"statisLegend\" style=\"display:"+(legend?"block":"none")+";\"></div></center>\n"); - output.append("<input type=\"hidden\" id=\"boxId\" value=\"iframe" - + this.id + "\">\n"); - output - .append("<script type=\"text/javascript\" src=\"/hicc/js/flot.extend.js\">\n"); - output.append("</script>\n"); - output.append("<script type=\"text/javascript\">\n"); - output.append("var chartTitle=\"<center>" + title + "</center>\";\n"); - output.append("var height=" + this.height + ";\n"); - output.append("var xLabels=new Array();\n"); - output.append("var cw = document.body.clientWidth-70;\n"); - output.append("var ch = document.body.clientHeight-50;\n"); - output - .append("document.getElementById('placeholder').style.width=cw+'px';\n"); - output - .append("document.getElementById('placeholder').style.height=ch+'px';\n"); - } - output.append("_options={\n"); - output.append(" points: { show: false },\n"); - output.append(" xaxis: { " + xAxisOptions + " },\n"); - output.append(" selection: { mode: \"xy\" },\n"); - output.append(" grid: {\n"); - output.append(" clickable: true,\n"); - output.append(" hoverable: true,\n"); - output.append(" tickColor: \"#C0C0C0\",\n"); - output.append(" borderWidth: 0,\n"); - output.append(" backgroundColor:\"#F9F9F9\"\n"); - output.append(" },\n"); - output.append(" legend: { show: " + this.legend - + ", noColumns: 3, container: $(\"#placeholderLegend\") },\n"); - output.append(" yaxis: { "); - boolean stack = false; - for (String type : this.chartType) { - if (type.startsWith("stack")) { - stack = true; - } - } - if (stack) { - output.append("mode: \"stack\", "); - } - if (displayPercentage) { - output - .append("tickFormatter: function(val, axis) { return val.toFixed(axis.tickDecimals) + \" %\"; }"); - } else { - output.append("tickFormatter: function(val, axis) { "); - output - .append("if (val >= 1000000000000000) return (val / 1000000000000000).toFixed(2) + \"x10<sup>15</sup>\";"); - output - .append("else if (val >= 100000000000000) return (val / 100000000000000).toFixed(2) + \"x10<sup>14</sup>\";"); - output - .append("else if (val >= 10000000000000) return (val / 10000000000000).toFixed(2) + \"x10<sup>13</sup>\";"); - output - .append("else if (val >= 1000000000000) return (val / 1000000000000).toFixed(2) + \"x10<sup>12</sup>\";"); - output - .append("else if (val >= 100000000000) return (val / 100000000000).toFixed(2) + \"x10<sup>11</sup>\";"); - output - .append("else if (val >= 10000000000) return (val / 10000000000).toFixed(2) + \"x10<sup>10</sup>\";"); - output - .append("else if (val >= 1000000000) return (val / 1000000000).toFixed(2) + \"x10<sup>9</sup>\";"); - output - .append("else if (val >= 100000000) return (val / 100000000).toFixed(2) + \"x10<sup>8</sup>\";"); - output - .append("else if (val >= 10000000) return (val / 10000000).toFixed(2) + \"x10<sup>7</sup>\";"); - output - .append("else if (val >= 1000000) return (val / 1000000).toFixed(2) + \"x10<sup>6</sup>\";"); - output - .append("else if (val >= 100000) return (val / 100000).toFixed(2) + \"x10<sup>5</sup>\";"); - output - .append("else if (val >= 10000) return (val / 10000).toFixed(2) + \"x10<sup>4</sup>\";"); - output - .append("else if (val >= 2000) return (val / 1000).toFixed(2) + \"x10<sup>3</sup>\";"); - output.append("else return val.toFixed(2) + \"\"; }"); - } - if (userDefinedMin) { - output.append(", min:"); - output.append(this.min); - } - if (userDefinedMax) { - output.append(", max:"); - output.append(this.max); - } - output.append("}\n"); - output.append(" };\n"); - if (!xLabel.equals("Time")) { - output.append("xLabels = [\""); - for (int i = 0; i < xLabelRange.size(); i++) { - if (i > 0) { - output.append("\",\""); - } - output.append(xLabelRange.get(i)); - } - output.append("\"];\n"); - } - output.append("_series=[\n"); - ColorPicker cp = new ColorPicker(); - int i = 0; - if(this.dataset!=null) { - for (TreeMap<String, TreeMap<String, Double>> dataMap : this.dataset) { - String[] keyNames; - if (this.seriesOrder != null) { - keyNames = this.seriesOrder; - } else { - keyNames = dataMap.keySet().toArray( - new String[dataMap.size()]); - } - int counter = 0; - if (i != 0 && !this.userDefinedMax) { - this.max = 0; - } - for (String seriesName : keyNames) { - int counter2 = 0; - if ((counter != 0) || (i != 0)) { - output.append(","); - } - String param = "fill: false, lineWidth: 1"; - String type = "lines"; - if (this.chartType.get(i).intern() == "stack-area".intern() - || this.chartType.get(i).intern() == "area".intern()) { - param = "fill: true, lineWidth: 0"; - } - if (this.chartType.get(i).intern() == "bar".intern()) { - type = "bars"; - param = "stepByStep: true, lineWidth: 0"; - } - if (this.chartType.get(i).intern() == "point".intern()) { - type = "points"; - param = "fill: false"; - } - output.append(" {"); - output.append(type); - output.append(": { show: true, "); - output.append(param); - output.append(" }, color: \""); - output.append(cp.getNext()); - output.append("\", label: \""); - output.append(seriesName); - output.append("\", "); - String showYAxis = "false"; - String shortRow = "false"; - if (counter == 0 || i > 0) { - showYAxis = "true"; - shortRow = "false"; - } - output.append(" row: { show: "); - output.append(showYAxis); - output.append(",shortRow:"); - output.append(shortRow); - output.append(", showYAxis:"); - output.append(showYAxis); - output.append("}, data:["); - TreeMap<String, Double> data = dataMap.get(seriesName); - if(data!=null) { - java.util.Iterator<Entry<String, Double>> iter = data.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry<String, Double> entry = (Map.Entry<String, Double>) iter.next(); - int rangeLabel = 0; - if (counter2 != 0) { - output.append(","); - } - if (xLabel.equals("Time")) { - if (Double.isNaN(entry.getValue())) { - output.append("["); - output.append(entry.getKey()); - output.append(",NULL]"); - } else { - output.append("["); - output.append(entry.getKey()); - output.append(","); - output.append(entry.getValue()); - output.append("]"); - } - } else { - long value = xLabelRangeHash.get(entry.getKey()); - if (Double.isNaN(entry.getValue())) { - output.append("["); - output.append(value); - output.append(",NULL]"); - } else { - output.append("["); - output.append(value); - output.append(","); - output.append(entry.getValue()); - output.append("]"); - } - rangeLabel++; - } - counter2++; - } - } - output.append("], min:0"); - if (this.userDefinedMax) { - output.append(", max:"); - output.append(this.max); - } - output.append("}"); - counter++; - } - i++; - } - } - output.append(" ];\n"); - if(this.restData!=null) { - JSONArray arr = new JSONArray(); - for(String url : restData) { - arr.put(url); - } - output.append("var _rest = "); - output.append(arr.toString()); - output.append(";"); - } - if (request != null && xf.getParameter("format") == null) { - output.append("$(document).ready(function() { \n"); - if(this.restData!=null) { - output.append(" loadData();\n"); - } else { - output.append(" wholePeriod();\n"); - } - output.append(" $(window).resize(function() { wholePeriod(); });\n"); - output.append("});\n"); - output.append("</script>\n"); - output.append("<input type=\"button\" value=\"Export\" onclick=\"javascript:saveReport();\">\n"); - output.append("</body></html>\n"); - } else { - output.append("chartTitle=\"<center>" + this.title + "</center>\";"); - output.append("height=" + this.height + ";"); - } - return output.toString(); + public boolean getLegend() { + return legend; + } + + public void setYUnitType(String yUnitType) { + this.yUnitType = yUnitType; + } + + public String getYUnitType() { + return this.yUnitType; } } http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/HiccWebServer.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/HiccWebServer.java b/src/main/java/org/apache/hadoop/chukwa/hicc/HiccWebServer.java index 09e829d..ea53941 100644 --- a/src/main/java/org/apache/hadoop/chukwa/hicc/HiccWebServer.java +++ b/src/main/java/org/apache/hadoop/chukwa/hicc/HiccWebServer.java @@ -22,6 +22,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; @@ -31,6 +32,7 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.apache.hadoop.chukwa.conf.ChukwaConfiguration; +import org.apache.hadoop.chukwa.datastore.ChukwaHBaseStore; import org.apache.hadoop.chukwa.util.ExceptionUtil; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataOutputStream; @@ -106,6 +108,7 @@ public class HiccWebServer { } } } + jar.close(); return result; } @@ -187,6 +190,22 @@ public class HiccWebServer { fs.mkdirs(viewsPath); List<String> views = getResourceListing("views"); populateDir(views, viewsPath); + + // Populate example chart widgets + Chart chart = new Chart("1"); + chart.setYUnitType(""); + chart.setTitle("Load Average"); + ArrayList<Series> series = new ArrayList<Series>(); + + Series s = new Series(); + s.setLabel("SystemMetrics.LoadAverage.1/Erics-MacBook-Pro.local"); + s.setUrl(new URI("/hicc/v1/metrics/series/SystemMetrics.LoadAverage.1/Erics-MacBook-Pro.local")); + LineOptions l = new LineOptions(); + s.setLineOptions(l); + series.add(s); + + chart.SetSeries(series); + ChukwaHBaseStore.createChart(chart); log.info("HICC Datastore initialization completed."); } } catch (IOException ex) { http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/LineOptions.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/LineOptions.java b/src/main/java/org/apache/hadoop/chukwa/hicc/LineOptions.java new file mode 100644 index 0000000..f0e1279 --- /dev/null +++ b/src/main/java/org/apache/hadoop/chukwa/hicc/LineOptions.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.hadoop.chukwa.hicc; + +public class LineOptions extends SeriesOptions { + public boolean zero; + public boolean steps; + + +} http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/PointOptions.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/PointOptions.java b/src/main/java/org/apache/hadoop/chukwa/hicc/PointOptions.java new file mode 100644 index 0000000..dedea86 --- /dev/null +++ b/src/main/java/org/apache/hadoop/chukwa/hicc/PointOptions.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.hadoop.chukwa.hicc; + +public class PointOptions extends SeriesOptions { + public int radius; + public String symbol = "circle"; + + public PointOptions() { + radius = 5; + } +} http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/Series.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/Series.java b/src/main/java/org/apache/hadoop/chukwa/hicc/Series.java new file mode 100644 index 0000000..4906059 --- /dev/null +++ b/src/main/java/org/apache/hadoop/chukwa/hicc/Series.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.hadoop.chukwa.hicc; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class Series implements Cloneable { + + @XmlElement + public URI url; + @XmlElement + public String color; + @XmlElement + public String label; + @XmlElement + public LineOptions lines; + @XmlElement + public BarOptions bars; + @XmlElement + public PointOptions points; + @XmlElement + public int xaxis; + @XmlElement + public int yaxis; + @XmlElement + public boolean clickable; + @XmlElement + public boolean hoverable; + @XmlElement + public int shadowSize; + @XmlElement + public int highlightColor; + public ArrayList<ArrayList<Number>> data = null; + + public Series() { + + } + + public void setUrl(URI url) { + this.url = url; + } + + public URI getUrl() { + return url; + } + + public void setLineOptions(LineOptions lines) { + this.lines = lines; + + } + + public LineOptions getLineOptions() { + return lines; + } + + public void setBarOptions(BarOptions bars) { + this.bars = bars; + } + + public BarOptions getBarOptions() { + return bars; + } + + public void setPointOptions(PointOptions points) { + this.points = points; + } + + public PointOptions getPointOptions() { + return points; + } + + public void setColor(String color) { + this.color = color; + } + + public String getColor() { + return color; + } + + public void setData(ArrayList<ArrayList<Number>> data) { + this.data = data; + } + + public ArrayList<ArrayList<Number>> getData() { + return data; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } + + @Override + public Object clone()throws CloneNotSupportedException{ + return super.clone(); + } +} http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/SeriesOptions.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/SeriesOptions.java b/src/main/java/org/apache/hadoop/chukwa/hicc/SeriesOptions.java new file mode 100644 index 0000000..74527d9 --- /dev/null +++ b/src/main/java/org/apache/hadoop/chukwa/hicc/SeriesOptions.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.hadoop.chukwa.hicc; + +public class SeriesOptions { + public boolean show = true; + public boolean fill = false; + public int lineWidth; + public String fillColor; + + public boolean getFill() { + return fill; + } + + public void setFill(boolean fill) { + this.fill = fill; + } +} http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/bean/Series.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/bean/Series.java b/src/main/java/org/apache/hadoop/chukwa/hicc/bean/Series.java index 90d3963..c946086 100644 --- a/src/main/java/org/apache/hadoop/chukwa/hicc/bean/Series.java +++ b/src/main/java/org/apache/hadoop/chukwa/hicc/bean/Series.java @@ -64,4 +64,8 @@ public class Series { public Object toJSONObject() { return series; } + + public String getData() { + return (String) series.get("data"); + } } http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/rest/ChartController.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/rest/ChartController.java b/src/main/java/org/apache/hadoop/chukwa/hicc/rest/ChartController.java new file mode 100644 index 0000000..93b8ab9 --- /dev/null +++ b/src/main/java/org/apache/hadoop/chukwa/hicc/rest/ChartController.java @@ -0,0 +1,187 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.hadoop.chukwa.hicc.rest; + +import java.io.IOException; +import java.io.StringWriter; +import java.lang.reflect.Type; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.apache.hadoop.chukwa.datastore.ChukwaHBaseStore; +import org.apache.hadoop.chukwa.hicc.Chart; +import org.apache.hadoop.chukwa.hicc.Series; +import org.apache.hadoop.chukwa.hicc.TimeHandler; +import org.apache.log4j.Logger; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.mortbay.log.Log; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.sun.jersey.api.Responses; + +@Path("/chart") +public class ChartController { + static Logger LOG = Logger.getLogger(ChartController.class); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); + + @Context + VelocityEngine velocity; + + /** + * Render chart using flot.js + * + * @param id Reference ID of Chart stored in HBase chukwa_meta table. + * @return html chart widget + */ + @GET + @Path("draw/{id}") + @Produces(MediaType.TEXT_HTML) + public String draw(@PathParam("id") String id) { + VelocityContext context = new VelocityContext(); + StringWriter sw = null; + try { + Chart chart = ChukwaHBaseStore.getChart(id); + List<Series> series = chart.getSeries(); + Gson gson = new Gson(); + String seriesMetaData = gson.toJson(series); + + context.put("chart", chart); + context.put("seriesMetaData", seriesMetaData); + Template template = velocity.getTemplate("chart.vm"); + sw = new StringWriter(); + template.merge(context, sw); + } catch (Exception e) { + e.printStackTrace(); + return e.getMessage(); + } + return sw.toString(); + } + + /** + * Describe chart meta data + */ + @GET + @Path("describe/{id}") + @Produces(MediaType.APPLICATION_JSON) + public String describe(@PathParam("id") String id) { + Chart chart = ChukwaHBaseStore.getChart(id); + Gson gson = new Gson(); + String buffer = gson.toJson(chart); + return buffer; + } + + /** + * Create a new chart meta data + * + * @param chart + * @return + */ + @POST + @Path("save") + @Consumes(MediaType.APPLICATION_JSON) + public Response create(String buffer) { + try { + Gson gson = new Gson(); + Chart chart = gson.fromJson(buffer, Chart.class); + String id = ChukwaHBaseStore.createChart(chart); + return Response.ok(id).build(); + } catch (IOException e) { + return Responses.notAcceptable().build(); + } + + } + + /** + * Save chart meta data + * + * @param chart + * @return + */ + @PUT + @Path("save/{id}") + @Consumes(MediaType.APPLICATION_JSON) + public Response save(@PathParam("id") String id, String buffer) { + Gson gson = new Gson(); + Chart chart = gson.fromJson(buffer, Chart.class); + ChukwaHBaseStore.putChart(id, chart); + return Response.ok().build(); + + } + + /** + * Preview a chart + */ + @PUT + @Path("preview") + public String preview(String buffer) { + VelocityContext context = new VelocityContext(); + StringWriter sw = null; + try { + Gson gson = new Gson(); + Chart chart = gson.fromJson(buffer, Chart.class); + List<Series> series = chart.getSeries(); + String seriesMetaData = gson.toJson(series); + + context.put("chart", chart); + context.put("seriesMetaData", seriesMetaData); + Template template = velocity.getTemplate("chart.vm"); + sw = new StringWriter(); + template.merge(context, sw); + } catch (Exception e) { + e.printStackTrace(); + return e.getMessage(); + } + return sw.toString(); + } + + @PUT + @Path("preview/series") + @Produces("application/json") + public String previewSeries(@Context HttpServletRequest request, String buffer) { + Type listType = new TypeToken<ArrayList<Series>>() { + }.getType(); + long startTime = 0; + long endTime = 0; + TimeHandler time = new TimeHandler(request); + startTime = time.getStartTime(); + endTime = time.getEndTime(); + Gson gson = new Gson(); + ArrayList<Series> series = gson.fromJson(buffer, listType); + series = ChukwaHBaseStore.getChartSeries(series, startTime, endTime); + String result = gson.toJson(series); + return result; + } + +} http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/rest/MetricsController.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/rest/MetricsController.java b/src/main/java/org/apache/hadoop/chukwa/hicc/rest/MetricsController.java index 61f8247..9730b43 100644 --- a/src/main/java/org/apache/hadoop/chukwa/hicc/rest/MetricsController.java +++ b/src/main/java/org/apache/hadoop/chukwa/hicc/rest/MetricsController.java @@ -37,6 +37,8 @@ import org.apache.hadoop.chukwa.hicc.TimeHandler; import org.apache.hadoop.chukwa.hicc.bean.Series; import org.json.simple.JSONArray; +import com.google.gson.Gson; + @Path("/metrics") public class MetricsController { @@ -128,7 +130,7 @@ public class MetricsController { @GET @Path("schema/{metricGroup}") @Produces("application/json") - public String getFamilies(@PathParam("metricGroup") String metricGroup) { + public String getMetrics(@PathParam("metricGroup") String metricGroup) { Set<String> metricNames = ChukwaHBaseStore.getMetricNames(metricGroup); JSONArray metrics = new JSONArray(); for(String metric : metricNames) { @@ -136,7 +138,7 @@ public class MetricsController { } return metrics.toString(); } - + @GET @Path("source/{metricGroup}") @Produces("application/json") @@ -148,4 +150,5 @@ public class MetricsController { } return rows.toString(); } + } http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/rest/VelocityResolver.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/rest/VelocityResolver.java b/src/main/java/org/apache/hadoop/chukwa/hicc/rest/VelocityResolver.java new file mode 100644 index 0000000..ea07797 --- /dev/null +++ b/src/main/java/org/apache/hadoop/chukwa/hicc/rest/VelocityResolver.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.hadoop.chukwa.hicc.rest; + +import java.lang.reflect.Type; + +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.ext.Provider; + +import org.apache.log4j.Logger; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; + +import com.sun.jersey.core.spi.component.ComponentContext; +import com.sun.jersey.core.spi.component.ComponentScope; +import com.sun.jersey.spi.inject.Injectable; +import com.sun.jersey.spi.inject.InjectableProvider; + +@Provider +public class VelocityResolver implements InjectableProvider<Context, Type> { + @Context + private ServletContext servletContext; + + private VelocityEngine ve; + private static Logger LOG = Logger.getLogger(VelocityResolver.class); + public static String LOGGER_NAME = VelocityResolver.class.getName(); + + /** + * Jersey configuration for setting up Velocity configuration. + */ + @Override + public Injectable<VelocityEngine> getInjectable(ComponentContext arg0, + Context arg1, Type c) { + if (c.equals(VelocityEngine.class)) { + return new Injectable<VelocityEngine>() { + public VelocityEngine getValue() { + if (ve == null) { + LOG.info("Ready to start velocity"); + ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, + "org.apache.velocity.runtime.log.Log4JLogChute"); + ve.setProperty("runtime.log.logsystem.log4j.logger", + LOGGER_NAME); + ve.setProperty(RuntimeConstants.RESOURCE_LOADER, + "webapp"); + ve.setProperty("webapp.resource.loader.class", + "org.apache.velocity.tools.view.WebappResourceLoader"); + ve.setProperty("webapp.resource.loader.path", + "/WEB-INF/vm/"); + ve.setApplicationAttribute( + "javax.servlet.ServletContext", servletContext); + try { + ve.init(); + LOG.info("Velocity is loaded"); + } catch (Exception e) { + LOG.error("Error when initializing Velocity", e); + } + } + return ve; + } + }; + } + return null; + } + + public ComponentScope getScope() { + return ComponentScope.Singleton; + } + +} http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/util/HBaseUtil.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/hadoop/chukwa/util/HBaseUtil.java b/src/main/java/org/apache/hadoop/chukwa/util/HBaseUtil.java index d463dd1..b0ae38e 100644 --- a/src/main/java/org/apache/hadoop/chukwa/util/HBaseUtil.java +++ b/src/main/java/org/apache/hadoop/chukwa/util/HBaseUtil.java @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.hadoop.chukwa.util; import java.security.MessageDigest; http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/WEB-INF/vm/chart.vm ---------------------------------------------------------------------- diff --git a/src/main/web/hicc/WEB-INF/vm/chart.vm b/src/main/web/hicc/WEB-INF/vm/chart.vm new file mode 100644 index 0000000..90cb1d7 --- /dev/null +++ b/src/main/web/hicc/WEB-INF/vm/chart.vm @@ -0,0 +1,106 @@ +#* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + *# +<!DOCTYPE html> +<html lang="en"> + <head> + <link href="/hicc/css/default.css" rel="stylesheet" type="text/css"> + <link href="/hicc/css/iframe.css" rel="stylesheet" type="text/css"> + <link href="/hicc/css/flexigrid/flexigrid.css" rel="stylesheet" type="text/css"> + </head> + <body> + <div id="placeholderTitle"><center>$chart.getTitle()</center></div> + <div id="placeholder"></div> + <div class="legendHolder"> + <div class="left"></div> + <div class="center" id="placeholderLegend"></div> + <div class="right"></div> + </div> + <div class="legendHolder"> + <div class="center" id="statisLegend"></div> + </div> + <script type="text/javascript" src="/hicc/js/jquery-1.2.6.min.js"></script> + <script type="text/javascript" src="/hicc/js/jquery.flot.pack.js"></script> + <script type="text/javascript" src="/hicc/js/flexigrid.pack.js"></script> + <script type="text/javascript" src="/hicc/js/excanvas.pack.js"></script> + <script type="text/javascript" src="/hicc/js/base64.js"></script> + <script type="text/javascript" src="/hicc/js/canvas2image.js"></script> + <script type="text/javascript" src="/hicc/js/flot.extend.js"></script> + + <script type="text/javascript"> + +var chartTitle="<center>$chart.getTitle()</center>"; +var xLabels=new Array(); + +var _options={ + points: { + show: false + }, + xaxis: { + mode: "time" + }, + selection: { + mode: "xy", + color: "#999999" + }, + grid: { + clickable: true, + hoverable: true, + tickColor: "#C0C0C0", + borderWidth: 0, + backgroundColor:"#F9F9F9" + }, + legend: { show: true, noColumns: 3, container: $("#placeholderLegend") }, + yaxis: { + #if ( $chart.getYMin()!=0 ) + min: $chart.getYMin(), + #end + #if ( $chart.getYMax()!=0 ) + max: $chart.getYMax(), + #end + tickFormatter: function(val, axis) { + #if ( $chart.getYUnitType().equals('bytes') ) + #parse("unit-bytes-binary.vm") + #elseif ( $chart.getYUnitType().equals('bytes-decimal') ) + #parse("unit-bytes-decimal.vm") + #elseif ( $chart.getYUnitType().equals('ops') ) + #parse("unit-ops.vm") + #elseif ( $chart.getYUnitType().equals('percent') ) + #parse("unit-percent.vm") + #else + #parse("unit-generic.vm") + #end + } + } +}; + +var _series=$seriesMetaData; +var _seriesTemplate=$seriesMetaData; + +$(document).ready(function() { + reload(); + $(window).resize(function() { + wholePeriod(); + }); +}); + + +</script> +<input type="hidden" id="boxId" value="iframe"> +<!-- <input type="button" value="Export" onclick="javascript:saveReport();"> --> +</body> +</html> http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/WEB-INF/vm/unit-bytes-binary.vm ---------------------------------------------------------------------- diff --git a/src/main/web/hicc/WEB-INF/vm/unit-bytes-binary.vm b/src/main/web/hicc/WEB-INF/vm/unit-bytes-binary.vm new file mode 100644 index 0000000..96c6cf7 --- /dev/null +++ b/src/main/web/hicc/WEB-INF/vm/unit-bytes-binary.vm @@ -0,0 +1,27 @@ +#* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + *# +var bytes = val; +var thresh = 1024; +if(bytes < thresh) return bytes + 'B'; + var units = ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB']; + var u = -1; + do { + bytes /= thresh; + ++u; + } while(bytes >= thresh); +return bytes.toFixed(1)+units[u]; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/WEB-INF/vm/unit-bytes-decimal.vm ---------------------------------------------------------------------- diff --git a/src/main/web/hicc/WEB-INF/vm/unit-bytes-decimal.vm b/src/main/web/hicc/WEB-INF/vm/unit-bytes-decimal.vm new file mode 100644 index 0000000..ed91660 --- /dev/null +++ b/src/main/web/hicc/WEB-INF/vm/unit-bytes-decimal.vm @@ -0,0 +1,27 @@ +#* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + *# +var bytes = val; +var thresh = 1000; +if(bytes < thresh) return bytes + 'B'; + var units = ['kB','MB','GB','TB','PB','EB','ZB','YB']; + var u = -1; + do { + bytes /= thresh; + ++u; + } while(bytes >= thresh); +return bytes.toFixed(1)+units[u]; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/WEB-INF/vm/unit-generic.vm ---------------------------------------------------------------------- diff --git a/src/main/web/hicc/WEB-INF/vm/unit-generic.vm b/src/main/web/hicc/WEB-INF/vm/unit-generic.vm new file mode 100644 index 0000000..2c56c1f --- /dev/null +++ b/src/main/web/hicc/WEB-INF/vm/unit-generic.vm @@ -0,0 +1,20 @@ +#* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + *# +var parts = val.toString().split("."); +parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); +return parts.join("."); http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/WEB-INF/vm/unit-ops.vm ---------------------------------------------------------------------- diff --git a/src/main/web/hicc/WEB-INF/vm/unit-ops.vm b/src/main/web/hicc/WEB-INF/vm/unit-ops.vm new file mode 100644 index 0000000..e863b6a --- /dev/null +++ b/src/main/web/hicc/WEB-INF/vm/unit-ops.vm @@ -0,0 +1,20 @@ +#* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + *# +var parts = val.toString().split("."); +parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); +return parts.join(".") + "ops"; http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/WEB-INF/vm/unit-percent.vm ---------------------------------------------------------------------- diff --git a/src/main/web/hicc/WEB-INF/vm/unit-percent.vm b/src/main/web/hicc/WEB-INF/vm/unit-percent.vm new file mode 100644 index 0000000..d37807a --- /dev/null +++ b/src/main/web/hicc/WEB-INF/vm/unit-percent.vm @@ -0,0 +1,20 @@ +#* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + *# +var parts = val.toString().split("."); +parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); +return parts.join(".") + "%"; http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/css/default.css ---------------------------------------------------------------------- diff --git a/src/main/web/hicc/css/default.css b/src/main/web/hicc/css/default.css index eef956e..3a2741b 100644 --- a/src/main/web/hicc/css/default.css +++ b/src/main/web/hicc/css/default.css @@ -67,8 +67,7 @@ body {font-family:Oswald,Arial;background-color:#ffffff;} .glossy_icon img { position:relative; /*this is the key*/ z-index:24; - filter:progid:DXImageTransform.Microsoft.Alpha(opacity=65); - opacity:.65; -moz-opacity: 0.65; + opacity:.65; text-decoration:none; border:none; } @@ -78,14 +77,14 @@ body {font-family:Oswald,Arial;background-color:#ffffff;} border:none; text-decoration:none; filter:progid:DXImageTransform.Microsoft.Alpha(opacity=100); - opacity:1.00; -moz-opacity: 1.00; + opacity:1.00; } .glossy_icon:hover img { z-index:25; border:none; filter:progid:DXImageTransform.Microsoft.Alpha(opacity=100); - opacity:1.00; -moz-opacity: 1.00; + opacity:1.00; } .glossy_icon span{display: none} @@ -107,7 +106,7 @@ body {font-family:Oswald,Arial;background-color:#ffffff;} .glossy_icon:disabled { border:none; filter:progid:DXImageTransform.Microsoft.Alpha(opacity=25); - opacity:.25; -moz-opacity: 0.25; + opacity:.25; } .group_box { @@ -443,7 +442,6 @@ table.simple th { border-color: #E1D8E5; background-color: #E1D8E5; font: bold 11px Arial; color:#000000; - -moz-border-radius: ; } table.simple td { text-decoration: none; @@ -451,7 +449,6 @@ table.simple td { padding: 2px; border-style: inset; border-color: #E1D8E5; - -moz-border-radius: ; } thead.fixedHead { http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/css/iframe.css ---------------------------------------------------------------------- diff --git a/src/main/web/hicc/css/iframe.css b/src/main/web/hicc/css/iframe.css index 4f7555f..493e0b1 100644 --- a/src/main/web/hicc/css/iframe.css +++ b/src/main/web/hicc/css/iframe.css @@ -16,31 +16,31 @@ * limitations under the License. */ #statisLegend table { - border-collapse: collapse; + border-collapse: collapse; + padding: 5px; } #statisLegend th strong { - color: #fff; + color: #fff; } #statisLegend th { - padding-left: 5px; - padding-right: 5px; - background: #93BC0C; - color: #fff; - text-align: center; - border-left: 1px solid #B6D59A; - border-bottom: solid 2px #fff; + padding-left: 5px; + padding-right: 5px; + background: #999999; + color: #fff; + text-align: center; + border-bottom: solid 2px #fff; } #statisLegend tr { } #statisLegend td { - padding-left: 5px; - padding-right: 5px; - border-left: 1px solid #fff; - border-bottom: 1px solid #fff; + padding-left: 5px; + padding-right: 5px; + border-left: 1px solid #fff; + border-bottom: 1px solid #fff; } #statisLegend td.first,th.first { @@ -57,8 +57,73 @@ #statisLegend { font-size: 0.85em; + margin: auto; + align: center; + overflow-x: hidden; + overflow-y: hidden; } .small_font { font-size: 0.85em; } + +#placeholder { + align: center; + width: 100%; + height: 70%; + min-height: 100px; + max-height: 480px; +} + +#placeholder canvas { + width: 100%; + height: 100%; + margin: 0 auto; + min-height: 100px; + max-height: 450px; +} + +.legendHolder { + text-align:center; + min-width: 400px; + min-height: 20px; +} + +div.center { + display: inline-block; + margin:auto; + min-width: 200px; + min-height: 20px; +} + +div.left { + display: inline-block; + margin:auto auto auto 0; + width: 20px; + height: 20px; +} + +div.right { + display: inline-block; + margin:auto 0 auto auto; + width: 20px; + height: 20px; +} + +#placeholderLegend { + margin: auto; + align: center; + overflow-x: hidden; + overflow-y: hidden; +} + +.statisTable table th td { + table-layout:fixed; + overflow:hidden; + white-space: nowrap; +} + +html, body { + height: 100%; + overflow: hidden; +} http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/js/flot.extend.js ---------------------------------------------------------------------- diff --git a/src/main/web/hicc/js/flot.extend.js b/src/main/web/hicc/js/flot.extend.js index 5af6793..d7a2056 100644 --- a/src/main/web/hicc/js/flot.extend.js +++ b/src/main/web/hicc/js/flot.extend.js @@ -15,7 +15,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -var zoom=false; +var pause=false; +var timer; var bound=null; var _chartSeriesSize=0; @@ -97,7 +98,6 @@ function calculateStatis() { } dataTable+='</table>'; $('#statisLegend').html(dataTable); - setIframeHeight(document.getElementById('boxId').value); } /* @@ -112,23 +112,31 @@ function showTooltip(x, y, contents) { } $('<div id="tooltip">' + contents + '</div>').css( { position: 'absolute', - display: 'none', - top: y + 5, - left: x + 5, - border: '2px solid #aaa', - padding: '2px', - 'background-color': '#fff', - }).appendTo("body").fadeIn(200); + display: 'none', + top: y + 5, + left: x + 5, + 'border-radius': '5px', + border: '2px solid #aaa', + padding: '2px', + 'background-color': '#fff', + }).appendTo("body").fadeIn(200); } /* * calculate the height of the area and set the correct height for the chart, legend and the statis legend as well. */ function wholePeriod() { - var cw = document.body.clientWidth-30; - var ch = height-$("#placeholderTitle").height()-10; - document.getElementById('placeholder').style.width=cw+'px'; - document.getElementById('placeholder').style.height=ch+'px'; + var ch = document.body.clientHeight; + if (ch < 200 ) { + $('#placeholderLegend').hide(); + $('#statisLegend').hide(); + } else if (ch < 320) { + $('#placeholderLegend').show(); + $('#statisLegend').hide(); + } else { + $('#placeholderLegend').show(); + $('#statisLegend').show(); + } $.plot($("#placeholder"), _series, _options); // update statis calculateStatis(); @@ -163,29 +171,29 @@ $("#placeholder").bind("plotclick", function (event, pos, item) { }; if (item) { if (previousPoint != item.datapoint) { - previousPoint = item.datapoint; - - $("#tooltip").remove(); - if(xLabels.length==0) { - var x = item.datapoint[0], - y = item.stackValue.toFixed(2); - var dnow=new Date(); - dnow.setTime(x); - var dita=leftPad(dnow.getUTCFullYear())+"/"+leftPad(dnow.getUTCMonth()+1)+"/"+dnow.getUTCDate()+" "+leftPad(dnow.getUTCHours())+":"+leftPad(dnow.getUTCMinutes())+":"+leftPad(dnow.getUTCSeconds()); - - showTooltip(item.pageX, item.pageY, - item.series.label + ": " + y + "<br>Time: " + dita); - } else { - var x = item.datapoint[0], - y = item.stackValue.toFixed(2); - xLabel = xLabels[x]; - showTooltip(item.pageX, item.pageY, - item.series.label + ": " + y + "<br>" + xLabel); - } + previousPoint = item.datapoint; + pause = true; + $("#tooltip").remove(); + if(xLabels.length==0) { + var x = item.datapoint[0], + y = item.stackValue.toFixed(2); + var dnow=new Date(); + dnow.setTime(x); + var dita=leftPad(dnow.getUTCFullYear())+"/"+leftPad(dnow.getUTCMonth()+1)+"/"+dnow.getUTCDate()+" "+leftPad(dnow.getUTCHours())+":"+leftPad(dnow.getUTCMinutes())+":"+leftPad(dnow.getUTCSeconds()); + showTooltip(item.pageX, item.pageY, + item.series.label + ": " + y + "<br>Time: " + dita); + } else { + var x = item.datapoint[0], + y = item.stackValue.toFixed(2); + xLabel = xLabels[x]; + showTooltip(item.pageX, item.pageY, + item.series.label + ": " + y + "<br>" + xLabel); + } } } else { $("#tooltip").remove(); - previousPoint = null; + previousPoint = null; + pause = false; } }); @@ -193,9 +201,13 @@ $("#placeholder").bind("plotclick", function (event, pos, item) { * bind the function for resizing the area inside the chart. */ $("#placeholder").bind("selected", function (event, area) { - zoom = true; + if(area.x1 == area.x2 && area.y1 == area.y2) { + pause = false; + } else { + pause = true; + } extra_options = {}; - extra_options.xaxis={ min: area.x1, max: area.x2 }; + extra_options.xaxis={ min: area.x1, max: area.x2 }; extra_options.yaxis={ min: area.y1, max: area.y2 }; bound = {}; bound.xmin=area.x1; @@ -204,15 +216,14 @@ $("#placeholder").bind("selected", function (event, area) { bound.ymax=area.y2; calculateStatis(); plot = $.plot( - $("#placeholder"), - _series, - $.extend( - true, - {}, - _options, extra_options - ) - ); - setIframeHeight(document.getElementById('boxId').value); + $("#placeholder"), + _series, + $.extend( + true, + {}, + _options, extra_options + ) + ); }); /* @@ -230,71 +241,30 @@ function getDocHeight(doc) { } /* - * auto resize the iframe height to match content. - */ -function setIframeHeight(ifrm) { - try { - objToResize = parent.document.getElementById(window.name); - objToResize.height = document.body.scrollHeight; - } catch(err) { - window.status = err.message; - } -} - -/* - * refresh the chart widget. + * Reload data */ -function refresh(url, parameters) { - bound=null; - if(zoom) { - wholePeriod(); - zoom=false; - } else { - if(parameters.indexOf("render=stack")>0) { - return false; - } - if(parameters.indexOf("_force_refresh")>0) { - return false; - } - var dataURL = url+"?"+parameters; - $.get(dataURL,{format: 'json'}, function(data){ - try { - eval(data); - wholePeriod(); - document.getElementById('placeholderTitle').innerHTML=chartTitle; - } catch(err) { - return false; - } - });a - if(_rest!=null) { - loadData(url, parameters); - } +function reload() { + if (!pause) { + loadData(); } - return true; + timer = setTimeout(reload, 3000); } /* * Initialize data from REST API. */ function loadData() { - _chartSeriesSize=0; - for(var i=0;i<_series.length;i++) { - $.getJSON(_rest[i], function(json) { - if(json.constructor.toString().indexOf("Array") != -1) { - for(var index=0;index<json.length;index++) { - _series[_chartSeriesSize].label=json[index].name; - _series[_chartSeriesSize].data=json[index].data; - _chartSeriesSize++; - } - } else { - var name=json.name; - _series[_chartSeriesSize].label=name; - _series[_chartSeriesSize].data=json.data; - _chartSeriesSize++; - } + $.ajax({ + url: '/hicc/v1/chart/preview/series', + type: 'PUT', + contentType: 'application/json', + data: JSON.stringify(_seriesTemplate), + dataType: "json", + success: function(result) { + _series = result; wholePeriod(); - }); - } + } + }); } /*
