riemann-dash 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/riemann/dash.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'rubygems'
2
- require 'riemann/client'
3
2
  require 'sinatra/base'
4
3
 
5
4
  module Riemann
@@ -13,24 +12,11 @@ module Riemann
13
12
 
14
13
  def self.config
15
14
  @config ||= {
16
- :client => {},
17
- :age_scale => 60 * 30,
18
- :state_order => {
19
- 'critical' => 3,
20
- 'warning' => 2,
21
- 'ok' => 1
22
- },
23
- :strftime => '%H:%M:%S',
24
15
  :controllers => [File.join(File.dirname(__FILE__), 'dash', 'controller')],
25
- :helpers => [File.join(File.dirname(__FILE__), 'dash', 'helper')],
26
16
  :views => File.join(File.dirname(__FILE__), 'dash', 'views')
27
17
  }
28
18
  end
29
19
 
30
- def self.client
31
- @client ||= Riemann::Client.new(config[:client])
32
- end
33
-
34
20
  def self.load(filename)
35
21
  unless load_config(filename || 'config.rb')
36
22
  # Configuration failed; load a default view.
@@ -38,7 +24,6 @@ module Riemann
38
24
  end
39
25
 
40
26
  config[:controllers].each { |d| load_controllers d }
41
- config[:helpers].each { |d| load_helpers d }
42
27
  set :views, File.expand_path(config[:views])
43
28
 
44
29
  # Fallback pub dir
@@ -55,12 +40,13 @@ module Riemann
55
40
  end
56
41
  end
57
42
 
58
- # Load controllers.
59
- # Controllers can be regular old one-file-per-class, but if you prefer a little
60
- # more modularity, this method will allow you to define all controller methods
61
- # in their own files. For example, get "/posts/*/edit" can live in
62
- # controller/posts/_/edit.rb. The sorting system provided here requires
63
- # files in the correct order to handle wildcards appropriately.
43
+ # Load controllers.
44
+ # Controllers can be regular old one-file-per-class, but
45
+ # if you prefer a little more modularity, this method will allow you to
46
+ # define all controller methods in their own files. For example, get
47
+ # "/posts/*/edit" can live in controller/posts/_/edit.rb. The sorting
48
+ # system provided here requires files in the correct order to handle
49
+ # wildcards appropriately.
64
50
  def self.load_controllers(dir)
65
51
  rbs = []
