redis-stat 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,14 +9,15 @@ class RedisStat
9
9
  MEASURES = {
10
10
  :static => [
11
11
  :redis_version,
12
+ :redis_mode,
12
13
  :process_id,
13
14
  :uptime_in_seconds,
14
15
  :uptime_in_days,
15
- :gcc_version,
16
16
  :role,
17
17
  :connected_slaves,
18
18
  :aof_enabled,
19
- :vm_enabled
19
+ [:rdb_bgsave_in_progress, :bgsave_in_progress],
20
+ [:rdb_last_save_time, :last_save_time],
20
21
  ],
21
22
  :default => [
22
23
  :at,
@@ -57,7 +58,7 @@ class RedisStat
57
58
  :keyspace_misses,
58
59
  :aof_current_size,
59
60
  :aof_base_size,
60
- :changes_since_last_save,
61
+ [:rdb_changes_since_last_save, :changes_since_last_save],
61
62
  :pubsub_channels,
62
63
  :pubsub_patterns,
63
64
  ]
@@ -85,7 +86,7 @@ class RedisStat
85
86
  :keyspace_misses_per_second => [:magenta],
86
87
  :aof_current_size => [:cyan],
87
88
  :aof_base_size => [:cyan],
88
- :changes_since_last_save => [:green, :bold],
89
+ :rdb_changes_since_last_save => [:green, :bold],
89
90
  :pubsub_channels => [:cyan, :bold],
90
91
  :pubsub_patterns => [:cyan, :bold],
91
92
  }
@@ -112,7 +113,7 @@ class RedisStat
112
113
  :keyspace_misses_per_second => 'mis/s',
113
114
  :aof_current_size => 'aofcs',
114
115
  :aof_base_size => 'aofbs',
115
- :changes_since_last_save => 'chsv',
116
+ :rdb_changes_since_last_save => 'chsv',
116
117
  :pubsub_channels => 'psch',
117
118
  :pubsub_patterns => 'psp',
118
119
  }
@@ -42,9 +42,6 @@ module Option
42
42
 
43
43
  opts.on('--server[=PORT]', "Launch redis-stat web server (default port: #{RedisStat::DEFAULT_SERVER_PORT})") do |v|
44
44
  options[:server_port] = v || RedisStat::DEFAULT_SERVER_PORT
45
- if RUBY_PLATFORM == 'java'
46
- raise ArgumentError.new("Sorry. redis-stat server is not supported in JRuby.")
47
- end
48
45
  end
49
46
 
50
47
  opts.on('--daemon', "Daemonize redis-stat. Must be used with --server option.") do |v|
@@ -66,7 +63,7 @@ module Option
66
63
  exit 0
67
64
  end
68
65
  }
69
-
66
+
70
67
  begin
71
68
  opts.parse! argv
72
69
 
@@ -125,7 +122,7 @@ module Option
125
122
  raise ArgumentError.new("Invalid style")
126
123
  end
127
124
  end
128
-
125
+
129
126
  if options[:daemon] && options[:server_port].nil?
130
127
  raise ArgumentError.new("--daemon option must be used in conjunction with --server option")
131
128
  end
@@ -5,8 +5,7 @@ var history = [],
5
5
  colors,
6
6
  info,
7
7
  fade_dur,
8
- chart_options,
9
- stats_to_update = ['uptime_in_seconds', 'uptime_in_days']
8
+ chart_options
10
9
 
