From f1bdc7b6643b7f6dc91ddc9c3b45382a573236f9 Mon Sep 17 00:00:00 2001 From: gingerlime Date: Fri, 23 Aug 2013 19:42:02 +0200 Subject: [PATCH 1/9] added link to giraffe-web --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e0cd8c3..2210f3f 100644 --- a/README.md +++ b/README.md @@ -205,3 +205,4 @@ Check out the different [demo dashboards](http://kenhub.github.com/giraffe/) for ##Links, Plugins and 3rd party tools * [giraffe-collectd](https://github.com/bflad/giraffe-collectd) - A simple Giraffe configuration generator for collectd metrics in Graphite (created by @bflad) +* [giraffe-web](https://github.com/jedi4ever/giraffe-web.js) - a node.js server wrapper and cli - also allows proxying your graphite server (created by @jedi4ever) From 399746ec46aefc198e0823d39ad5e7c3aeb4ec35 Mon Sep 17 00:00:00 2001 From: Chris Rebert Date: Fri, 11 Oct 2013 16:31:38 -0700 Subject: [PATCH 2/9] reflect Bootstrap's org change Drop "Twitter" from Bootstrap's name. See https://github.com/twbs/bootstrap/issues/9899 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2210f3f..cdc4485 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Need a quick way to install and play with graphite? try [graphite-fabric](https: Giraffe is based on a number of amazing open-source projects and libraries, to name a few: * The [Rickshaw](http://code.shutterstock.com/rickshaw/) charting library (based on [d3](http://mbostock.github.com/d3/)) -* [HTML5 Boilerplate](http://html5boilerplate.com/) and [Twitter Bootstrap](https://github.com/twitter/bootstrap) +* [HTML5 Boilerplate](http://html5boilerplate.com/) and [Bootstrap](https://github.com/twbs/bootstrap) * Written in (but does not require) [Coffeescript](http://coffeescript.org) * Other libraries such as [jQuery](http://jquery.com), [underscore.js](http://underscorejs.org), [jQuery BBQ](http://benalman.com/projects/jquery-bbq-plugin/), [pagedown](), [{{mustache}}](https://github.com/janl/mustache.js/) and more @@ -20,7 +20,7 @@ Giraffe is based on a number of amazing open-source projects and libraries, to n Giraffe is heavily inspired by several existing graphite dashboards. Primarily: -* [GDash](https://github.com/ripienaar/gdash) - it uses twitter bootstrap and allows multiple dashboards to be configured. However, it requires running a sinatra server, and the graphs are pulled directly from graphite rather than rendered via a js charting library. +* [GDash](https://github.com/ripienaar/gdash) - it uses Bootstrap and allows multiple dashboards to be configured. However, it requires running a sinatra server, and the graphs are pulled directly from graphite rather than rendered via a js charting library. * [Tasseo](https://github.com/obfuscurity/tasseo) - also allows multiple dashboards, but still relies on a server component. Tasseo also uses Rickshaw, but charts only a single data series. Giraffe started as a tasseo fork, but eventually got refactored (almost) beyond recognition. * [Graphene](https://github.com/jondot/graphene) - a d3-based relatime dashboard with different widgets. Supports a single dashboard, and its charting functionality is not as extensive as with Richshaw. From a9babed1677b5ac0ad2ca019a8c6c91d9dd53890 Mon Sep 17 00:00:00 2001 From: gingerlime Date: Wed, 6 Nov 2013 10:15:58 +0100 Subject: [PATCH 3/9] Update README.md added clarification for pull requests --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index cdc4485..95cc221 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,8 @@ The core code lives in `js/src/giraffe.coffee`. Since the `dashboards.js` configuration needs easy access to everything inside `giraffe.js`, please compile the coffeescript using the `--bare` option. +* To submit a pull request, please make sure your changes are going into the original `giraffe.coffee`. Patches to the compiled `js` file cannot be merged on their own. + ##Who is behind Giraffe? Giraffe was developed at [kenHub](https://www.kenhub.com). We are not much of techie startup, but we hope to build the From 6914884dc49cb5f21b3748fe038efdbb185210f1 Mon Sep 17 00:00:00 2001 From: Yoav Date: Wed, 27 Nov 2013 11:04:36 +0100 Subject: [PATCH 4/9] added changelog and version info --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..eac4558 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog for Giraffe + +* Version 1.0.0 + - first tagged version + +## commits + +[github commit log](https://github.com/kenhub/giraffe/commits) From 95a2daa1b341812c1be5205dc1d7cb4bc8270bb1 Mon Sep 17 00:00:00 2001 From: Yoav Date: Wed, 27 Nov 2013 20:21:08 +0000 Subject: [PATCH 5/9] fixes #49 * defaulting `min` to `auto` instead of `0` --- js/giraffe.js | 4 ++-- js/src/giraffe.coffee | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js/giraffe.js b/js/giraffe.js index 55bc1b4..93aa18b 100644 --- a/js/giraffe.js +++ b/js/giraffe.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.5.0 +// Generated by CoffeeScript 1.6.3 var auth, changeDashboard, createGraph, dashboard, dataPoll, default_graphite_url, default_period, description, generateDataURL, generateEventsURL, generateGraphiteTargets, getTargetColor, graphScaffold, graphite_url, graphs, init, metrics, period, refresh, refreshSummary, refreshTimer, scheme, toggleCss, _avg, _formatBase1024KMGTP, _last, _max, _min, _sum; graphite_url = graphite_url || 'demo'; @@ -260,7 +260,7 @@ createGraph = function(anchor, metric) { element: $("" + anchor + " .chart")[0], width: $("" + anchor + " .chart").width(), height: metric.height || 300, - min: metric.min || 0, + min: metric.min || 'auto', max: metric.max, null_as: metric.null_as === void 0 ? null : metric.null_as, renderer: metric.renderer || 'area', diff --git a/js/src/giraffe.coffee b/js/src/giraffe.coffee index c78baff..0ec8a66 100644 --- a/js/src/giraffe.coffee +++ b/js/src/giraffe.coffee @@ -179,7 +179,7 @@ createGraph = (anchor, metric) -> element: $("#{anchor} .chart")[0] width: $("#{anchor} .chart").width() height: metric.height || 300 - min: metric.min || 0 + min: metric.min || 'auto' max: metric.max null_as: if metric.null_as is undefined then null else metric.null_as renderer: metric.renderer || 'area' From bd78f1c4cf56c1d159c2f3e0af24fcbfc00327b3 Mon Sep 17 00:00:00 2001 From: Yoav Date: Wed, 27 Nov 2013 20:25:54 +0000 Subject: [PATCH 6/9] updating changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eac4558..10ff9e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Changelog for Giraffe +* Version 1.0.1 - min default set to `auto` (#49) * Version 1.0.0 - first tagged version From 243fe29939bd2988a6ce77654d6c147d35efc954 Mon Sep 17 00:00:00 2001 From: Mikael Langer Date: Thu, 2 Jan 2014 22:37:57 +0100 Subject: [PATCH 7/9] Make some more things configurable: * Stroke color in area renderer can be a function that takes the graph color as a d3.rgb color and returns the color of the stroke * Format y axis ticks and totals values with a formatting function, `ticks_formatter` and `totals_formatter` respectively, just like `summary_formatter`. * Totals fields can be selected by passing an array of strings, e.g. `["max", "min"]`. --- dashboards.js | 4 ++++ js/giraffe.js | 54 ++++++++++++++++++++++++++++++++----------- js/src/giraffe.coffee | 36 ++++++++++++++++++++--------- 3 files changed, 69 insertions(+), 25 deletions(-) diff --git a/dashboards.js b/dashboards.js index d229f4f..5d7d5cf 100644 --- a/dashboards.js +++ b/dashboards.js @@ -22,6 +22,7 @@ var dashboards = "description": "New signups to the website", // enter your metric description here "summary": "sum", // available options: [sum|min|max|avg|last|] "summary_formatter": d3.format(",f") // customize your summary format function. see d3 formatting docs for more options + // also supported are tick_formatter to customize y axis ticks, and totals_formatter to format the values in the legend }, { "alias": "signup breakdown", @@ -99,6 +100,7 @@ var dashboards = "description": "cpu utilization on production (using linear interpolation). Summary displays the average across all series", "interpolation": "linear", // you can use different rickshaw interpolation values "stroke_width": 1, // change stroke width + "stroke": stroke, // stoke may be true, false or a function that takes and returns a d3 rgb color to style the stroke "summary": "avg", }, { @@ -184,3 +186,5 @@ var scheme = [ function relative_period() { return (typeof period == 'undefined') ? 1 : parseInt(period / 7) + 1; } function entire_period() { return (typeof period == 'undefined') ? 1 : period; } function at_least_a_day() { return entire_period() >= 1440 ? entire_period() : 1440; } + +function stroke(color) { return color.brighter().brighter() } diff --git a/js/giraffe.js b/js/giraffe.js index 93aa18b..ce9b341 100644 --- a/js/giraffe.js +++ b/js/giraffe.js @@ -1,5 +1,6 @@ // Generated by CoffeeScript 1.6.3 -var auth, changeDashboard, createGraph, dashboard, dataPoll, default_graphite_url, default_period, description, generateDataURL, generateEventsURL, generateGraphiteTargets, getTargetColor, graphScaffold, graphite_url, graphs, init, metrics, period, refresh, refreshSummary, refreshTimer, scheme, toggleCss, _avg, _formatBase1024KMGTP, _last, _max, _min, _sum; +var auth, changeDashboard, createGraph, dashboard, dataPoll, default_graphite_url, default_period, description, generateDataURL, generateEventsURL, generateGraphiteTargets, getTargetColor, graphScaffold, graphite_url, graphs, init, metrics, period, refresh, refreshSummary, refreshTimer, scheme, toggleCss, _avg, _formatBase1024KMGTP, _last, _max, _min, _sum, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; graphite_url = graphite_url || 'demo'; @@ -253,6 +254,8 @@ createGraph = function(anchor, metric) { targets: metric.target || metric.targets, summary: metric.summary, summary_formatter: metric.summary_formatter || _formatBase1024KMGTP, + totals_formatter: metric.totals_formatter || _formatBase1024KMGTP, + totals_fields: metric.totals_fields || ["sum", "min", "max", "avg"], scheme: metric.scheme || dashboard.scheme || scheme || 'classic9', annotator_target: ((_ref1 = metric.annotator) != null ? _ref1.target : void 0) || metric.annotator, annotator_description: ((_ref2 = metric.annotator) != null ? _ref2.description : void 0) || 'deployment', @@ -267,6 +270,7 @@ createGraph = function(anchor, metric) { interpolation: metric.interpolation || 'step-before', unstack: metric.unstack === void 0 ? unstackable : metric.unstack, stroke: metric.stroke === false ? false : true, + stroke_fn: typeof metric.stroke === "function" ? metric.stroke : void 0, strokeWidth: metric.stroke_width, dataURL: generateDataURL(metric.target || metric.targets), onRefresh: function(transport) { @@ -281,7 +285,7 @@ createGraph = function(anchor, metric) { xAxis.render(); yAxis = new Rickshaw.Graph.Axis.Y({ graph: graph, - tickFormat: function(y) { + tickFormat: metric.tick_formatter || function(y) { return _formatBase1024KMGTP(y); }, ticksTreatment: 'glow' @@ -359,17 +363,31 @@ Rickshaw.Graph.JSONP.Graphite = Rickshaw.Class.create(Rickshaw.Graph.JSONP, { }); }, addTotals: function(i) { - var avg, label, max, min, series_data, sum; + var avg, label, max, min, series_data, sum, totals; label = $(this.legend.lines[i].element).find('span.label').text(); $(this.legend.lines[i].element).find('span.totals').remove(); series_data = _.map(this.legend.lines[i].series.data, function(d) { return d.y; }); - sum = _formatBase1024KMGTP(_sum(series_data)); - max = _formatBase1024KMGTP(_max(series_data)); - min = _formatBase1024KMGTP(_min(series_data)); - avg = _formatBase1024KMGTP(_avg(series_data)); - return $(this.legend.lines[i].element).append(" Σ: " + sum + " : " + min + " : " + max + " : " + avg + ""); + sum = this.args.totals_formatter(_sum(series_data)); + max = this.args.totals_formatter(_max(series_data)); + min = this.args.totals_formatter(_min(series_data)); + avg = this.args.totals_formatter(_avg(series_data)); + totals = ""; + if (__indexOf.call(this.args.totals_fields, "sum") >= 0) { + totals = totals + (" Σ: " + sum); + } + if (__indexOf.call(this.args.totals_fields, "min") >= 0) { + totals = totals + (" : " + min); + } + if (__indexOf.call(this.args.totals_fields, "max") >= 0) { + totals = totals + (" : " + max); + } + if (__indexOf.call(this.args.totals_fields, "avg") >= 0) { + totals = totals + (" : " + avg); + } + totals += ""; + return $(this.legend.lines[i].element).append(totals); }, preProcess: function(result) { var item, _i, _len; @@ -387,7 +405,7 @@ Rickshaw.Graph.JSONP.Graphite = Rickshaw.Class.create(Rickshaw.Graph.JSONP, { return result; }, parseGraphiteData: function(d, null_as) { - var palette, rev_xy, targets; + var palette, rev_xy, stroke_fn, targets; if (null_as == null) { null_as = null; } @@ -403,6 +421,7 @@ Rickshaw.Graph.JSONP.Graphite = Rickshaw.Class.create(Rickshaw.Graph.JSONP, { scheme: this.args.scheme }); targets = this.args.target || this.args.targets; + stroke_fn = this.args.stroke_fn; d = _.map(d, function(el) { var color, _ref; if ((_ref = typeof targets) === "string" || _ref === "function") { @@ -411,9 +430,10 @@ Rickshaw.Graph.JSONP.Graphite = Rickshaw.Class.create(Rickshaw.Graph.JSONP, { color = getTargetColor(targets, el.target) || palette.color(); } return { - "color": color, - "name": el.target, - "data": rev_xy(el.datapoints) + color: color, + stroke: stroke_fn != null ? stroke_fn(d3.rgb(color)) : void 0, + name: el.target, + data: rev_xy(el.datapoints) }; }); Rickshaw.Series.zeroFill(d); @@ -488,7 +508,8 @@ Rickshaw.Graph.JSONP.Graphite = Rickshaw.Class.create(Rickshaw.Graph.JSONP, { Rickshaw.Graph.Demo = Rickshaw.Class.create(Rickshaw.Graph.JSONP.Graphite, { success: function(data) { - var i, palette, _i; + var i, palette, _i, + _this = this; palette = new Rickshaw.Color.Palette({ scheme: this.args.scheme }); @@ -537,7 +558,12 @@ Rickshaw.Graph.Demo = Rickshaw.Class.create(Rickshaw.Graph.JSONP.Graphite, { data: this.seriesData[6], name: 'New York' } - ] + ].map(function(s) { + if (_this.args.stroke_fn != null) { + s.stroke = _this.args.stroke_fn(d3.rgb(s.color)); + } + return s; + }) }); this.graph.renderer.unstack = this.args.unstack; this.graph.render(); diff --git a/js/src/giraffe.coffee b/js/src/giraffe.coffee index 0ec8a66..062ea27 100644 --- a/js/src/giraffe.coffee +++ b/js/src/giraffe.coffee @@ -172,6 +172,8 @@ createGraph = (anchor, metric) -> targets: metric.target || metric.targets summary: metric.summary summary_formatter: metric.summary_formatter || _formatBase1024KMGTP + totals_formatter: metric.totals_formatter || _formatBase1024KMGTP + totals_fields: metric.totals_fields || ["sum", "min", "max", "avg"] scheme: metric.scheme || dashboard.scheme || scheme || 'classic9' annotator_target: metric.annotator?.target || metric.annotator annotator_description: metric.annotator?.description || 'deployment' @@ -186,6 +188,7 @@ createGraph = (anchor, metric) -> interpolation: metric.interpolation || 'step-before' unstack: if metric.unstack is undefined then unstackable else metric.unstack stroke: if metric.stroke is false then false else true + stroke_fn: metric.stroke if typeof metric.stroke is "function" strokeWidth: metric.stroke_width dataURL: generateDataURL(metric.target || metric.targets) onRefresh: (transport) -> @@ -198,9 +201,7 @@ createGraph = (anchor, metric) -> xAxis.render() yAxis = new Rickshaw.Graph.Axis.Y graph: graph - # tickFormat: d3.format(".2r") #Rickshaw.Fixtures.Number.formatBase1024KMGTP(y).toFixed(2).replace('.00','') - # tickFormat: (y) -> Rickshaw.Fixtures.Number.formatBase1024KMGTP(d3.format(".2r")(y)) #.toFixed(2).replace('.00','') - tickFormat: (y) -> _formatBase1024KMGTP(y) #.toFixed(2).replace('.00','') + tickFormat: metric.tick_formatter || (y) -> _formatBase1024KMGTP(y) ticksTreatment: 'glow' yAxis.render() # element: $("#{anchor} .y-axis")[0] @@ -238,7 +239,6 @@ Rickshaw.Graph.JSONP.Graphite = Rickshaw.Class.create(Rickshaw.Graph.JSONP, result_data = @preProcess(result_data) # success is called once to build the initial graph @success(@parseGraphiteData(result_data, @args.null_as)) if not @graph - series = @parseGraphiteData(result_data, @args.null_as) annotations = @parseGraphiteData(_.filter(result, (el) => el.target == @args.annotator_target.replace(/["']/g, '')), @args.null_as) if @args.annotator_target @@ -259,13 +259,19 @@ Rickshaw.Graph.JSONP.Graphite = Rickshaw.Class.create(Rickshaw.Graph.JSONP, label = $(@legend.lines[i].element).find('span.label').text() $(@legend.lines[i].element).find('span.totals').remove() series_data = _.map(@legend.lines[i].series.data, (d) -> d.y) - sum = _formatBase1024KMGTP(_sum(series_data)) - max = _formatBase1024KMGTP(_max(series_data)) - min = _formatBase1024KMGTP(_min(series_data)) - avg = _formatBase1024KMGTP(_avg(series_data)) + sum = @args.totals_formatter(_sum(series_data)) + max = @args.totals_formatter(_max(series_data)) + min = @args.totals_formatter(_min(series_data)) + avg = @args.totals_formatter(_avg(series_data)) - $(@legend.lines[i].element).append(" Σ: #{sum} : #{min} : #{max} : #{avg}") + totals = "" + totals = totals + " Σ: #{sum}" if "sum" in @args.totals_fields + totals = totals + " : #{min}" if "min" in @args.totals_fields + totals = totals + " : #{max}" if "max" in @args.totals_fields + totals = totals + " : #{avg}" if "avg" in @args.totals_fields + totals += "" + $(@legend.lines[i].element).append(totals) preProcess: (result) -> for item in result @@ -293,12 +299,18 @@ Rickshaw.Graph.JSONP.Graphite = Rickshaw.Class.create(Rickshaw.Graph.JSONP, palette = new Rickshaw.Color.Palette scheme: @args.scheme targets = @args.target || @args.targets + stroke_fn = @args.stroke_fn d = _.map d, (el) -> if typeof targets in ["string", "function"] color = palette.color() else color = getTargetColor(targets, el.target) || palette.color() - return {"color": color, "name": el.target, "data": rev_xy(el.datapoints)} + return { + color: color + stroke: stroke_fn(d3.rgb(color)) if stroke_fn? + name: el.target + data: rev_xy(el.datapoints) + } Rickshaw.Series.zeroFill(d) return d @@ -394,7 +406,9 @@ Rickshaw.Graph.Demo = Rickshaw.Class.create(Rickshaw.Graph.JSONP.Graphite, data: @seriesData[6], name: 'New York' } - ] + ].map((s) => + s.stroke = @args.stroke_fn(d3.rgb(s.color)) if @args.stroke_fn? + s) @graph.renderer.unstack = @args.unstack @graph.render() From afcd7a6f51eed50eda78618989481ac9a4d6d039 Mon Sep 17 00:00:00 2001 From: Mikael Langer Date: Fri, 3 Jan 2014 11:14:56 +0100 Subject: [PATCH 8/9] Add examples of `totals_fields`, `totals_formatter` and `tick_formatter`. --- dashboards.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dashboards.js b/dashboards.js index 5d7d5cf..9bf25c4 100644 --- a/dashboards.js +++ b/dashboards.js @@ -102,6 +102,11 @@ var dashboards = "stroke_width": 1, // change stroke width "stroke": stroke, // stoke may be true, false or a function that takes and returns a d3 rgb color to style the stroke "summary": "avg", + "totals_fields": ["min", "max", "avg"], // customize which totals are shown in the legend + "summary_formatter": format_pct, + "hover_formatter": format_pct, + "totals_formatter": format_pct, // customize the formatting of the legend totals + "tick_formatter": format_pct, // and also the y axis ticks }, { "alias": "proc mem prod", @@ -188,3 +193,4 @@ function entire_period() { return (typeof period == 'undefined') ? 1 : period; } function at_least_a_day() { return entire_period() >= 1440 ? entire_period() : 1440; } function stroke(color) { return color.brighter().brighter() } +function format_pct(n) { return d3.format(",f")(n) + "%" } From aa068a23a2deb752bbbb0e5158f4916c62367974 Mon Sep 17 00:00:00 2001 From: Yoav Date: Fri, 3 Jan 2014 15:11:00 +0000 Subject: [PATCH 9/9] bumped to version 1.0.2 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10ff9e2..9c56b7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog for Giraffe +* Version 1.0.2 - more configuration options + - Stroke color in area renderer can be a function that takes the graph color + as a d3.rgb color and returns the color of the stroke + - Format y axis ticks and totals values with a formatting function, + `ticks_formatter` and `totals_formatter` respectively, + just like `summary_formatter` + - Totals fields can be selected by passing an array of strings, e.g. + `"totals_fields": ["max", "min"]` * Version 1.0.1 - min default set to `auto` (#49) * Version 1.0.0 - first tagged version