gdash 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/gdash.rb +56 -0
- data/lib/gdash/dashboard.rb +51 -0
- data/lib/gdash/monkey_patches.rb +37 -0
- data/lib/gdash/sinatra_app.rb +162 -0
- data/public/js/bootstrap-alerts.js +104 -0
- data/public/js/bootstrap-dropdown.js +50 -0
- data/public/js/bootstrap-modal.js +238 -0
- data/public/js/bootstrap-popover.js +77 -0
- data/public/js/bootstrap-scrollspy.js +105 -0
- data/public/js/bootstrap-tabs.js +62 -0
- data/public/js/bootstrap-twipsy.js +307 -0
- data/public/js/jquery-1.5.2.min.js +16 -0
- data/public/js/jquery.tablesorter.min.js +4 -0
- data/public/js/less-1.1.3.min.js +16 -0
- data/public/lib/bootstrap.less +26 -0
- data/public/lib/forms.less +465 -0
- data/public/lib/mixins.less +217 -0
- data/public/lib/patterns.less +1006 -0
- data/public/lib/reset.less +141 -0
- data/public/lib/scaffolding.less +135 -0
- data/public/lib/tables.less +170 -0
- data/public/lib/type.less +187 -0
- data/public/lib/variables.less +60 -0
- data/sample/README.md +5 -0
- data/sample/email-full-screen.png +0 -0
- data/sample/email.png +0 -0
- data/sample/email/cpu.graph +19 -0
- data/sample/email/dash.yaml +2 -0
- data/sample/email/io.graph +12 -0
- data/sample/email/load.graph +6 -0
- data/sample/email/network.graph +11 -0
- data/views/README.md +177 -0
- data/views/_interval_filter.erb +5 -0
- data/views/dashboard.erb +44 -0
- data/views/detailed_dashboard.erb +45 -0
- data/views/full_size_dashboard.erb +24 -0
- data/views/index.erb +18 -0
- data/views/layout.erb +53 -0
- metadata +146 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
/* Variables.less
|
2
|
+
* Variables to customize the look and feel of Bootstrap
|
3
|
+
* ----------------------------------------------------- */
|
4
|
+
|
5
|
+
|
6
|
+
// Links
|
7
|
+
@linkColor: #0069d6;
|
8
|
+
@linkColorHover: darken(@linkColor, 15);
|
9
|
+
|
10
|
+
// Grays
|
11
|
+
@black: #000;
|
12
|
+
@grayDark: lighten(@black, 25%);
|
13
|
+
@gray: lighten(@black, 50%);
|
14
|
+
@grayLight: lighten(@black, 75%);
|
15
|
+
@grayLighter: lighten(@black, 90%);
|
16
|
+
@white: #fff;
|
17
|
+
|
18
|
+
// Accent Colors
|
19
|
+
@blue: #049CDB;
|
20
|
+
@blueDark: #0064CD;
|
21
|
+
@green: #46a546;
|
22
|
+
@red: #9d261d;
|
23
|
+
@yellow: #ffc40d;
|
24
|
+
@orange: #f89406;
|
25
|
+
@pink: #c3325f;
|
26
|
+
@purple: #7a43b6;
|
27
|
+
|
28
|
+
// Baseline grid
|
29
|
+
@basefont: 13px;
|
30
|
+
@baseline: 18px;
|
31
|
+
|
32
|
+
// Griditude
|
33
|
+
// Modify the grid styles in mixins.less
|
34
|
+
@gridColumns: 16;
|
35
|
+
@gridColumnWidth: 60px;
|
36
|
+
@gridGutterWidth: 10px;
|
37
|
+
@extraSpace: (@gridGutterWidth * 2); // For our grid calculations
|
38
|
+
@siteWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1));
|
39
|
+
|
40
|
+
// Color Scheme
|
41
|
+
// Use this to roll your own color schemes if you like (unused by Bootstrap by default)
|
42
|
+
@baseColor: @blue; // Set a base color
|
43
|
+
@complement: spin(@baseColor, 180); // Determine a complementary color
|
44
|
+
@split1: spin(@baseColor, 158); // Split complements
|
45
|
+
@split2: spin(@baseColor, -158);
|
46
|
+
@triad1: spin(@baseColor, 135); // Triads colors
|
47
|
+
@triad2: spin(@baseColor, -135);
|
48
|
+
@tetra1: spin(@baseColor, 90); // Tetra colors
|
49
|
+
@tetra2: spin(@baseColor, -90);
|
50
|
+
@analog1: spin(@baseColor, 22); // Analogs colors
|
51
|
+
@analog2: spin(@baseColor, -22);
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
// More variables coming soon:
|
56
|
+
// - @basefont to @baseFontSize
|
57
|
+
// - @baseline to @baseLineHeight
|
58
|
+
// - @baseFontFamily
|
59
|
+
// - @primaryButtonColor
|
60
|
+
// - anything else? File an issue on GitHub
|
data/sample/README.md
ADDED
Binary file
|
data/sample/email.png
ADDED
Binary file
|
@@ -0,0 +1,19 @@
|
|
1
|
+
title "Combined CPU Usage"
|
2
|
+
vtitle "percent"
|
3
|
+
area :stacked
|
4
|
+
description "The combined CPU usage for all Exim Anti Spam servers"
|
5
|
+
|
6
|
+
field :iowait, :scale => 0.001,
|
7
|
+
:color => "red",
|
8
|
+
:alias => "IO Wait",
|
9
|
+
:data => "sumSeries(derivative(mw*.munin.cpu.iowait))"
|
10
|
+
|
11
|
+
field :system, :scale => 0.001,
|
12
|
+
:color => "orange",
|
13
|
+
:alias => "System",
|
14
|
+
:data => "sumSeries(derivative(mw*.munin.cpu.system))"
|
15
|
+
|
16
|
+
field :user, :scale => 0.001,
|
17
|
+
:color => "yellow",
|
18
|
+
:alias => "User",
|
19
|
+
:data => "sumSeries(derivative(mw*.munin.cpu.user))"
|
@@ -0,0 +1,12 @@
|
|
1
|
+
title "Combined IO"
|
2
|
+
area :first
|
3
|
+
vtitle "blocks"
|
4
|
+
|
5
|
+
field :down, :color => "blue",
|
6
|
+
:alias => "Writes",
|
7
|
+
:data => "sumSeries(derivative(mw*.munin.iostat.dev*_write))"
|
8
|
+
|
9
|
+
field :up, :color => "green",
|
10
|
+
:alias => "Reads",
|
11
|
+
:data => "sumSeries(derivative(mw*.munin.iostat.dev*_read))"
|
12
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
title "Combined Network Usage"
|
2
|
+
vtitle "bps"
|
3
|
+
area :first
|
4
|
+
|
5
|
+
field :up, :color => "green",
|
6
|
+
:alias => "Up",
|
7
|
+
:data => "sumSeries(nonNegativeDerivative(mw*.munin.if_*.up))"
|
8
|
+
|
9
|
+
field :down, :color => "blue",
|
10
|
+
:alias => "Down",
|
11
|
+
:data => "sumSeries(nonNegativeDerivative(mw*.munin.if_*.down))"
|
data/views/README.md
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
What?
|
2
|
+
=====
|
3
|
+
|
4
|
+
A simple Graphite dashboard built using Twitter's Bootstrap.
|
5
|
+
|
6
|
+
Adding new dashboards is very easy and individual graphs are
|
7
|
+
described using a small DSL.
|
8
|
+
|
9
|
+
See the _sample_ directory for a sample dashboard configuration.
|
10
|
+
|
11
|
+

