graphite-coffee is a small library written in CoffeeScript that makes it slightly easier to programatically generate Graphite URLs:
g = new GraphiteUrl "https://graphite.example.com/render/",
title: 'Cluster Overprovisioning'
width: 1000
from: '-1day'
until: 'now'
bgcolor: 'FFFFFF'
fgcolor: '000000'
yMin: 0
tz: 'America/Denver'
height: 400
clusters = [ '1', '1_3', '2_14', '3', '4', '5', '6', '7_11', '8', '9_10', '12_13' ]
_load =
g.sumSeries ->
(g.multiplySeries(g.s("clusters.app_cluster.#{c}.cpu"), g.s("clusters.app_cluster.#{c}.instances")) for c in clusters)
_capacity =
g.sumSeries g.s("clusters.app_cluster.*.instances")
g.target ->
g.divideSeries(g.diffSeries(_capacity, _load), _capacity)
.alias('overprovisioning %')
.cactiStyle()
url = g.render()Initialize an instance of GraphiteUrl with the URL to your graphite installation. You can also pass some URL options:
g = new GraphiteUrl "http://graphite.example.com/render/",
title: "My Graphite Graph"Add or change attributes with attr:
g.attr 'width', 600
g.attr 'height', 300Add a new target, or line on your graph, with target:
g.target g.s('path.to.series.blah')Series (like path.to.series.blah above) must be wrapped in s.
Apply Graphite functions to your data:
g.target ->
g.dashed -> # makes this series a dashed line
g.sumSeries g.s('series1'), g.s('series2')(Read about all available functions here.)
In addition to the functional style used above, you can also call Graphite functions as methods on Series objects. When you make a method call on a Series, that Series will be the first argument to the Graphite function, and the arguments passed to the method will be the rest.
These two examples are equivalent:
g.target ->
g.dashed ->
g.alias ->
g.sumSeries(g.s('series*'))
, 'My Series'
g.target ->
g.sumSeries(g.s('series*')).alias('My Series').dashed()For functions that take non-Series arguments, any Series provided will be pulled to the front of the argument list. What that means is that these two examples both work, the second (hopefully) being more readable:
g.target ->
g.alias ->
g.lineWidth ->
g.sumSeries ->
[ g.s('series1'), s.g('series2') ]
, 2
, 'Summed Series'
g.target ->
g.alias 'Summed Series', ->
g.lineWidth 2, ->
g.sumSeries ->
[ g.s('series1'), g.s('series2') ]Reuse composed Series to DRY things up:
_load =
g.sumSeries ->
(g.multiplySeries(g.s("clusters.app_cluster.#{c}.cpu"), g.s("clusters.app_cluster.#{c}.instances")) for c in [1..10])
_capacity =
g.sumSeries g.s("clusters.app_cluster.*.instances")
g.target ->
g.cactiStyle ->
g.alias 'overprovisioning %', ->
g.divideSeries ->
g.diffSeries _capacity, _load
, _capacity
When you're done adding your targets, render the url with render:
url = g.render()Sure, but the intention was to create a pseudo-DSL for describing
Graphite graphs, and I think you lose some of that with all the
parentheses and functions that will be everywhere.