66
52
  Find.find(
@@ -104,27 +90,10 @@ module Riemann
104
90
  end
105
91
  end
106
92
 
107
- # Load helpers
108
- def self.load_helpers(dir)
109
- Find.find(
110
- File.expand_path(dir)
111
- ) do |path|
112
- require path if path =~ /\.rb$/
113
- end
114
- end
115
-
116
93
  # Add an additional public directory.
117
94
  def self.public_dir(dir)
118
95
  require 'riemann/dash/rack/static'
119
96
  use Riemann::Dash::Static, :root => dir
120
97
  end
121
-
122
- def client
123
- self.class.client
124
- end
125
-
126
- def query(*a)
127
- self.class.client.query(*a).events || []
128
- end
129
98
  end
130
99
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: riemann-dash
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-18 00:00:00.000000000 Z
12
+ date: 2013-01-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: riemann-client
16
- requirement: !ruby/object:Gem::Requirement
16
+ requirement: &11919920 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,15 +21,10 @@ dependencies:
21
21
  version: 0.0.7
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: 0.0.7
24
+ version_requirements: *11919920
30
25
  - !ruby/object:Gem::Dependency
31
26
  name: erubis
32
- requirement: !ruby/object:Gem::Requirement
27
+ requirement: &11918520 !ruby/object:Gem::Requirement
33
28
  none: false
34
29
  requirements:
35
30
  - - ! '>='
@@ -37,15 +32,10 @@ dependencies:
37
32
  version: 2.7.0
38
33
  type: :runtime
39
34
  prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ! '>='
44
- - !ruby/object:Gem::Version
45
- version: 2.7.0
35
+ version_requirements: *11918520
46
36
  - !ruby/object:Gem::Dependency
47
37
  name: sinatra
48
- requirement: !ruby/object:Gem::Requirement
38
+ requirement: &11917660 !ruby/object:Gem::Requirement
49
39
  none: false
50
40
  requirements:
51
41
  - - ! '>='
@@ -53,15 +43,10 @@ dependencies:
53
43
  version: 1.3.2
54
44
  type: :runtime
55
45
  prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: 1.3.2
46
+ version_requirements: *11917660
62
47
  - !ruby/object:Gem::Dependency
63
48
  name: sass
64
- requirement: !ruby/object:Gem::Requirement
49
+ requirement: &11916360 !ruby/object:Gem::Requirement
65
50
  none: false
66
51
  requirements:
67
52
  - - ! '>='
@@ -69,15 +54,10 @@ dependencies:
69
54
  version: 3.1.14
70
55
  type: :runtime
71
56
  prerelease: false
72
- version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
- requirements:
75
- - - ! '>='
76
- - !ruby/object:Gem::Version
77
- version: 3.1.14
57
+ version_requirements: *11916360
78
58
  - !ruby/object:Gem::Dependency
79
59
  name: thin
80
- requirement: !ruby/object:Gem::Requirement
60
+ requirement: &11914740 !ruby/object:Gem::Requirement
81
61
  none: false
82
62
  requirements:
83
63
  - - ! '>='
@@ -85,28 +65,18 @@ dependencies:
85
65
  version: 1.3.1
86
66
  type: :runtime
87
67
  prerelease: false
88
- version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
- requirements:
91
- - - ! '>='
92
- - !ruby/object:Gem::Version
93
- version: 1.3.1
68
+ version_requirements: *11914740
94
69
  - !ruby/object:Gem::Dependency
95
70
  name: multi_json
96
- requirement: !ruby/object:Gem::Requirement
71
+ requirement: &11540560 !ruby/object:Gem::Requirement
97
72
  none: false
98
73
  requirements:
99
- - - '='
74
+ - - =
100
75
  - !ruby/object:Gem::Version
101
76
  version: 1.3.6
102
77
  type: :runtime
103
78
  prerelease: false
104
- version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
- requirements:
107
- - - '='
108
- - !ruby/object:Gem::Version
109
- version: 1.3.6
79
+ version_requirements: *11540560
110
80
  description:
111
81
  email: aphyr@aphyr.com
112
82
  executables:
@@ -115,38 +85,37 @@ extensions: []
115
85
  extra_rdoc_files: []
116
86
  files:
117
87
  - lib/riemann/dash.rb
118
- - lib/riemann/dash/version.rb
119
- - lib/riemann/dash/public/keys.js
120
- - lib/riemann/dash/public/jquery-ui-1.9.0.custom.min.js
121
- - lib/riemann/dash/public/toolbar.js
122
- - lib/riemann/dash/public/subs.js
123
- - lib/riemann/dash/public/underscore-min.js
88
+ - lib/riemann/dash/rack/static.rb
89
+ - lib/riemann/dash/public/format.js
90
+ - lib/riemann/dash/public/view.js
124
91
  - lib/riemann/dash/public/jquery-1.7.2.min.js
92
+ - lib/riemann/dash/public/mustache.js
125
93
  - lib/riemann/dash/public/x.png
126
- - lib/riemann/dash/public/jquery.quickfit.js
127
- - lib/riemann/dash/public/view.js
94
+ - lib/riemann/dash/public/util.js
95
+ - lib/riemann/dash/public/jquery-ui-1.9.0.custom.min.js
96
+ - lib/riemann/dash/public/underscore-min.js
97
+ - lib/riemann/dash/public/persistence.js
98
+ - lib/riemann/dash/public/subs.js
99
+ - lib/riemann/dash/public/jquery.simplemodal.1.4.3.min.js
128
100
  - lib/riemann/dash/public/views/help.js
129
- - lib/riemann/dash/public/views/title.js
130
101
  - lib/riemann/dash/public/views/grid.js
102
+ - lib/riemann/dash/public/views/title.js
131
103
  - lib/riemann/dash/public/views/gauge.js
132
- - lib/riemann/dash/public/jquery.simplemodal.1.4.3.min.js
104
+ - lib/riemann/dash/public/jquery.quickfit.js
105
+ - lib/riemann/dash/public/toastr.js
106
+ - lib/riemann/dash/public/toolbar.js
107
+ - lib/riemann/dash/public/toastr.css
133
108
  - lib/riemann/dash/public/dash.js
134
- - lib/riemann/dash/public/format.js
135
109
  - lib/riemann/dash/public/profile.js
136
- - lib/riemann/dash/public/mustache.js
137
- - lib/riemann/dash/public/persistence.js
138
- - lib/riemann/dash/public/util.js
139
110
  - lib/riemann/dash/public/clock.js
140
111
  - lib/riemann/dash/public/jquery.json-2.2.min.js
141
- - lib/riemann/dash/controller/css.rb
112
+ - lib/riemann/dash/public/keys.js
113
+ - lib/riemann/dash/version.rb
142
114
  - lib/riemann/dash/controller/index.rb
143
- - lib/riemann/dash/controller/websockets.rb
115
+ - lib/riemann/dash/controller/css.rb
116
+ - lib/riemann/dash/views/css.scss
144
117
  - lib/riemann/dash/views/layout.erubis
145
118
  - lib/riemann/dash/views/index.erubis
146
- - lib/riemann/dash/views/css.scss
147
- - lib/riemann/dash/views/websockets.erubis
148
- - lib/riemann/dash/helper/renderer.rb
149
- - lib/riemann/dash/rack/static.rb
150
119
  - bin/riemann-dash
151
120
  - LICENSE
152
121
  - README.markdown
@@ -170,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
139
  version: '0'
171
140
  requirements: []
172
141
  rubyforge_project: riemann-dash
173
- rubygems_version: 1.8.22
142
+ rubygems_version: 1.8.10
174
143
  signing_key:
175
144
  specification_version: 3
176
145
  summary: HTTP dashboard for the distributed event system Riemann.
@@ -1,50 +0,0 @@
1
- class Riemann::Dash
2
- require 'multi_json'
3
- require 'fileutils'
4
- require 'set'
5
-
6
- WS_CONFIG_FILE = "ws/config.json"
7
-
8
- get '/ws' do
9
- erb :websockets, :layout => false
10
- end
11
-
12
- get '/ws/config', :provides => 'json' do
13
- if File.exists? WS_CONFIG_FILE
14
- send_file WS_CONFIG_FILE, :type => :json
15
- else
16
- MultiJson.encode({})
17
- end
18
- end
19
-
20
- post '/ws/config' do
21
- # Read update
22
- request.body.rewind
23
- update = MultiJson.decode(request.body.read)
24
-
25
- # Read old config
26
- if File.exists? WS_CONFIG_FILE
27
- old = MultiJson.decode File.read WS_CONFIG_FILE
28
- else
29
- old = {}
30
- end
31
-
32
- new = {}
33
-
34
- # Server
35
- new['server'] = update['server'] or old['server']
36
-
37
- p update['workspaces']
38
- new['workspaces'] = update['workspaces'] or old['workspaces']
39
-
40
- # Save new config
41
- FileUtils.mkdir_p 'ws'
42
- File.open(WS_CONFIG_FILE, 'w') do |f|
43
- f.write(MultiJson.encode(new))
44
- end
45
-
46
- # Return current config
47
- content_type "application/json"
48
- MultiJson.encode(new)
49
- end
50
- end
@@ -1,266 +0,0 @@
1
- module Riemann
2
- class Dash
3
- helpers do
4
- include ::Rack::Utils
5
-
6
- alias_method :h, :escape_html
7
-
8
- # Returns a scalar factor from 0.2 to 1, where 0.2 is "on the order of
9
- # age_scale ago", and 1 is "very recent"
10
- def age_fraction(time)
11
- return 1 if time.nil?
12
-
13
- x = 1 - ((Time.now.to_f - time) / Dash.config[:age_scale])
14
- if x < 0.2
15
- 0.2
16
- elsif x > 1
17
- 1
18
- else
19
- x
20
- end
21
- end
22
-
23
- # Finds the longest common prefix of a list of strings.
24
- # i.e. 'abc, 'ab', 'abdf' => 'ab'
25
- def longest_common_prefix(strings, prefix = '')
26
- return strings.first if strings.size <= 1
27
-
28
- first = strings[0][0,1] or return prefix
29
- tails = strings[1..-1].inject([strings[0][1..-1]]) do |tails, string|
30
- if string[0,1] != first
31
- return prefix
32
- else
33
- tails << string[1..-1]
34
- end
35
- end
36
-
37
- longest_common_prefix(tails, prefix + first)
38
- end
39
-
40
- # An overview of states
41
- def state_list(states)
42
- ul(states.map { |s| state_short s })
43
- end
44
-
45
- def state_grid(states = Dash.client.query)
46
- h2('States by Host') +
47
- table(
48
- *Event.partition(states, :host).map do |host, states|
49
- tr(
50
- th(host, :class => 'host'),
51
- *Event.sort(states, :service).map do |state|
52
- state_short state
53
- end
54
- )
55
- end
56
- )
57
- end
58
-
59
- # Renders a state as the given HTML tag with a % width corresponding to
60
- # metric / max.
61
- def state_bar(s, opts = {})
62
- opts = {:tag => 'div', :max => 1}.merge opts
63
-
64
- return '' unless s
65
- x = s.metric
66
-
67
- # Text
68
- text = case x
69
- when Float
70
- '%.2f' % x
71
- when Integer
72
- x.to_s
73
- else
74
- s.state || '?'
75
- end
76
-
77
- # Size
78
- size = case x
79
- when 0
80
- 0
81
- when nil
82
- 100
83
- else
84
- begin
85
- x * 100 / opts[:max]
86
- rescue ZeroDivisionError
87
- 0
88
- end
89
- end
90
- size = "%.2f" % size
91
-
92
- time = Time.at(s.time).strftime(Dash.config[:strftime])
93
-
94
- tag opts[:tag], h(text),
95
- :class => "state #{s.state}",
96
- :style => "opacity: #{age_fraction s.time}; width: #{size}%",
97
- :title => "#{s.state}\n#{s.description}\n\n(at #{time})"
98
- end
99
-
100
- # Renders a set of states in a chart. Each row is a given host, each
101
- # service is a column. Each state is shown as a bar with an inferred
102
- # maximum for the entire service, so you can readily compare multiple
103
- # hosts.
104
- #
105
- # Takes a a set of states and options:
106
- # title: the title of the chart. Inferred to be the longest common
107
- # prefix of all services.
108
- # maxima: maps each service to the maximum value used to display its
109
- # bar.
110
- # service_names: maps each service to a friendly name. Default service
111
- # names have common prefixes removed.
112
- # hosts: an array of hosts for rows. Default is every host present in
113
- # states, sorted.
114
- # transpose: Hosts go across, services go down. Enables :global_maxima.
115
- # global_maximum: Compute default maxima for services globally,
116
- # instead of a different maximum for each service.
117
- def state_chart(states, opts = {})
118
- o = {
119
- :maxima => {},
120
- :service_names => {}
121
- }.merge opts
122
- if o[:transpose] and not o.include?(:global_maximum)
123
- o[:global_maximum] = true
124
- end
125
-
126
- # Get all services
127
- services = states.map { |s| s.service }.compact.uniq.sort
128
-
129
- # Figure out what name to use for each service.
130
- prefix = longest_common_prefix services
131
- service_names = services.inject({}) do |names, service|
132
- names[service] = service[prefix.length..-1]
133
- names
134
- end.merge o[:service_names]
135
-
136
- # Compute maximum for each service
137
- maxima = if o[:global_maximum]
138
- max = states.map(&:metric).compact.max
139
- services.inject({}) do |m, s|
140
- m[s] = max
141
- m
142
- end.merge o[:maxima]
143
- else
144
- states.inject(Hash.new(0)) do |m, s|
145
- if s.metric && !(s.metric.nan?)
146
- m[s.service] = [s.metric, m[s.service]].max
147
- end
148
- m
149
- end.merge o[:maxima]
150
- end
151
-
152
- # Compute union of all hosts for these states, if no
153
- # list of hosts explicitly given.
154
- hosts = o[:hosts] || states.map do |state|
155
- state.host
156
- end
157
- hosts = hosts.uniq.sort { |a, b|
158
- if !a
159
- -1
160
- elsif !b
161
- 1
162
- else
163
- a <=> b
164
- end
165
- }
166
-
167
- # Construct index
168
- by = states.inject({}) do |index, s|
169
- index[[s.host, s.service]] = s
170
- index
171
- end
172
-
173
- # Title
174
- title = o[:title] || prefix.capitalize rescue 'Unknown'
175
-
176
- if o[:transpose]
177
- h2(title) +
178
- table(
179
- tr(
180
- th,
181
- *hosts.map do |host|
182
- th host
183
- end
184
- ),
185
- *services.map do |service|
186
- tr(
187
- th(service_names[service]),
188
- *hosts.map do |host|
189
- s = by[[host, service]]
190
- td(
191
- s ? state_bar(s, :max => maxima[service]) : nil
192
- )
193
- end
194
- )
195
- end << {:class => 'chart'} # ruby 1.8.7 this is your fault
196
- )
197
- else
198
- h2(title) +
199
- table(
200
- tr(
201
- th,
202
- *services.map do |service|
203
- th service_names[service]
204
- end
205
- ),
206
- *hosts.map do |host|
207
- tr(
208
- th(host),
209
- *services.map do |service|
210
- s = by[[host, service]]
211
- td(
212
- s ? state_bar(s, :max => maxima[service]) : nil
213
- )
214
- end
215
- )
216
- end <<
217
- {:class => 'chart'}
218
- )
219
- end
220
- end
221
-
222
- # Renders a state as a short tag.
223
- def state_short(s, opts={:tag => 'li'})
224
- if s
225
- "<#{opts[:tag]} class=\"state #{s.state}\" style=\"opacity: #{age_fraction s.time}\" title=\"#{h s.description}\">#{h s.host} #{h s.service}</#{opts[:tag]}>"
226
- else
227
- "<#{opts[:tag]} class=\"service\"></#{opts[:tag]}>"
228
- end
229
- end
230
-
231
- # Renders a time to an HTML tag.
232
- def time(unix)
233
- t = Time.at(unix)
234
- "<time datetime=\"#{t.iso8601}\">#{t.strftime(Dash.config[:strftime])}</time>"
235
- end
236
-
237
- # Renders an HTML tag
238
- def tag(tag, *a)
239
- if Hash === a.last
240
- opts = a.pop
241
- else
242
- opts = {}
243
- end
244
-
245
- attrs = opts.map do |k,v|
246
- "#{k}=\"#{h v}\""
247
- end.join ' '
248
-
249
- content = if block_given?
250
- a << yield
251
- else
252
- a
253
- end.flatten.join("\n")
254
-
255
- s = "<#{tag} #{attrs}>#{content}</#{tag}>"
256
- end
257
-
258
- # Specific tag aliases
259
- %w(div span h1 h2 h3 h4 h5 h6 ul ol li table th tr td u i b).each do |tag|
260
- class_eval "def #{tag}(*a, &block)
261
- tag #{tag.inspect}, *a, &block
262
- end"
263
- end
264
- end
265
- end
266
- end