|
12
|
+
|
13
|
+
Config?
|
14
|
+
-------
|
15
|
+
|
16
|
+
This dashboard is a Sinatra application, I suggest deploying it
|
17
|
+
in Passenger or other Sinatra application server.
|
18
|
+
|
19
|
+
A sample _gdash.yaml-sample_ is included, you should rename it to
|
20
|
+
_gdash.yaml_ and adjust the url to your Graphite etc in there.
|
21
|
+
|
22
|
+
The SinatraApp class take two required arguments:
|
23
|
+
|
24
|
+
* Where graphite is installed
|
25
|
+
* The directory that has your _dashboards_ directory full of templates
|
26
|
+
|
27
|
+
and additional options:
|
28
|
+
|
29
|
+
* The title to show at the top of your Graphite
|
30
|
+
* A prefix to prepend to all URLs in the dashboard
|
31
|
+
* How many columns of graphs to create, 2 by default.
|
32
|
+
* How often dashboard page is refreshed, 60 sec by default.
|
33
|
+
* The width of the graphs, 500 by default
|
34
|
+
* The height of the graphs, 250 by default
|
35
|
+
* Where your whisper files are stored - future use
|
36
|
+
* Optional interval quick filters
|
37
|
+
|
38
|
+
Creating Dashboards?
|
39
|
+
--------------------
|
40
|
+
|
41
|
+
You can have multiple top level categories of dashboard. Just create directories
|
42
|
+
in the _templatedir_ for each top level category.
|
43
|
+
|
44
|
+
In each top level category create a sub directory with a short name for each new dashboard.
|
45
|
+
|
46
|
+
You need a file called _dash.yaml_ for each dashboard, here is a sample:
|
47
|
+
|
48
|
+
:name: Email Metrics
|
49
|
+
:description: Hourly metrics for the email system
|
50
|
+
|
51
|
+
Then create descriptions in files like _cpu.graph_ in the same directory, here
|
52
|
+
is a sample:
|
53
|
+
|
54
|
+
title "Combined CPU Usage"
|
55
|
+
vtitle "percent"
|
56
|
+
area :stacked
|
57
|
+
description "The combined CPU usage for all Exim Anti Spam servers"
|
58
|
+
|
59
|
+
field :iowait, :scale => 0.001,
|
60
|
+
:color => "red",
|
61
|
+
:alias => "IO Wait",
|
62
|
+
:data => "sumSeries(derivative(mw*munin.cpu.iowait))"
|
63
|
+
|
64
|
+
field :system, :scale => 0.001,
|
65
|
+
:color => "orange",
|
66
|
+
:alias => "System",
|
67
|
+
:data => "sumSeries(derivative(mw*.munin.cpu.system))"
|
68
|
+
|
69
|
+
field :user, :scale => 0.001,
|
70
|
+
:color => "yellow",
|
71
|
+
:alias => "User",
|
72
|
+
:data => "sumSeries(derivative(mw*.munin.cpu.user))"
|
73
|
+
|
74
|
+
The dashboard will use the _description_ field to show popup information bubbles
|
75
|
+
when someone hovers over a graph with their mouse for 2 seconds.
|
76
|
+
|
77
|
+
The graphs are described using a DSL that has its own project and documented
|
78
|
+
over at https://github.com/ripienaar/graphite-graph-dsl/wiki
|
79
|
+
|
80
|
+
At the moment we do not support the _Related Items_ feature of the DSL.
|
81
|
+
|
82
|
+
Template Directory Layout?
|
83
|
+
--------------------------
|
84
|
+
|
85
|
+
The directory layout is such that you can have many groupins of dashboards each with
|
86
|
+
many dashboards underneath it, an example layout of your templates dir would be:
|
87
|
+
|
88
|
+
graph_templates
|
89
|
+
`-- virtualization
|
90
|
+
|-- dom0
|
91
|
+
| |-- dash.yaml
|
92
|
+
| |-- iowait.graph
|
93
|
+
| |-- load.graph
|
94
|
+
| |-- system.graph
|
95
|
+
| |-- threads.graph
|
96
|
+
| `-- user.graph
|
97
|
+
`-- kvm1
|
98
|
+
|-- dash.yaml
|
99
|
+
|-- disk_read.graph
|
100
|
+
|-- disk_write.graph
|
101
|
+
|-- ssd_read.graph
|
102
|
+
`-- ssd_write.graph
|
103
|
+
|
104
|
+
Here we have a group of dashboards called 'virtualization' with 2 dashboards inside it
|
105
|
+
each with numerous graphs.
|
106
|
+
|
107
|
+
You can create as many groups as you want each with many dashboards inside.
|
108
|
+
|
109
|
+
Custom Time Intervals?
|
110
|
+
--------------------
|
111
|
+
|
112
|
+
You can reuse your dashboards and adjust the time interval by using the following url
|
113
|
+
structure:
|
114
|
+
|
115
|
+
http://gdash.example.com/dashboard/email/time/-8d/-7d
|
116
|
+
|
117
|
+
or
|
118
|
+
|
119
|
+
http://gdash.example.com/dashboard/email/?from=-8d&until=-7d
|
120
|
+
http://gdash.example.com/dashboard/email/full/2/600/300?from=-8d&until=-7d
|
121
|
+
|
122
|
+
This will display the _email_ dashboard with a time interval same day last week.
|
123
|
+
If you hit */dashboard/email/time/* it will default to the past hour (*-1hour*)
|
124
|
+
See http://graphite.readthedocs.org/en/1.0/url-api.html#from-until for more info
|
125
|
+
acceptable *from* and *until* values.
|
126
|
+
|
127
|
+
Quick interval filters shown in interface are configurable in _gdash.yaml_ options sections. Eg:
|
128
|
+
|
129
|
+
:options:
|
130
|
+
:interval_filters:
|
131
|
+
- :label: Last Hour
|
132
|
+
:from: -1h
|
133
|
+
:to: now
|
134
|
+
- :label: Last Day
|
135
|
+
:from: -1day
|
136
|
+
- :label: Current Week
|
137
|
+
:from: monday
|
138
|
+
:to: now
|
139
|
+
|
140
|
+
Quick filter is not shown when *interval_filters* section is missing in configuration file.
|
141
|
+
|
142
|
+
Time Intervals Display?
|
143
|
+
-----------------------
|
144
|
+
|
145
|
+
If you configure time intervals in the config file you can click on any graph in
|
146
|
+
the main dashboard view and get a view with different time intervals of the same
|
147
|
+
graph
|
148
|
+
|
149
|
+
:options:
|
150
|
+
:intervals:
|
151
|
+
- [ "-1hour", "1 hour" ]
|
152
|
+
- [ "-2hour", "2 hour" ]
|
153
|
+
- [ "-1day", "1 day" ]
|
154
|
+
- [ "-1month", "1 month" ]
|
155
|
+
- [ "-1year", "1 year" ]
|
156
|
+
|
157
|
+
With this in place in the _config.yaml_ clicking on a graph will show the 5 intervals
|
158
|
+
defined above of that graph
|
159
|
+
|
160
|
+
Full Screen Displays?
|
161
|
+
---------------------
|
162
|
+
|
163
|
+
You can reuse your dashboards for big displays against a wall in your NOC or office
|
164
|
+
by using the following url structure:
|
165
|
+
|
166
|
+
http://gdash.example.com/dashboard/email/full/4/600/300
|
167
|
+
http://gdash.example.com/dashboard/email/full/4?width=600&height=300
|
168
|
+
|
169
|
+
This will display the _email_ dashboard in _4_ columns each graph with a width of
|
170
|
+
_600_ and a height of _300_
|
171
|
+
|
172
|
+
The screen will refresh every minute
|
173
|
+
|
174
|
+
Contact?
|
175
|
+
--------
|
176
|
+
|
177
|
+
R.I.Pienaar / rip@devco.net / http://www.devco.net/ / @ripienaar
|
data/views/dashboard.erb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
<% unless @error %>
|
2
|
+
<h1><%= @dashboard.name %> <small><%= @dashboard.description %></small></h1>
|
3
|
+
<%= erb :_interval_filter, :layout => false unless @interval_filters.empty? %>
|
4
|
+
<div class="row">
|
5
|
+
<table>
|
6
|
+
<% row = 1 %>
|
7
|
+
<% grouped_graphs = @dashboard.graphs.in_groups_of(@graph_columns) %>
|
8
|
+
<% grouped_graphs.each do |graphs| %>
|
9
|
+
<tr>
|
10
|
+
<% graphs.each do |graph| %>
|
11
|
+
<% i = grouped_graphs.rindex(graphs) * @graph_columns + graphs.rindex(graph) %>
|
12
|
+
<td>
|
13
|
+
<% if graph %>
|
14
|
+
<% if graph[:graphite][:description] %>
|
15
|
+
<a href='<%= [@prefix, params[:category], @params[:dash], 'details', i].join "/" %>'>
|
16
|
+
<img src='<%= [@top_level[@params[:category]].graphite_render, graph[:graphite][:url]].join "?" %>' rel="<%= row == 1 ? 'popover-below' : 'popover-above' %>" title="<%= graph[:graphite][:title] %>" data-content="<%= graph[:graphite][:description] %>"></a>
|
17
|
+
<% else %>
|
18
|
+
<a href='<%= [@prefix, params[:category], @params[:dash], 'details', i].join "/" %>'>
|
19
|
+
<img src='<%= [@top_level[@params[:category]].graphite_render, graph[:graphite][:url]].join "?" %>'></a>
|
20
|
+
<% end %>
|
21
|
+
<% end %>
|
22
|
+
</td>
|
23
|
+
<% end %>
|
24
|
+
</tr>
|
25
|
+
<% row += 1 %>
|
26
|
+
<% end %>
|
27
|
+
</table>
|
28
|
+
</div>
|
29
|
+
<script>
|
30
|
+
$(function () {
|
31
|
+
$("img[rel=popover-above]")
|
32
|
+
.popover({
|
33
|
+
placement: "above", delayIn: 1000
|
34
|
+
})
|
35
|
+
})
|
36
|
+
|
37
|
+
$(function () {
|
38
|
+
$("img[rel=popover-below]")
|
39
|
+
.popover({
|
40
|
+
placement: "below", delayIn: 1000
|
41
|
+
})
|
42
|
+
})
|
43
|
+
</script>
|
44
|
+
<% end %>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<% unless @error %>
|
2
|
+
<h1><%= @dashboard.name %> <small><%= @dashboard.description %></small></h1>
|
3
|
+
<div class="row">
|
4
|
+
<table>
|
5
|
+
<% row = 1 %>
|
6
|
+
<% @graphs.in_groups_of(@graph_columns) do |graphrows| %>
|
7
|
+
<tr>
|
8
|
+
<% graphrows.each do |graph| %>
|
9
|
+
<td>
|
10
|
+
<% if graph %>
|
11
|
+
<% if graph[:description] %>
|
12
|
+
<img src='<%= [@top_level[@params[:category]].graphite_render, graph[:url]].join "?" %>' rel="<%= row == 1 ? 'popover-below' : 'popover-above' %>" title="<%= graph[:title] %>" data-content="<%= graph[:description] %>">
|
13
|
+
<% else %>
|
14
|
+
<img src='<%= [@top_level[@params[:category]].graphite_render, graph[:url]].join "?" %>'>
|
15
|
+
<% end %>
|
16
|
+
<% end %>
|
17
|
+
</td>
|
18
|
+
<% end %>
|
19
|
+
</tr>
|
20
|
+
<% row += 1 %>
|
21
|
+
<% end %>
|
22
|
+
</table>
|
23
|
+
</div>
|
24
|
+
<script>
|
25
|
+
$(function () {
|
26
|
+
$("img[rel=popover-above]")
|
27
|
+
.popover({
|
28
|
+
placement: "above", delayIn: 1000
|
29
|
+
})
|
30
|
+
.click(function(e) {
|
31
|
+
e.preventDefault()
|
32
|
+
})
|
33
|
+
})
|
34
|
+
|
35
|
+
$(function () {
|
36
|
+
$("img[rel=popover-below]")
|
37
|
+
.popover({
|
38
|
+
placement: "below", delayIn: 1000
|
39
|
+
})
|
40
|
+
.click(function(e) {
|
41
|
+
e.preventDefault()
|
42
|
+
})
|
43
|
+
})
|
44
|
+
</script>
|
45
|
+
<% end %>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<meta http-equiv="refresh" content="60">
|
4
|
+
</head>
|
5
|
+
<% if @error %>
|
6
|
+
<h2><%= @error %></h2>
|
7
|
+
<% else %>
|
8
|
+
<body bgcolor="black">
|
9
|
+
<table width="100%" height="100%">
|
10
|
+
<% @dashboard.graphs.in_groups_of(params["columns"]) do |graphs| %>
|
11
|
+
<tr>
|
12
|
+
<% graphs.each do |graph| %>
|
13
|
+
<td valign="middle" align="center">
|
14
|
+
<% if graph %>
|
15
|
+
<img src='<%= [@top_level[@params[:category]].graphite_render, graph[:graphite][:url]].join "?" %>'>
|
16
|
+
<% end %>
|
17
|
+
</td>
|
18
|
+
<% end %>
|
19
|
+
</tr>
|
20
|
+
<% end %>
|
21
|
+
</table>
|
22
|
+
</body>
|
23
|
+
<% end %>
|
24
|
+
</html>
|
data/views/index.erb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
<% unless @error %>
|
2
|
+
<% @top_level.keys.sort.each do |key| %>
|
3
|
+
<h2> <%= key.capitalize %> </h2>
|
4
|
+
<table>
|
5
|
+
<thead>
|
6
|
+
<th width="30%">Name</th>
|
7
|
+
<th width="70%">Description</th>
|
8
|
+
</thead>
|
9
|
+
<tbody>
|
10
|
+
<% @top_level[key].dashboards.sort_by{|b| b[:name]}.each do |board| %>
|
11
|
+
<tr>
|
12
|
+
<td><a href="<%= [@prefix, key, board[:link]].join('/') %>/"><%= board[:name] %></a></td><td><%= board[:description] %></td>
|
13
|
+
</tr>
|
14
|
+
<% end %>
|
15
|
+
</tbody>
|
16
|
+
</table>
|
17
|
+
<% end %>
|
18
|
+
<% end %>
|