pencil 0.2.2 → 0.2.6
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/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
|