11
10
  var initialize = function(params) {
12
11
  measures = params.measures
@@ -89,7 +88,7 @@ var initialize = function(params) {
89
88
  shadow: false,
90
89
  },
91
90
  series: [
92
- { label: "used" },
91
+ { label: "mem" },
93
92
  { label: "rss" }
94
93
  ],
95
94
  axesDefaults: {
@@ -134,8 +133,13 @@ var initialize = function(params) {
134
133
  }
135
134
 
136
135
  var appendToHistory = function(json) {
137
- history.push(json)
138
- if (history.length > max) history.shift()
136
+ if (history.length == 0 || json.at > history[ history.length - 1 ].at) {
137
+ history.push(json)
138
+ if (history.length > max) history.shift()
139
+ return true
140
+ } else {
141
+ return false
142
+ }
139
143
  }
140
144
 
141
145
  var updateTable = function() {
@@ -144,12 +148,10 @@ var updateTable = function() {
144
148
  jd = json.dynamic
145
149
 
146
150
  // Instance information (mostly static)
147
- // for (stat in js) {
148
- for (var i = 0; i < stats_to_update.length; ++i) {
149
- var stat = stats_to_update[i]
151
+ for (var stat in js) {
150
152
  $("#" + stat).replaceWith(
151
153
  "<tr id='" + stat + "'><th>" + stat + "</th>" +
152
- js[stat].map(function(e) { return "<td>" + e + "</td>" }).join() +
154
+ js[stat].map(function(e) { return "<td>" + (e == null ? "" : e) + "</td>" }).join() +
153
155
  "</tr>"
154
156
  )
155
157
  }
@@ -26,6 +26,11 @@
26
26
  <div class="row">
27
27
  <div class="span12">
28
28
  <h3>Dashboard</h3>
29
+ <% unless RUBY_PLATFORM == 'java' %>
30
+ <div class="alert alert-error hide">
31
+ <h4>Lost connection to redis-stat</h4>
32
+ </div>
33
+ <% end %>
29
34
  </div>
30
35
  </div>
31
36
 
@@ -80,7 +85,7 @@
80
85
  </tr>
81
86
  </thead>
82
87
  <tbody>
83
- <% RedisStat::MEASURES[:static].each do |stat| %>
88
+ <% @tab_measures.each do |stat| %>
84
89
  <tr id="<%= stat %>">
85
90
  <th>
86
91
  <%= stat %>
@@ -103,19 +108,6 @@
103
108
  <img style="position: fixed; top: 0; right: 0; border: 0; z-index: 10000" src="/forkme.png" alt="Fork me on GitHub">
104
109
  </a>
105
110
 
106
- <div class="modal hide fade" id="fail" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
107
- <div class="modal-header">
108
- <h3 id="myModalLabel">Oops!</h3>
109
- </div>
110
- <div class="modal-body">
111
- <p>Lost connection to redis-stat.</p>
112
- <p>Try reloading the page.</p>
113
- </div>
114
- <div class="modal-footer">
115
- <a href="/" class="btn btn-primary">Reload</a>
116
- </div>
117
- </div>
118
-
119
111
  <footer class="footer">
120
112
  <div class="container">
121
113
  <p>Powered by <a href="http://twitter.github.com/bootstrap/">Bootstrap</a>, <a href="http://jquery.com/">jQuery</a> and <a href="http://www.jqplot.com/">jqPlot</a>.</p>
@@ -134,15 +126,19 @@
134
126
 
135
127
  $("#stat_table th a").tooltip()
136
128
 
129
+ // TODO Check (typeof(EventSource) !== "undefined")
130
+
137
131
  var source = new EventSource("/pull")
138
132
  source.onmessage = function(e) {
139
- appendToHistory(JSON.parse(e.data))
140
- updateTable()
141
- updatePlot()
133
+ if (appendToHistory(JSON.parse(e.data))) {
134
+ $(".alert").fadeOut()
135
+ updateTable()
136
+ updatePlot()
137
+ }
142
138
  }
143
139
  source.onerror = function(e) {
144
- source.close()
145
- $('#fail').modal({backdrop: 'static'})
140
+ $(".alert").fadeIn()
141
+ // source.close()
146
142
  }
147
143
  })
148
144
  </script>
@@ -1,5 +1,6 @@
1
1
  require 'sinatra/base'
2
2
  require 'json'
3
+ require 'thread'
3
4
 
4
5
  class RedisStat
5
6
  class Server < Sinatra::Base
@@ -7,7 +8,10 @@ class Server < Sinatra::Base
7
8
  STAT_TABLE_ROWS = 10
8
9
 
9
10
  configure do
10
- unless RUBY_PLATFORM == 'java'
11
+ if RUBY_PLATFORM == 'java'
12
+ require 'puma'
13
+ set :server, :puma
14
+ else
11
15
  require 'thin'
12
16
  set :server, :thin
13
17
  end
@@ -15,24 +19,32 @@ class Server < Sinatra::Base
15
19
  set :root, File.join( File.dirname(__FILE__), 'server' )
16
20
  set :clients, []
17
21
  set :history, []
22
+ set :mutex, Mutex.new
18
23
  end
19
24
 
20
25
  get '/' do
21
- @hosts = settings.redis_stat.hosts
22
- @info = settings.redis_stat.info
23
- @measures = settings.redis_stat.measures
24
- @interval = settings.redis_stat.interval
25
- @verbose = settings.redis_stat.verbose ? 'verbose' : ''
26
- @history = settings.history
26
+ @hosts = settings.redis_stat.hosts
27
+ @info = settings.redis_stat.info
28
+ @measures = settings.redis_stat.measures
29
+ @tab_measures = settings.redis_stat.tab_measures
30
+ @interval = settings.redis_stat.interval
31
+ @verbose = settings.redis_stat.verbose ? 'verbose' : ''
32
+ @history = settings.history
27
33
  erb :index
28
34
  end
29
35
 
30
36
  get '/pull' do
31
37
  content_type 'text/event-stream'
32
38
 
33
- stream(:keep_open) do |out|
34
- settings.clients << out
35
- out.callback { settings.clients.delete out }
39
+ if RUBY_PLATFORM == 'java'
40
+ if last = settings.mutex.synchronize { settings.history.last }
41
+ body "retry: #{settings.redis_stat.interval * 900}\ndata: #{last.to_json}\n\n"
42
+ end
43
+ else
44
+ stream(:keep_open) do |out|
45
+ settings.clients << out
46
+ out.callback { settings.clients.delete out }
47
+ end
36
48
  end
37
49
  end
38
50
 
@@ -44,14 +56,18 @@ class Server < Sinatra::Base
44
56
  end
45
57
 
46
58
  def push info, data
47
- static = Hash[RedisStat::MEASURES[:static].map { |stat|
59
+ static = Hash[settings.redis_stat.tab_measures.map { |stat|
48
60
  [stat, info[stat]]
49
61
  }]
50
- data = {:static => static, :dynamic => data}
62
+ data = {:at => Time.now.to_i, :static => static, :dynamic => data}
63
+
64
+ hist = settings.history
65
+ settings.mutex.synchronize do
66
+ hist << data
67
+ hist.shift if hist.length > HISTORY_LENGTH
68
+ end
51
69
 
52
- @history = settings.history
53
- @history << data
54
- @history.shift if @history.length > HISTORY_LENGTH
70
+ return if settings.clients.empty?
55
71
 
56
72
  resp = "data: #{data.to_json}\n\n"
57
73
  settings.clients.each do |cl|
@@ -1,3 +1,3 @@
1
1
  class RedisStat
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.2"
3
3
  end
data/lib/redis-stat.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require 'redis-stat/version'
4
4
  require 'redis-stat/constants'
5
5
  require 'redis-stat/option'
6
- require 'redis-stat/server' unless RUBY_PLATFORM == 'java'
6
+ require 'redis-stat/server'
7
7
  require 'insensitive_hash'
8
8
  require 'redis'
9
9
  require 'tabularize'
@@ -13,12 +13,12 @@ require 'parallelize'
13
13
  require 'si'
14
14
 
15
15
  class RedisStat
16
- attr_reader :hosts, :measures, :verbose, :interval
16
+ attr_reader :hosts, :measures, :tab_measures, :verbose, :interval
17
17
 
18
18
  def initialize options = {}
19
19
  options = RedisStat::Option::DEFAULT.merge options
20
20
  @hosts = options[:hosts]
21
- @redises = @hosts.map { |e|
21
+ @redises = @hosts.map { |e|
22
22
  host, port = e.split(':')
23
23
  Redis.new(Hash[ {:host => host, :port => port, :timeout => DEFAULT_REDIS_TIMEOUT}.select { |k, v| v } ])
24
24
  }
@@ -29,7 +29,8 @@ class RedisStat
29
29
  @csv = options[:csv]
30
30
  @auth = options[:auth]
31
31
  @verbose = options[:verbose]
32
- @measures = MEASURES[ @verbose ? :verbose : :default ]
32
+ @measures = MEASURES[ @verbose ? :verbose : :default ].map { |m| [*m].first }
33
+ @tab_measures= MEASURES[:static].map { |m| [*m].first }
33
34
  @all_measures= MEASURES.values.inject(:+).uniq - [:at]
34
35
  @count = 0
35
36
  @style = options[:style]
@@ -72,9 +73,12 @@ class RedisStat
72
73
  rescue Interrupt
73
74
  raise
74
75
  rescue Exception => e
75
- if (errs += 1) < NUM_RETRIES
76
+ errs += 1
77
+ if server || errs < NUM_RETRIES
76
78
  @os.puts if errs == 1
77
- @os.puts ansi(:red, :bold) { "#{e} (#{errs}/#{NUM_RETRIES})" }
79
+ @os.puts ansi(:red, :bold) {
80
+ "#{e} (#{ server ? "#{errs}" : [errs, NUM_RETRIES].join('/') })"
81
+ }
78
82
  sleep @interval
79
83
  retry
80
84
  else
@@ -128,8 +132,11 @@ private
128
132
  redis.info.insensitive
129
133
  }.each do |rinfo|
130
134
  (@all_measures + rinfo.keys.select { |k| k =~ /^db[0-9]+$/ }).each do |k|
135
+ ks = [*k]
136
+ v = ks.map { |e| rinfo[e] }.compact.first
137
+ k = ks.first
131
138
  info[k] ||= []
132
- info[k] << rinfo[k]
139
+ info[k] << v
133
140
  end
134
141
  end
135
142
  end
@@ -241,7 +248,7 @@ private
241
248
  )
242
249
  tab << [nil] + @hosts.map { |h| ansi(:bold, :green) { h } }
243
250
  tab.separator!
244
- MEASURES[:static].each do |key|
251
+ @tab_measures.each do |key|
245
252
  tab << [ansi(:bold) { key }] + info[key] unless info[key].compact.empty?
246
253
  end
247
254
  @os.puts tab
@@ -260,7 +267,7 @@ private
260
267
  table << info_output.map { |pair|
261
268
  ansi(*((@colors[pair.first] || []) + [:underline])) {
262
269
  LABELS[pair.first] || pair.first
263
- }
270
+ }
264
271
  }
265
272
  table.separator!
266
273
  table
@@ -292,7 +299,7 @@ private
292
299
  val &&= (val * 100).round
293
300
  [humanize_number(val), val]
294
301
  when :keys
295
- val = Hash[ info.select { |k, v| k =~ /^db[0-9]+$/ } ].values.inject(0) { |sum, vs|
302
+ val = Hash[ info.select { |k, v| k =~ /^db[0-9]+$/ } ].values.inject(0) { |sum, vs|
296
303
  sum + vs.map { |v| Hash[ v.split(',').map { |e| e.split '=' } ]['keys'].to_i }.inject(:+)
297
304
  }
298
305
  [humanize_number(val), val]
data/redis-stat.gemspec CHANGED
@@ -17,15 +17,18 @@ Gem::Specification.new do |gem|
17
17
  gem.version = RedisStat::VERSION
18
18
 
19
19
  gem.add_runtime_dependency "ansi", '~> 1.4.3'
20
- gem.add_runtime_dependency "redis", '~> 3.0.1'
21
- gem.add_runtime_dependency "tabularize", '~> 0.2.8'
20
+ gem.add_runtime_dependency "redis", '~> 3.0.2'
21
+ gem.add_runtime_dependency "tabularize", '~> 0.2.9'
22
22
  gem.add_runtime_dependency "insensitive_hash", '~> 0.3.0'
23
23
  gem.add_runtime_dependency "parallelize", '~> 0.4.0'
24
- gem.add_runtime_dependency "si", '~> 0.1.3'
25
- unless RUBY_PLATFORM == 'java'
26
- gem.add_runtime_dependency "sinatra", '~> 1.3.3'
27
- gem.add_runtime_dependency "thin", '~> 1.5.0'
28
- gem.add_runtime_dependency "json", '~> 1.7.5'
24
+ gem.add_runtime_dependency "si", '~> 0.1.4'
25
+ gem.add_runtime_dependency "sinatra", '~> 1.3.3'
26
+ gem.add_runtime_dependency "json", '~> 1.7.5'
27
+
28
+ if RUBY_PLATFORM == 'java'
29
+ gem.add_runtime_dependency "puma", '~> 1.6.3'
30
+ else
31
+ gem.add_runtime_dependency "thin", '~> 1.5.0'
29
32
  gem.add_runtime_dependency "daemons", '~> 1.1.9'
30
33
  end
31
34
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-stat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-31 00:00:00.000000000 Z
12
+ date: 2012-12-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ansi
@@ -34,7 +34,7 @@ dependencies:
34
34
  requirements:
35
35
  - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: 3.0.1
37
+ version: 3.0.2
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +42,7 @@ dependencies:
42
42
  requirements:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: 3.0.1
45
+ version: 3.0.2
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: tabularize
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -50,7 +50,7 @@ dependencies:
50
50
  requirements:
51
51
  - - ~>
52
52
  - !ruby/object:Gem::Version
53
- version: 0.2.8
53
+ version: 0.2.9
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,7 +58,7 @@ dependencies:
58
58
  requirements:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: 0.2.8
61
+ version: 0.2.9
62
62
  - !ruby/object:Gem::Dependency
63
63
  name: insensitive_hash
64
64
  requirement: !ruby/object:Gem::Requirement
@@ -98,7 +98,7 @@ dependencies:
98
98
  requirements:
99
99
  - - ~>
100
100
  - !ruby/object:Gem::Version
101
- version: 0.1.3
101
+ version: 0.1.4
102
102
  type: :runtime
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
@@ -106,7 +106,7 @@ dependencies:
106
106
  requirements:
107
107
  - - ~>
108
108
  - !ruby/object:Gem::Version
109
- version: 0.1.3
109
+ version: 0.1.4
110
110
  - !ruby/object:Gem::Dependency
111
111
  name: sinatra
112
112
  requirement: !ruby/object:Gem::Requirement
@@ -124,13 +124,13 @@ dependencies:
124
124
  - !ruby/object:Gem::Version
125
125
  version: 1.3.3
126
126
  - !ruby/object:Gem::Dependency
127
- name: thin
127
+ name: json
128
128
  requirement: !ruby/object:Gem::Requirement
129
129
  none: false
130
130
  requirements:
131
131
  - - ~>
132
132
  - !ruby/object:Gem::Version
133
- version: 1.5.0
133
+ version: 1.7.5
134
134
  type: :runtime
135
135
  prerelease: false
136
136
  version_requirements: !ruby/object:Gem::Requirement
@@ -138,15 +138,15 @@ dependencies:
138
138
  requirements:
139
139
  - - ~>
140
140
  - !ruby/object:Gem::Version
141
- version: 1.5.0
141
+ version: 1.7.5
142
142
  - !ruby/object:Gem::Dependency
143
- name: json
143
+ name: thin
144
144
  requirement: !ruby/object:Gem::Requirement
145
145
  none: false
146
146
  requirements:
147
147
  - - ~>
148
148
  - !ruby/object:Gem::Version
149
- version: 1.7.5
149
+ version: 1.5.0
150
150
  type: :runtime
151
151
  prerelease: false
152
152
  version_requirements: !ruby/object:Gem::Requirement
@@ -154,7 +154,7 @@ dependencies:
154
154
  requirements:
155
155
  - - ~>
156
156
  - !ruby/object:Gem::Version
157
- version: 1.7.5
157
+ version: 1.5.0
158
158
  - !ruby/object:Gem::Dependency
159
159
  name: daemons
160
160
  requirement: !ruby/object:Gem::Requirement