redmon 0.0.4 → 0.0.5

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/.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) {