redmon 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,8 +1,9 @@
1
1
  *.gem
2
2
  .bundle
3
- /vendor
3
+ .rbenv-version
4
4
  .DS_Store
5
5
  dump.rdb
6
- Gemfile.lock
7
- .rvmrc
8
- highcharts.js
6
+ pkg
7
+ vendor
8
+ !/lib/redmon/public/vendor
9
+ Gemfile.lock
data/.travis.yml CHANGED
@@ -1 +1,9 @@
1
- rvm: 1.9.3
1
+ language: ruby
2
+ rvm:
3
+ - ree-1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ branches:
7
+ only:
8
+ - master
9
+ - ruby-1.8
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # Redmon
2
2
 
3
- ** Work in progress in the very early stages of dev **
4
-
5
3
  Simple sinatra based dashbord for redis. After seeing the [fnordmetric](https://github.com/paulasmuth/fnordmetric)
6
4
  project I was inspired to write this. Some of the ideas there have be carried over here.
7
5
 
8
6
  [ ![Build status - Travis-ci](https://secure.travis-ci.org/steelThread/redmon.png) ](http://travis-ci.org/steelThread/redmon)
9
7
 
8
+ [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/steelThread/redmon)
9
+
10
10
  ----
11
11
 
12
12
  Watch your redis server live.
@@ -38,17 +38,18 @@ gem install redmon
38
38
  ## Usage
39
39
 
40
40
  ```bash
41
- $ bundle install
42
- $ bundle exec bin/redmon -h
43
- Usage: bin/redmon (options)
41
+ $ redmon -h
42
+ Usage: /Users/sean/codez/steelThread/redmon/vendor/ruby/1.9.1/bin/redmon (options)
44
43
  -a, --address ADDRESS The thin bind address for the app (default: 0.0.0.0)
45
44
  -n, --namespace NAMESPACE The root Redis namespace (default: redmon)
46
45
  -i, --interval SECS Poll interval in secs for the worker (default: 10)
47
46
  -p, --port PORT The thin bind port for the app (default: 4567)
48
47
  -r, --redis URL The Redis url for monitor (default: redis://127.0.0.1:6379)
48
+ -s, --secure CREDENTIALS Use basic auth. Colon separated credentials, eg admin:admin.
49
49
  --no-app Do not run the web app to present stats
50
50
  --no-worker Do not run a worker to collect the stats
51
- $ bundle exec bin/redmon
51
+
52
+ $ redmon
52
53
  >> Thin web server (v1.3.1 codename Triple Espresso)
53
54
  >> Maximum connections set to 1024
54
55
  >> Listening on 0.0.0.0:4567, CTRL+C to stop
@@ -63,7 +64,6 @@ $ ruby load_sim.rb
63
64
 
64
65
  Open your browser to 0.0.0.0:4567
65
66
 
66
-
67
67
  ## Using in a Rails application
68
68
 
69
69
  Add to Gemfile:
@@ -85,12 +85,14 @@ You can configure the Redmon using an initializer config/initializers/redmon.rb:
85
85
  Redmon.configure do |config|
86
86
  config.redis_url = 'redis://127.0.0.1:6379'
87
87
  config.namespace = 'redmon'
88
- config.poll_interval = 10
89
88
  end
90
89
  ```
91
90
 
92
91
  This will mount the Redmon application to the /redmon/ path. The trailing slash
93
- is important.
92
+ is important. The worker that gathers the redis info stats will not be started
93
+ when Redmon is mounted. In order to get a worker running inside of your Rails
94
+ app you can try this [Railtie](https://github.com/steelThread/redmon/pull/19#issuecomment-7273659)
95
+ based approach.
94
96
 
95
97
  ## License
96
98
 
data/bin/redmon CHANGED
@@ -1,12 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'rubygems'
3
4
  require 'mixlib/cli'
4
5
  require 'redmon'
5
6
 
6
7
  class RedmonCLI
7
8
  include Mixlib::CLI
8
9
 
9
- to_i =-> s {s.to_i}
10
+ to_i = lambda { |s| s.to_i }
10
11
 
11
12
  option :address,
12
13
  :short => '-a ADDRESS',
@@ -33,6 +34,11 @@ class RedmonCLI
33
34
  :default => 'redmon',
34
35
  :description => 'The root Redis namespace (default: redmon)'
35
36
 
37
+ option :secure,
38
+ :short => '-s CREDENTIALS',
39
+ :long => '--secure CREDENTIALS',
40
+ :description => "Use basic auth. Colon separated credentials, eg admin:admin."
41
+
36
42
  option :poll_interval,
37
43
  :short => '-i SECS',
38
44
  :long => '--interval SECS',
@@ -56,10 +62,10 @@ class RedmonCLI
56
62
 
57
63
  def run
58
64
  parse_options
59
- config[:web_interface] = [config[:address], config[:port]]
65
+ config[:web_interface] = [config[:address], config[:port]] if config[:app]
60
66
  config
61
67
  end
62
68
 
63
69
  end
64
70
 
65
- Redmon.run RedmonCLI.new.run
71
+ Redmon.run RedmonCLI.new.run
data/lib/redmon.rb CHANGED
@@ -1,10 +1,5 @@
1
- require 'redmon/config'
2
- require 'active_support/core_ext'
3
1
  require 'eventmachine'
4
- require 'haml'
5
- require 'redis'
6
- require 'sinatra/base'
7
- require 'thin'
2
+ require 'active_support/core_ext'
8
3
 
9
4
  module Redmon
10
5
  extend self
@@ -13,8 +8,11 @@ module Redmon
13
8
  config.apply opts
14
9
  start_em
15
10
  rescue Exception => e
16
- log "!!! Redmon has shit the bed, restarting... #{e.message}"
17
- sleep(1); run(opts)
11
+ unless e.is_a?(SystemExit)
12
+ log "!!! Redmon has shit the bed, restarting... #{e.message}"
13
+ sleep(1)
14
+ run(opts)
15
+ end
18
16
  end
19
17
 
20
18
  def start_em
@@ -27,8 +25,10 @@ module Redmon
27
25
  end
28
26
 
29
27
  def start_app
30
- app = Redmon::App.new
31
- Thin::Server.start(*config.web_interface, app)
28
+ require 'thin'
29
+ Thin::Server.start(*config.web_interface) do
30
+ run Redmon::App.new
31
+ end
32
32
  log "listening on http##{config.web_interface.join(':')}"
33
33
  rescue Exception => e
34
34
  log "Can't start Redmon::App. port in use? Error #{e}"
@@ -46,14 +46,10 @@ module Redmon
46
46
  puts "[#{Time.now.strftime('%y-%m-%d %H:%M:%S')}] #{msg}"
47
47
  end
48
48
 
49
- # @deprecated
50
- def [](option)
51
- config.send :option
52
- end
49
+ require 'redmon/config'
50
+ require 'redmon/redis'
53
51
 
54
- end
52
+ autoload :App, 'redmon/app'
53
+ autoload :Worker, 'redmon/worker'
55
54
 
56
- require 'redmon/redis'
57
- require 'redmon/helpers'
58
- require 'redmon/app'
59
- require 'redmon/worker'
55
+ end
data/lib/redmon/app.rb CHANGED
@@ -1,4 +1,6 @@
1
+ require 'sinatra/base'
1
2
  require 'redmon/helpers'
3
+ require 'haml'
2
4
 
3
5
  module Redmon
4
6
  class App < Sinatra::Base
@@ -6,17 +8,24 @@ module Redmon
6
8
  helpers Redmon::Helpers
7
9
 
8
10
  use Rack::Static, {
9
- urls: [/\.css$/, /\.js$/],
10
- root: "#{root}/public",
11
- cache_control: 'public, max-age=3600'
11
+ :urls => [/\.css$/, /\.js$/],
12
+ :root => "#{root}/public",
13
+ :cache_control => 'public, max-age=3600'
12
14
  }
13
15
 
16
+ if Redmon.config.secure
17
+ use Rack::Auth::Basic do |username, password|
18
+ [username, password] == Redmon.config.secure.split(':')
19
+ end
20
+ end
21
+
14
22
  get '/' do
15
23
  haml :app
16
24
  end
17
25
 
18
26
  get '/cli' do
19
- args = params[:command].split
27
+ args = params[:command].split(/ *"(.*?)" *| *'(.*?)' *| /)
28
+ args.reject!(&:blank?)
20
29
  @cmd = args.shift.downcase.intern
21
30
  begin
22
31
  raise RuntimeError unless supported? @cmd
@@ -44,4 +53,4 @@ module Redmon
44
53
  end
45
54
 
46
55
  end
47
- end
56
+ end
data/lib/redmon/config.rb CHANGED
@@ -14,7 +14,8 @@ module Redmon
14
14
  :app => true,
15
15
  :worker => true,
16
16
  :web_interface => ['0.0.0.0', 4567],
17
- :poll_interval => 10
17
+ :poll_interval => 10,
18
+ :secure => false
18
19
  }
19
20
 
20
21
  attr_accessor(*DEFAULTS.keys)
@@ -24,8 +25,8 @@ module Redmon
24
25
  end
25
26
 
26
27
  def apply(opts)
27
- opts.each {|k,v| send("#{k}=", v) if respond_to? k}
28
+ opts.each { |k,v| send("#{k}=", v) if respond_to? k }
28
29
  end
29
30
 
30
31
  end
31
- end
32
+ end
@@ -1,5 +1,3 @@
1
- require 'redmon/redis'
2
-
3
1
  module Redmon
4
2
  module Helpers
5
3
  include Redmon::Redis
@@ -17,4 +15,4 @@ module Redmon
17
15
  end
18
16
 
19
17
  end
20
- end
18
+ end
@@ -108,7 +108,21 @@ body {
108
108
 
109
109
  #terminal input:focus{ box-shadow:none; }
110
110
 
111
- .chart {
111
+ .chart-container {
112
+ position: relative;
112
113
  width:880px;
113
114
  height:225px;
115
+ margin-top: 10px;
116
+ }
117
+
118
+ .label {
119
+ padding: none;
120
+ font-size: inherit;
121
+ font-weight: bold;
122
+ color: white;
123
+ text-transform: uppercase;
124
+ background-color: #404040;
125
+ -webkit-border-radius: none;
126
+ -moz-border-radius: none;
127
+ border-radius: none;
114
128
  }
@@ -52,17 +52,20 @@ var Redmon = (function() {
52
52
  }
53
53
 
54
54
  function formatDate(date) {
55
- var d = new Date(parseInt(parseInt(date)));
55
+ var d = new Date(parseInt(date));
56
56
  return d.getMonth()+1+'/'+d.getDate()+' '+d.getHours()+':'+d.getMinutes()+':'+d.getSeconds();
57
57
  }
58
58
 
59
59
  function formatNumber(num) {
60
- return (num + "").replace(/(\d)(?=(\d{3})+(\.\d+|)\b)/g, "$1,");
60
+ return d3.format(',.0f')(d3.round(num, 2));
61
+ }
62
+
63
+ function formatMetric(num) {
64
+ return d3.format('s')(num);
61
65
  }
62
66
 
63
67
  function formatTime(time) {
64
- var d = new Date(parseInt(parseInt(time)));
65
- return d.getHours()+':'+d.getMinutes();
68
+ return d3.time.format('%H:%S')(new Date(time));
66
69
  }
67
70
 
68
71
  /**
@@ -70,10 +73,10 @@ var Redmon = (function() {
70
73
  */
71
74
  function base1024(arg) {
72
75
  var y = arg;
73
- if (y >= 1073741824) { return (y / 1073741824).toFixed(2) + "GB" }
74
- else if (y >= 1048576) { return (y / 1048576).toFixed(1) + "MB" }
75
- else if (y >= 1024) { return (y / 1024).toFixed(0) + "KB" }
76
- else if (y < 1 && y > 0) { return y.toFixed(0) }
76
+ if (y >= 1073741824) { return (y / 1073741824).toFixed(2) + "Gb" }
77
+ else if (y >= 1048576) { return (y / 1048576).toFixed(1) + "Mb" }
78
+ else if (y >= 1024) { return (y / 1024).toFixed(0) + "Kb" }
79
+ else if (y < 1 && y > 0) { return y.toFixed(0) + "b"}
77
80
  else { return y }
78
81
  }
79
82
 
@@ -146,57 +149,57 @@ var Redmon = (function() {
146
149
  //////////////////////////////////////////////////////////////////////
147
150
  // encapsulate the keyspace chart
148
151
  var memoryWidget = (function() {
149
- var plot
150
- , dataset;
152
+ var chart
153
+ , dataset = [];
151
154
 
152
155
  function render(data) {
153
156
  dataset = points(data);
154
- plot = $.plot('#memory-container', [dataset], {
155
- lines: {
156
- show: true,
157
- fill: true,
158
- color: 'rgb(255,50,50)'
159
- },
160
- points: { show: false },
161
- series: { shadowSize: 3 },
162
- yaxis: { tickFormatter: base1024},
163
- xaxis: { tickFormatter: formatTime},
164
- grid: {
165
- hoverable: true,
166
- clickable: true,
167
- backgroundColor: {
168
- colors: ['#ddd', '#fff']
169
- }
170
- }
171
- });
157
+ chart = nv.models.lineChart()
158
+ .x(function(d) { return d.x })
159
+ .y(function(d) { return d.y })
160
+ .margin({top : 10, right : 20, bottom : 20, left : 60})
161
+ .showLegend(false);
162
+
163
+ chart.xAxis
164
+ .tickFormat(formatTime);
165
+
166
+ chart.yAxis
167
+ .tickFormat(base1024);
168
+
169
+ update();
170
+
171
+ events.bind('data', onData);
172
172
  }
173
173
 
174
174
  function points(data) {
175
- return data.map(point);
175
+ if (data.length)
176
+ return data.map(point);
177
+
178
+ return [];
176
179
  }
177
180
 
178
181
  function point(info) {
179
- return [
180
- parseInt(info.time),
181
- parseInt(info.used_memory)
182
- ]
182
+ return !info ? {} : {
183
+ x : parseInt(info.time),
184
+ y : parseInt(info.used_memory)
185
+ }
183
186
  }
184
187
 
185
188
  function onData(ev, data) {
186
- if (data) {
187
- if (dataset.length >= 100) {
188
- dataset.shift()
189
- }
190
-
191
- dataset.push(point(data));
192
- plot.setData([dataset]);
193
- plot.setupGrid();
194
- plot.draw();
189
+ if (dataset.length >= 200) {
190
+ dataset.shift()
195
191
  }
192
+
193
+ dataset.push(point(data));
194
+ update();
196
195
  }
197
196
 
198
- // observe data events
199
- events.bind('data', onData);
197
+ function update() {
198
+ d3.select('#memory-chart svg')
199
+ .datum([{key : '', values: dataset}])
200
+ .transition()
201
+ .ease("linear").call(chart);
202
+ }
200
203
 
201
204
  return {
202
205
  render: render
@@ -206,47 +209,45 @@ var Redmon = (function() {
206
209
  //////////////////////////////////////////////////////////////////////
207
210
  // encapsulate the keyspace chart
208
211
  var keyspaceWidget = (function() {
209
- var plot
212
+ var chart
210
213
  , dataset = {
211
- hits: {label: 'Hits', data: []},
212
- misses: {label: 'Misses', data: []},
214
+ hits: {key: 'Hits' , values: []},
215
+ misses: {key: 'Misses' , values: []},
213
216
  load: function(data) {
214
217
  var self = this;
215
218
  points(data).forEach(function(point) {self.push(point)});
216
- return self.series();
219
+ return self;
217
220
  },
218
221
  append: function(data) {
219
- if (this.hits.length >= 100) this.shift();
222
+ if (this.hits.values.length >= 100) this.shift();
220
223
  this.push(point(data));
221
- return this;
222
224
  },
223
225
  push: function(point) {
224
- this.hits.data.push(point[0]);
225
- this.misses.data.push(point[1]);
226
+ this.hits.values.push(point[0]);
227
+ this.misses.values.push(point[1]);
226
228
  },
227
229
  shift: function() {
228
- this.hits.data.shift();
229
- this.misses.data.shift();
230
- },
231
- series: function() {
232
- return [this.hits, this.misses]
230
+ this.hits.values.shift();
231
+ this.misses.values.shift();
233
232
  }
234
233
  };
235
234
 
236
235
  function render(data) {
237
- plot = $.plot('#keyspace-container', dataset.load(data), {
238
- series: { shadowSize: 3 },
239
- legend: { show: false },
240
- yaxis: { tickFormatter: formatNumber },
241
- xaxis: { tickFormatter: formatTime },
242
- grid: {
243
- hoverable: true,
244
- clickable: true,
245
- backgroundColor: {
246
- colors: ['#ddd', '#fff']
247
- }
248
- }
249
- });
236
+ dataset.load(data);
237
+ chart = nv.models.lineChart()
238
+ .x(function(d) { return d.x })
239
+ .y(function(d) { return d.y })
240
+ .margin({top : 10, right : 20, bottom : 20, left : 60});
241
+
242
+ chart.xAxis
243
+ .tickFormat(formatTime);
244
+
245
+ chart.yAxis
246
+ .tickFormat(formatMetric);
247
+
248
+ update();
249
+
250
+ events.bind('data', onData);
250
251
  }
251
252
 
252
253
  function points(data) {
@@ -256,21 +257,27 @@ var Redmon = (function() {
256
257
  function point(info) {
257
258
  var time = parseInt(info.time);
258
259
  return [
259
- [time, parseInt(info.keyspace_hits)],
260
- [time, parseInt(info.keyspace_misses)]
260
+ {x: time, y: parseInt(info.keyspace_hits)},
261
+ {x: time, y: parseInt(info.keyspace_misses)}
261
262
  ];
262
263
  }
263
264
 
264
265
  function onData(ev, data) {
265
- if (data) {
266
- plot.setData(dataset.append(data).series());
267
- plot.setupGrid();
268
- plot.draw();
269
- }
266
+ dataset.append(data);
267
+ update();
270
268
  }
271
269
 
272
- // observe data events
273
- events.bind('data', onData);
270
+ function update() {
271
+ var data = [
272
+ {key : dataset.hits.key, values : dataset.hits.values, color : '#0000FF'},
273
+ {key : dataset.misses.key, values : dataset.misses.values, color : '#FF0000'}
274
+ ];
275
+
276
+ d3.select('#keyspace-chart svg')
277
+ .datum(data)
278
+ .transition()
279
+ .ease("linear").call(chart);
280
+ }
274
281
 
275
282
  return {
276
283
  render: render
@@ -281,7 +288,8 @@ var Redmon = (function() {
281
288
  // encapsulate the info widget
282
289
  var infoWidget = (function() {
283
290
  function render(data) {
284
- updateTable(data[data.length-1]);
291
+ if (data && data.length)
292
+ updateTable(data[data.length-1]);
285
293
  }
286
294
 
287
295
  function onData(ev, data) {