pencil 0.2.2 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/pencil +3 -0
- data/docs/pencil_options.md +37 -4
- data/examples/dashboards.yml +25 -1
- data/examples/graphs.yml +83 -7
- data/examples/pencil.yml +3 -0
- data/lib/dash.rb +7 -1
- data/lib/helpers.rb +1 -1
- data/lib/models/dashboard.rb +1 -1
- data/lib/models/graph.rb +97 -35
- data/lib/rubyfixes.rb +8 -0
- data/lib/views/cluster.erb +3 -0
- data/lib/views/dash-cluster-zoom.erb +0 -8
- data/lib/views/layout.erb +4 -2
- data/lib/views/partials/cluster_switcher.erb +1 -0
- data/lib/views/partials/dash_switcher.erb +1 -0
- data/lib/views/partials/graph_switcher.erb +4 -1
- metadata +24 -23
data/bin/pencil
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
$: << File.dirname($0) + "/../lib"
|
3
3
|
|
4
|
+
require File.join(File.dirname(__FILE__), "..", "VERSION")
|
4
5
|
require "dash"
|
5
6
|
|
7
|
+
STDOUT.puts "pencil v#{PENCIL_VERSION} on port #{Dash::App.port}, PID #{$$}"
|
8
|
+
|
6
9
|
Rack::Handler::Mongrel.run(Dash::App, :Port => Dash::App.port)
|
data/docs/pencil_options.md
CHANGED
@@ -77,6 +77,23 @@ These are options that go under the :config key in pencil configuration files.
|
|
77
77
|
How many seconds before Time.now an end time is considered to still be 'now',
|
78
78
|
for the purposes of adding meta-refresh and displaying time intervals.
|
79
79
|
|
80
|
+
* :use_color: [Boolean, optional, default false]
|
81
|
+
|
82
|
+
In graphite 0.9.8 and earlier coloring of targets sucks. Coloring is not done
|
83
|
+
on a per-target basis, but rather by an additional parameter
|
84
|
+
"colorList". Pencil handles colors by appending a target's color parameter
|
85
|
+
(or a suitable default) onto this list. Targets are processed in order and
|
86
|
+
consume the first color available in colorList.
|
87
|
+
|
88
|
+
This sucks because nonexistent targets occasionally produced by pencil don't
|
89
|
+
consume their associated color, which screws up the coloring of every
|
90
|
+
subsequent metric.
|
91
|
+
|
92
|
+
The latest Graphite trunk supports color as a property of a target, set with
|
93
|
+
color(target, "COLOR"). If you are using a new graphite and want to take
|
94
|
+
advantage of this more accurate coloring technique set :use_color to true,
|
95
|
+
and bask in the glory of color correctness.
|
96
|
+
|
80
97
|
## <a name="gopts"/> Graph-level Options
|
81
98
|
This is a list of the supported graph-level options for pencil, which
|
82
99
|
correspond to request(image)-level options for graphite. These options are
|
@@ -103,11 +120,25 @@ minor annotations:
|
|
103
120
|
|
104
121
|
## Target-level Options
|
105
122
|
This is a list of the supported target-level options for pencil. These are
|
106
|
-
|
123
|
+
mostly a list of transformations graphite supports, including summation and
|
107
124
|
scaling of metrics. You can apply them to individual metrics, or lists of
|
108
125
|
metrics. See the example configs for how this works. Also see the graphite
|
109
126
|
composer for the effects of these options, many of which are untested.
|
110
127
|
|
128
|
+
A note on the divideSeries case: for aggregate graphs, pencil takes the ratio
|
129
|
+
of the sums, as opposed to the sums of the ratios, for ease of implementation
|
130
|
+
and because it makes some sense. If you're not a fan of 80k URLs then you will
|
131
|
+
agree. divideSeries should only ever be used with two targets, like this:
|
132
|
+
|
133
|
+
? - stats.timers.mysql.innodb.threads_active_read.mean:
|
134
|
+
- stats.timers.mysql.innodb.threads_total_read.mean:
|
135
|
+
:
|
136
|
+
!omap
|
137
|
+
- :divideSeries:
|
138
|
+
|
139
|
+
(Notice the omap, as opposed to a hash, to impose an order in which options are
|
140
|
+
applied)
|
141
|
+
|
111
142
|
### Combinations
|
112
143
|
These functions take an arbitrary number of targets (usually simple metrics)
|
113
144
|
for arguments.
|
@@ -139,7 +170,7 @@ for arguments.
|
|
139
170
|
* stdev
|
140
171
|
* asPercent
|
141
172
|
* diffSeries
|
142
|
-
*
|
173
|
+
* divideSeries (NOTE: takes exactly 1 series as divisor)
|
143
174
|
|
144
175
|
### Filters
|
145
176
|
Most of these options take a single argument.
|
@@ -172,5 +203,7 @@ Most of these options take a single argument.
|
|
172
203
|
* threshold
|
173
204
|
* color
|
174
205
|
|
175
|
-
Note: key
|
176
|
-
|
206
|
+
Note: key is interpreted differently from the other options, which are more
|
207
|
+
simply translated.
|
208
|
+
|
209
|
+
color's interpretation depends on whether :use_color is set.
|
data/examples/dashboards.yml
CHANGED
@@ -4,12 +4,30 @@
|
|
4
4
|
title: syncstorage_overview
|
5
5
|
graphs:
|
6
6
|
- syncstorage_qps:
|
7
|
-
# hosts: ["sync*_web"]
|
8
7
|
- syncstorage_401:
|
9
8
|
- syncstorage_exceptions:
|
10
9
|
- cpu_usage:
|
10
|
+
- memory_usage:
|
11
11
|
- network_traffic:
|
12
12
|
hosts: ["sync*_web", "wp-web*"]
|
13
|
+
syncreg:
|
14
|
+
title: syncreg_overview
|
15
|
+
graphs:
|
16
|
+
- syncreg_qps:
|
17
|
+
- syncreg_exceptions:
|
18
|
+
- cpu_usage:
|
19
|
+
- memory_usage:
|
20
|
+
- network_traffic:
|
21
|
+
hosts: ["wp-reg*"]
|
22
|
+
syncsreg:
|
23
|
+
title: syncsreg_overview
|
24
|
+
graphs:
|
25
|
+
- syncsreg_qps:
|
26
|
+
- syncsreg_exceptions:
|
27
|
+
- cpu_usage:
|
28
|
+
- memory_usage:
|
29
|
+
- network_traffic:
|
30
|
+
hosts: ["wp-sreg*"]
|
13
31
|
ldap_slaves:
|
14
32
|
title: LDAP slaves
|
15
33
|
graphs:
|
@@ -34,3 +52,9 @@
|
|
34
52
|
- cpu_usage:
|
35
53
|
- network_traffic:
|
36
54
|
hosts: ["sync*_db", "wp-db*"]
|
55
|
+
sync_node_alloc:
|
56
|
+
title: sync node allocation
|
57
|
+
graphs:
|
58
|
+
- sync_node_alloc:
|
59
|
+
- sync_node_actives:
|
60
|
+
hosts: ["wp-adm01"]
|
data/examples/graphs.yml
CHANGED
@@ -15,12 +15,6 @@
|
|
15
15
|
syncstorage.request_rate.404:
|
16
16
|
:key: 404
|
17
17
|
:color: purple
|
18
|
-
syncstorage.request_rate.500:
|
19
|
-
:key: 500
|
20
|
-
:color: yellow
|
21
|
-
syncstorage.request_rate.502:
|
22
|
-
:key: 502
|
23
|
-
:color: "#cc0000"
|
24
18
|
syncstorage.request_rate.503:
|
25
19
|
:key: 503
|
26
20
|
:color: red
|
@@ -31,7 +25,7 @@
|
|
31
25
|
title: "syncstorage 401s"
|
32
26
|
targets:
|
33
27
|
syncstorage.request_rate.401:
|
34
|
-
:key:
|
28
|
+
:key: 401
|
35
29
|
:color: brown
|
36
30
|
hosts: ["sync*_web", "test*_web", "wp-web*"]
|
37
31
|
|
@@ -43,6 +37,64 @@
|
|
43
37
|
:color: red
|
44
38
|
hosts: ["sync*_web", "test*_web", "wp-web*"]
|
45
39
|
|
40
|
+
syncreg_qps:
|
41
|
+
title: "syncreg qps"
|
42
|
+
targets:
|
43
|
+
syncreg.request_rate.200:
|
44
|
+
:key: 200
|
45
|
+
:color: green
|
46
|
+
syncreg.request_rate.302:
|
47
|
+
:key: 302
|
48
|
+
:color: blue
|
49
|
+
syncreg.request_rate.401:
|
50
|
+
:key: 401
|
51
|
+
:color: brown
|
52
|
+
syncreg.request_rate.404:
|
53
|
+
:key: 404
|
54
|
+
:color: purple
|
55
|
+
syncreg.request_rate.503:
|
56
|
+
:key: 503
|
57
|
+
:color: red
|
58
|
+
areaMode: stacked
|
59
|
+
hosts: ["wp-reg*"]
|
60
|
+
|
61
|
+
syncreg_exceptions:
|
62
|
+
title: "syncreg exceptions"
|
63
|
+
targets:
|
64
|
+
syncreg.log.exception:
|
65
|
+
:key: exceptions/s
|
66
|
+
:color: red
|
67
|
+
hosts: ["wp-reg*"]
|
68
|
+
|
69
|
+
syncsreg_qps:
|
70
|
+
title: "syncsreg qps"
|
71
|
+
targets:
|
72
|
+
syncsreg.request_rate.200:
|
73
|
+
:key: 200
|
74
|
+
:color: green
|
75
|
+
syncsreg.request_rate.302:
|
76
|
+
:key: 302
|
77
|
+
:color: blue
|
78
|
+
syncsreg.request_rate.401:
|
79
|
+
:key: 401
|
80
|
+
:color: brown
|
81
|
+
syncsreg.request_rate.404:
|
82
|
+
:key: 404
|
83
|
+
:color: purple
|
84
|
+
syncsreg.request_rate.503:
|
85
|
+
:key: 503
|
86
|
+
:color: red
|
87
|
+
areaMode: stacked
|
88
|
+
hosts: ["wp-sreg*"]
|
89
|
+
|
90
|
+
syncsreg_exceptions:
|
91
|
+
title: "syncsreg exceptions"
|
92
|
+
targets:
|
93
|
+
syncsreg.log.exception:
|
94
|
+
:key: exceptions/s
|
95
|
+
:color: red
|
96
|
+
hosts: ["wp-sreg*"]
|
97
|
+
|
46
98
|
cpu_usage:
|
47
99
|
title: "cpu usage"
|
48
100
|
targets:
|
@@ -145,3 +197,27 @@
|
|
145
197
|
bgcolor: "#AFFFFF"
|
146
198
|
vtitle: tvtnolgrf
|
147
199
|
lineWidth: 20
|
200
|
+
|
201
|
+
sync_node_alloc:
|
202
|
+
title: "node alloc rate"
|
203
|
+
targets:
|
204
|
+
sync.users.alloc_rate.scl2:
|
205
|
+
:key: scl2 alloc/s
|
206
|
+
:color: green
|
207
|
+
sync.users.alloc_rate.phx1:
|
208
|
+
:key: phx1 alloc/s
|
209
|
+
:color: blue
|
210
|
+
|
211
|
+
hosts: ["wp-adm01"]
|
212
|
+
|
213
|
+
sync_node_actives:
|
214
|
+
title: "node actives"
|
215
|
+
targets:
|
216
|
+
sync.users.active.scl2:
|
217
|
+
:key: scl2 actives
|
218
|
+
:color: green
|
219
|
+
sync.users.active.phx1:
|
220
|
+
:key: phx1 actives
|
221
|
+
:color: blue
|
222
|
+
|
223
|
+
hosts: ["wp-adm01"]
|
data/examples/pencil.yml
CHANGED
@@ -19,3 +19,6 @@
|
|
19
19
|
:date_format: "%X %x" # strftime
|
20
20
|
:metric_format: "%m.%c.%h" #%m metric, %c cluster, %h host
|
21
21
|
:now_threshold: 300 # Time.at(Time.now - now_threshold) considered Time.now
|
22
|
+
|
23
|
+
# set this if you have a new graphite that supports color(series, "color")
|
24
|
+
# :use_color: true
|
data/lib/dash.rb
CHANGED
@@ -15,6 +15,7 @@ require "yaml"
|
|
15
15
|
require "chronic"
|
16
16
|
require "chronic_duration"
|
17
17
|
require "optparse"
|
18
|
+
require "rubyfixes"
|
18
19
|
|
19
20
|
# fixme style.css isn't actually cached, you need to set something up with
|
20
21
|
# rack to cache static files
|
@@ -32,6 +33,7 @@ module Dash
|
|
32
33
|
use Rack::Session::Cookie, :expire_after => 126227700 # 4 years
|
33
34
|
set :root, File.dirname(__FILE__)
|
34
35
|
set :static, true
|
36
|
+
set :logging, true
|
35
37
|
|
36
38
|
def initialize(settings={})
|
37
39
|
super
|
@@ -73,7 +75,11 @@ module Dash
|
|
73
75
|
|
74
76
|
get %r[^/(dash/?)?$] do
|
75
77
|
@no_graphs = true
|
76
|
-
|
78
|
+
if settings.config.clusters.size == 1
|
79
|
+
redirect "/dash/#{settings.config.clusters.first}"
|
80
|
+
else
|
81
|
+
redirect '/dash/global'
|
82
|
+
end
|
77
83
|
end
|
78
84
|
|
79
85
|
get '/dash/:cluster/:dashboard/:zoom/?' do
|
data/lib/helpers.rb
CHANGED
@@ -188,7 +188,7 @@ module Dash::Helpers
|
|
188
188
|
|
189
189
|
def permalink
|
190
190
|
return "" unless @stime && @duration
|
191
|
-
format = "%
|
191
|
+
format = "%F %T" # chronic REALLY understands this
|
192
192
|
url = request.path + "?"
|
193
193
|
url << "&start=#{@stime.strftime(format)}"
|
194
194
|
url << "&duration=#{ChronicDuration.output(@duration)}"
|
data/lib/models/dashboard.rb
CHANGED
@@ -15,7 +15,7 @@ module Dash::Models
|
|
15
15
|
@graph_opts = {}
|
16
16
|
params["graphs"].each do |name|
|
17
17
|
# graphs map to option hashes
|
18
|
-
if name.instance_of?(Hash)
|
18
|
+
if name.instance_of?(Hash) # could be YAML::Omap
|
19
19
|
g = Graph.find(name.keys.first) # should only be one key
|
20
20
|
@graph_opts[g] = name[name.keys.first]||{}
|
21
21
|
else
|
data/lib/models/graph.rb
CHANGED
@@ -51,7 +51,7 @@ module Dash::Models
|
|
51
51
|
# calculate
|
52
52
|
"movingAverage", "stdev", "asPercent"
|
53
53
|
x.call
|
54
|
-
when "diffSeries", "
|
54
|
+
when "diffSeries", "divideSeries"
|
55
55
|
z.call
|
56
56
|
# filters
|
57
57
|
when "mostDeviant"
|
@@ -75,7 +75,7 @@ module Dash::Models
|
|
75
75
|
when "substr", "threshold"
|
76
76
|
x.call
|
77
77
|
when "color"
|
78
|
-
str #
|
78
|
+
@params[:use_color] ? "color(#{str}, \"#{arg}\")" : str
|
79
79
|
else
|
80
80
|
raise "BAD FUNC #{func}" unless pass
|
81
81
|
str
|
@@ -83,7 +83,6 @@ module Dash::Models
|
|
83
83
|
end
|
84
84
|
|
85
85
|
# inner means we're dealing with a complex key; @params will be applied
|
86
|
-
# later on
|
87
86
|
def handle_metric(name, opts, inner=false)
|
88
87
|
ret = name.dup
|
89
88
|
if inner
|
@@ -136,18 +135,24 @@ module Dash::Models
|
|
136
135
|
|
137
136
|
target = []
|
138
137
|
colors = []
|
139
|
-
#
|
138
|
+
#FIXME code duplication
|
140
139
|
if opts[:sum] == :global
|
141
140
|
@params["targets"].each do |stat_name, opts|
|
142
|
-
z = opts
|
143
|
-
# opts['key'] ||= stat_name
|
141
|
+
z = Marshal.load(Marshal.dump(opts))
|
144
142
|
z[:key] ||= stat_name
|
145
143
|
#######################
|
146
144
|
if stat_name.instance_of?(Array)
|
147
145
|
metric = stat_name.map do |m|
|
148
|
-
mm = compose_metric(m.keys.first,
|
149
|
-
|
150
|
-
|
146
|
+
mm = compose_metric(m.keys.first,
|
147
|
+
"{#{clusters.to_a.join(',')}}",
|
148
|
+
"{#{hosts.to_a.join(',')}}")
|
149
|
+
|
150
|
+
if z.keys.member?(:divideSeries)
|
151
|
+
handle_metric(translate(:sumSeries, mm),
|
152
|
+
m[m.keys.first], true)
|
153
|
+
else
|
154
|
+
handle_metric(mm, m[m.keys.first], true)
|
155
|
+
end
|
151
156
|
end.join(",")
|
152
157
|
else
|
153
158
|
metric = "#{stat_name}.{#{clusters.to_a.join(',')}}" +
|
@@ -156,30 +161,68 @@ module Dash::Models
|
|
156
161
|
end
|
157
162
|
#######################
|
158
163
|
z[:key] = "global #{z[:key]}"
|
159
|
-
target << handle_metric(
|
160
|
-
|
164
|
+
# target << handle_metric(translate(:sumSeries, metric), z)
|
165
|
+
|
166
|
+
if z.keys.member?(:divideSeries) # special case
|
167
|
+
# apply divideSeries, sumSeries then other options
|
168
|
+
res = translate(:divideSeries, metric)
|
169
|
+
res = translate(:sumSeries, res)
|
170
|
+
z.delete(:divideSeries)
|
171
|
+
h = YAML::Omap.new
|
172
|
+
z.each { |k,v| h[k] = v unless k == :divideSeries }
|
173
|
+
target << handle_metric(res, h)
|
174
|
+
else
|
175
|
+
target << handle_metric(translate(:sumSeries, metric), z)
|
176
|
+
end
|
177
|
+
if !@params[:use_color] ||
|
178
|
+
(!z[:color] && @params[:use_color])
|
179
|
+
colors << next_color(colors, z[:color])
|
180
|
+
end
|
161
181
|
end # @params["targets"].each
|
162
182
|
elsif opts[:sum] == :cluster # one line per cluster/metric
|
163
183
|
clusters.each do |cluster|
|
164
184
|
@params["targets"].each do |stat_name, opts|
|
165
|
-
z = opts
|
185
|
+
z = Marshal.load(Marshal.dump(opts))
|
166
186
|
metrics = []
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
187
|
+
#######################
|
188
|
+
h = "{#{hosts.to_a.join(',')}}"
|
189
|
+
if stat_name.instance_of?(Array)
|
190
|
+
metrics << stat_name.map do |m|
|
191
|
+
mm = compose_metric(m.keys.first, cluster, h)
|
192
|
+
# note: we take the ratio of the sums in this case, instead of
|
193
|
+
# the sums of the ratios
|
194
|
+
if z.keys.member?(:divideSeries)
|
195
|
+
# divideSeries is picky about the number of series given as
|
196
|
+
# arguments, so sum them in this case
|
197
|
+
handle_metric(translate(:sumSeries, mm),
|
198
|
+
m[m.keys.first], true)
|
199
|
+
else
|
172
200
|
handle_metric(mm, m[m.keys.first], true)
|
173
|
-
end
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
end
|
179
|
-
|
201
|
+
end
|
202
|
+
end.join(",")
|
203
|
+
else
|
204
|
+
metrics << handle_metric(compose_metric(stat_name,
|
205
|
+
cluster, h), {}, true)
|
206
|
+
end
|
207
|
+
#######################
|
180
208
|
z[:key] = "#{cluster} #{z[:key]}"
|
181
|
-
|
182
|
-
|
209
|
+
|
210
|
+
if z.keys.member?(:divideSeries) # special case
|
211
|
+
# apply divideSeries, sumSeries then other options
|
212
|
+
res = translate(:divideSeries, metrics.join(','))
|
213
|
+
res = translate(:sumSeries, res)
|
214
|
+
z.delete(:divideSeries)
|
215
|
+
h = YAML::Omap.new
|
216
|
+
z.each { |k,v| h[k] = v unless k == :divideSeries }
|
217
|
+
target << handle_metric(res, h)
|
218
|
+
else
|
219
|
+
target << handle_metric(translate(:sumSeries,
|
220
|
+
metrics.join(',')), z)
|
221
|
+
end
|
222
|
+
|
223
|
+
if !@params[:use_color] || (!z[:color] && @params[:use_color])
|
224
|
+
colors << next_color(colors, z[:color])
|
225
|
+
end
|
183
226
|
end # metrics.each
|
184
227
|
end # clusters.each
|
185
228
|
else # one line per {metric,host,colo}
|
@@ -199,9 +242,11 @@ module Dash::Models
|
|
199
242
|
#################
|
200
243
|
|
201
244
|
if label =~ /\*/
|
202
|
-
# for this particular type of graph, don't display a legend
|
245
|
+
# for this particular type of graph, don't display a legend,
|
246
|
+
# and color with abandon
|
203
247
|
url_opts[:hideLegend] = true
|
204
|
-
z = opts
|
248
|
+
z = Marshal.load(Marshal.dump(opts))
|
249
|
+
z.delete(:color)
|
205
250
|
# fixme proper labeling... maybe
|
206
251
|
# With wildcards let graphite construct the legend (or not).
|
207
252
|
# Since we're handling wildcards we don't know how many
|
@@ -211,10 +256,13 @@ module Dash::Models
|
|
211
256
|
target << handle_metric(metric, z)
|
212
257
|
colors.concat(@params[:default_colors]) if colors.empty?
|
213
258
|
else
|
214
|
-
z = opts
|
215
|
-
z[:key] = "#{host}/#{cluster} #{
|
259
|
+
z = Marshal.load(Marshal.dump(opts))
|
260
|
+
z[:key] = "#{host}/#{cluster} #{z[:key]}"
|
216
261
|
target << handle_metric(metric, z)
|
217
|
-
|
262
|
+
if !@params[:use_color] ||
|
263
|
+
(!opts[:color] && @params[:use_color])
|
264
|
+
colors << next_color(colors, opts[:color])
|
265
|
+
end
|
218
266
|
end
|
219
267
|
end
|
220
268
|
end
|
@@ -259,13 +307,27 @@ module Dash::Models
|
|
259
307
|
return metrics.flatten.map { |x| x.split(".") }
|
260
308
|
end
|
261
309
|
|
310
|
+
# FIXMEEEE needs to be fixed for different metric formats
|
262
311
|
def hosts_clusters
|
263
312
|
metrics = expand
|
264
313
|
clusters = Set.new
|
265
314
|
|
266
|
-
|
267
|
-
|
268
|
-
|
315
|
+
f = @params[:metric_format].dup.split("%m")
|
316
|
+
first = f.first.split(".")
|
317
|
+
last = f.last.split(".")
|
318
|
+
ci = hi = nil
|
319
|
+
first.each_with_index do |v, i|
|
320
|
+
ci = i if v.match("%c")
|
321
|
+
hi = i if v.match("%h")
|
322
|
+
end
|
323
|
+
unless ci && hi
|
324
|
+
last.reverse.each_with_index do |v, i|
|
325
|
+
ci = -1 -i if v.match("%c")
|
326
|
+
hi = -1 -i if v.match("%h")
|
327
|
+
end
|
328
|
+
end
|
329
|
+
hosts = metrics.map do |m|
|
330
|
+
Host.new(m[hi], @params.merge({ "cluster" => m[ci] }))
|
269
331
|
end.uniq
|
270
332
|
|
271
333
|
# filter by what matches the graph definition
|
@@ -287,7 +349,7 @@ module Dash::Models
|
|
287
349
|
default_colors << preferred_color
|
288
350
|
end
|
289
351
|
|
290
|
-
weights = Hash.new
|
352
|
+
weights = Hash.new(0)
|
291
353
|
colors.each do |c|
|
292
354
|
weights[c] += 1
|
293
355
|
end
|
data/lib/rubyfixes.rb
ADDED
data/lib/views/cluster.erb
CHANGED
@@ -16,8 +16,11 @@
|
|
16
16
|
end %>
|
17
17
|
<br>
|
18
18
|
<% end %>
|
19
|
+
|
20
|
+
<% if (hosts.to_set - seen_hosts).size > 0 %>
|
19
21
|
<h3>Other Hosts (not associated with a dashboard)</h3>
|
20
22
|
<%= (hosts.to_set - seen_hosts).sort.collect do |h|
|
21
23
|
href = append_query_string("/host/#{@cluster}/#{h}")
|
22
24
|
"<li><a href=\"#{href}\">#{h}</a></li>"
|
23
25
|
end %>
|
26
|
+
<% end %>
|
@@ -15,14 +15,6 @@
|
|
15
15
|
</div>
|
16
16
|
</div>
|
17
17
|
|
18
|
-
<div class="graphsection" style="width:<%= @zoom.width(merge_opts) %>;">
|
19
|
-
<a name="by_host">
|
20
|
-
<span class="graphtitle"><%= @zoom.name %> / <%= @cluster %> :: by host</span>
|
21
|
-
<div class="graph">
|
22
|
-
<img src="<%= @dash.render_cluster_graph(@zoom, @cluster, :zoom => true, :dynamic_url_opts => merge_opts) %>">
|
23
|
-
</div>
|
24
|
-
</div>
|
25
|
-
|
26
18
|
<% hosts.each do |host| %>
|
27
19
|
<div class="graphsection" style="width:<%= @zoom.width(merge_opts) %>;">
|
28
20
|
<a name="<%= host %>">
|
data/lib/views/layout.erb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
<%= css_url %>
|
4
4
|
<link href="/favicon.ico" rel="icon" type="text/x-icon">
|
5
5
|
<link href="/favicon.ico" rel="shortcut icon" type="text/x-icon">
|
6
|
-
<%= refresh %>
|
6
|
+
<%= refresh unless @no_graphs %>
|
7
7
|
</head>
|
8
8
|
<body bgcolor="black">
|
9
9
|
|
@@ -51,5 +51,7 @@
|
|
51
51
|
</div>
|
52
52
|
|
53
53
|
</body>
|
54
|
-
<div id="footer" style="color:green;">
|
54
|
+
<div id="footer" style="color:green;">
|
55
|
+
generated <%= @request_time %> by <a href="https://github.com/petef/pencil">pencil</a> v<%= PENCIL_VERSION %>
|
56
|
+
</div>
|
55
57
|
</html>
|
@@ -1,6 +1,7 @@
|
|
1
1
|
<span class="graphtitle">
|
2
2
|
dashboards:
|
3
3
|
<%= @dashboards.sort.collect do |d|
|
4
|
+
# this works unless you have a cluster with the same name as a dashboard
|
4
5
|
sub = append_query_string(request.path.sub(@dash.name, d.name))
|
5
6
|
@dash == d ? "#{d}" : "<a href=\"#{sub}\">#{d}</a>"
|
6
7
|
end.join(" ") %>
|
@@ -1,7 +1,10 @@
|
|
1
1
|
<span class="graphtitle">
|
2
2
|
graphs:
|
3
3
|
<%= @dash.graphs.map { |g| g.name }.collect do |g|
|
4
|
-
|
4
|
+
reversed = request.path.split("/").reverse
|
5
|
+
i = reversed.index(@zoom.name)
|
6
|
+
reversed[i] = g
|
7
|
+
sub = append_query_string(reversed.reverse.join('/'))
|
5
8
|
@zoom.name == g ? "#{g}" : "<a href=\"#{sub}\">#{g}</a>"
|
6
9
|
end.join(" ") %>
|
7
10
|
</span>
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pencil
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 6
|
10
|
+
version: 0.2.6
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Pete Fritchman
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2011-
|
19
|
+
date: 2011-08-02 00:00:00 -07:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -114,33 +114,34 @@ extensions: []
|
|
114
114
|
extra_rdoc_files: []
|
115
115
|
|
116
116
|
files:
|
117
|
+
- lib/dash.rb
|
117
118
|
- lib/models.rb
|
118
|
-
- lib/
|
119
|
-
- lib/
|
119
|
+
- lib/helpers.rb
|
120
|
+
- lib/namespace.rb
|
120
121
|
- lib/config.rb
|
121
|
-
- lib/
|
122
|
-
- lib/models/graph.rb
|
123
|
-
- lib/models/dashboard.rb
|
124
|
-
- lib/models/base.rb
|
122
|
+
- lib/views/dash-cluster.erb
|
125
123
|
- lib/views/cluster.erb
|
126
|
-
- lib/views/
|
127
|
-
- lib/views/dash-cluster-zoom.erb
|
128
|
-
- lib/views/dash-global-zoom.erb
|
129
|
-
- lib/views/dash-global.erb
|
124
|
+
- lib/views/layout.erb
|
130
125
|
- lib/views/host.erb
|
131
|
-
- lib/views/
|
132
|
-
- lib/views/
|
126
|
+
- lib/views/dash-global.erb
|
127
|
+
- lib/views/dash-global-zoom.erb
|
128
|
+
- lib/views/global.erb
|
133
129
|
- lib/views/partials/input_boxes.erb
|
130
|
+
- lib/views/partials/graph_switcher.erb
|
134
131
|
- lib/views/partials/cluster_selector.erb
|
135
|
-
- lib/views/partials/cluster_switcher.erb
|
136
132
|
- lib/views/partials/dash_switcher.erb
|
137
|
-
- lib/views/partials/
|
133
|
+
- lib/views/partials/hosts_selector.erb
|
138
134
|
- lib/views/partials/refresh_button.erb
|
139
|
-
- lib/views/
|
140
|
-
- lib/views/
|
141
|
-
- lib/
|
142
|
-
- lib/
|
143
|
-
- lib/
|
135
|
+
- lib/views/partials/cookies_form.erb
|
136
|
+
- lib/views/partials/cluster_switcher.erb
|
137
|
+
- lib/views/dash-cluster-zoom.erb
|
138
|
+
- lib/rubyfixes.rb
|
139
|
+
- lib/public/favicon.ico
|
140
|
+
- lib/public/style.css
|
141
|
+
- lib/models/graph.rb
|
142
|
+
- lib/models/dashboard.rb
|
143
|
+
- lib/models/base.rb
|
144
|
+
- lib/models/host.rb
|
144
145
|
- lib/config.ru
|
145
146
|
- docs/pencil_options.md
|
146
147
|
- examples/pencil.yml
|