redis-stat 0.2.7 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # redis-stat
2
2
 
3
- A command-line Redis monitoring tool written in Ruby.
3
+ _redis-stat_ is a simple Redis monitoring tool written in Ruby.
4
+
5
+ It is based on [INFO](http://redis.io/commands/info) command of Redis,
6
+ and thus generally won't affect the performance of the Redis instance
7
+ unlike the other monitoring tools based on [MONITOR](http://redis.io/commands/monitor) command.
8
+
9
+ _redis-stat_ allows you to monitor Redis instances
10
+ - either with vmstat-like output from the terminal
11
+ - or with the dashboard page served by its embedded web server.
4
12
 
5
13
  ## Installation
6
14
 
@@ -13,38 +21,59 @@ gem install redis-stat
13
21
  ```
14
22
  usage: redis-stat [HOST[:PORT] ...] [INTERVAL [COUNT]]
15
23
 
16
- --auth=PASSWORD Password
17
- --csv=OUTPUT_CSV_FILE_PATH Save the result in CSV format
24
+ -a, --auth=PASSWORD Password
18
25
  -v, --verbose Show more info
19
26
  --style=STYLE Output style: unicode|ascii
20
27
  --no-color Suppress ANSI color codes
28
+ --csv=OUTPUT_CSV_FILE_PATH Save the result in CSV format
29
+
30
+ --server[=PORT] Launch redis-stat web server (default port: 63790)
31
+ --daemon Daemonize redis-stat. Must be used with --server option.
32
+
21
33
  --version Show version
22
34
  --help Show this message
23
35
  ```
24
36
 
25
- ## Examples
37
+ ## Running redis-stat for command-line monitoring
26
38
 
27
39
  ```
28
40
  redis-stat
29
-
30
41
  redis-stat 1
31
-
32
42
  redis-stat 1 10
33
-
43
+ redis-stat --verbose
34
44
  redis-stat localhost:6380 1 10
35
-
36
45
  redis-stat localhost localhost:6380 localhost:6381 5
37
-
38
46
  redis-stat localhost localhost:6380 1 10 --csv=/tmp/output.csv --verbose
39
47
  ```
40
48
 
41
- ## Screenshot
49
+ ### Screenshot
42
50
 
43
- ![](https://github.com/junegunn/redis-stat/raw/master/screenshots/redis-stat-0.2.4.png)
51
+ ![Terminal output](https://github.com/junegunn/redis-stat/raw/master/screenshots/redis-stat-0.3.0.png)
44
52
 
45
- ## Contributors
53
+ ## redis-stat in web browser
54
+
55
+ When `--server` option is set, redis-stat will open up an embedded web server (default port: 63790)
56
+ in the background so that you can monitor Redis in your browser.
57
+
58
+ Since _redis-stat_ pushes updates every interval via [Server-sent events](http://www.w3.org/TR/eventsource/),
59
+ modern browsers are required to view the page.
46
60
 
61
+ ```
62
+ redis-stat --server
63
+ redis-stat --verbose --server=8080 5
64
+
65
+ # redis-stat server can be daemonized
66
+ redis-stat --server --daemon
67
+ ```
68
+
69
+ ### Screenshot
70
+
71
+ ![Dashboard](https://github.com/junegunn/redis-stat/raw/master/screenshots/redis-stat-web.png)
72
+
73
+ ## Author
47
74
  - [Junegunn Choi](https://github.com/junegunn)
75
+
76
+ ## Contributors
48
77
  - [Chris Meisl](https://github.com/cmeisl)
49
78
 
50
79
  ## Contributing
data/bin/redis-stat CHANGED
@@ -5,4 +5,12 @@ require 'redis-stat'
5
5
 
6
6
  options = RedisStat::Option.parse ARGV
7
7
  rs = RedisStat.new options
8
- rs.start $stdout
8
+ if options[:daemon]
9
+ require 'daemons'
10
+ Daemons.daemonize(:app_name => 'redis-stat-daemon')
11
+ end
12
+ begin
13
+ rs.start $stdout
14
+ rescue Exception
15
+ raise if options[:verbose]
16
+ end
data/lib/redis-stat.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  # encoding: utf-8
2
2
 
3
- require "redis-stat/version"
4
- require "redis-stat/option"
3
+ require 'redis-stat/version'
4
+ require 'redis-stat/constants'
5
+ require 'redis-stat/option'
6
+ require 'redis-stat/server' unless RUBY_PLATFORM == 'java'
5
7
  require 'insensitive_hash'
6
8
  require 'redis'
7
9
  require 'tabularize'
@@ -11,15 +13,14 @@ require 'parallelize'
11
13
  require 'si'
12
14
 
13
15
  class RedisStat
14
- DEFAULT_TERM_WIDTH = 180
15
- DEFAULT_TERM_HEIGHT = 25
16
+ attr_reader :hosts, :measures
16
17
 
17
18
  def initialize options = {}
18
19
  options = RedisStat::Option::DEFAULT.merge options
19
20
  @hosts = options[:hosts]
20
21
  @redises = @hosts.map { |e|
21
22
  host, port = e.split(':')
22
- Redis.new(Hash[ {:host => host, :port => port}.select { |k, v| v } ])
23
+ Redis.new(Hash[ {:host => host, :port => port, :timeout => DEFAULT_REDIS_TIMEOUT}.select { |k, v| v } ])
23
24
  }
24
25
  @interval = options[:interval]
25
26
  @max_count = options[:count]
@@ -28,9 +29,16 @@ class RedisStat
28
29
  @csv = options[:csv]
29
30
  @auth = options[:auth]
30
31
  @measures = MEASURES[ options[:verbose] ? :verbose : :default ]
32
+ @all_measures= MEASURES.values.inject(:+).uniq - [:at]
31
33
  @count = 0
32
34
  @style = options[:style]
33
35
  @first_batch = true
36
+ @server_port = options[:server_port]
37
+ @daemonized = options[:daemon]
38
+ end
39
+
40
+ def info
41
+ collect
34
42
  end
35
43
 
36
44
  def start output_stream
@@ -50,30 +58,18 @@ class RedisStat
50
58
  end
51
59
  end
52
60
 
53
- @started_at = Time.now
54
- all_measures = MEASURES.values.inject(:+).uniq - [:at]
55
- prev_info = nil
56
- loop do
57
- info = {}.insensitive
58
- class << info
59
- def sumf label
60
- (self[label] || []).map(&:to_f).inject(:+)
61
- end
62
- end
63
-
64
- info[:at] = Time.now.to_f
65
- @redises.pmap(@redises.length) { |redis|
66
- redis.info.insensitive
67
- }.each do |rinfo|
68
- (all_measures + rinfo.keys.select { |k| k =~ /^db[0-9]+$/ }).each do |k|
69
- info[k] ||= []
70
- info[k] << rinfo[k]
71
- end
72
- end
73
61
 
74
- output info, prev_info, csv
62
+ @started_at = Time.now
63
+ prev_info = nil
64
+ server = start_server if @server_port
75
65
 
66
+ loop do
67
+ info = collect
68
+ info_output = process info, prev_info
69
+ output info, info_output, csv unless @daemonized
70
+ server.push info, Hash[info_output] if server
76
71
  prev_info = info
72
+
77
73
  @count += 1
78
74
  break if @max_count && @count >= @max_count
79
75
  sleep @interval
@@ -84,7 +80,7 @@ class RedisStat
84
80
  @os.puts ansi(:yellow, :bold) { "Interrupted." }
85
81
  rescue Exception => e
86
82
  @os.puts ansi(:red, :bold) { e.to_s }
87
- exit 1
83
+ raise
88
84
  ensure
89
85
  csv.close if csv
90
86
  end
@@ -94,14 +90,51 @@ class RedisStat
94
90
  end
95
91
 
96
92
  private
93
+ def start_server
94
+ RedisStat::Server.set :port, @server_port
95
+ RedisStat::Server.set :redis_stat, self
96
+ Thread.new { RedisStat::Server.run! }
97
+ RedisStat::Server.wait_until_running
98
+ trap('INT') { Thread.main.raise Interrupt }
99
+ RedisStat::Server
100
+ end
101
+
102
+ def collect
103
+ {}.insensitive.tap do |info|
104
+ class << info
105
+ def sumf label
106
+ (self[label] || []).map(&:to_f).inject(:+)
107
+ end
108
+ end
109
+
110
+ info[:at] = Time.now.to_f
111
+ @redises.pmap(@redises.length) { |redis|
112
+ redis.info.insensitive
113
+ }.each do |rinfo|
114
+ (@all_measures + rinfo.keys.select { |k| k =~ /^db[0-9]+$/ }).each do |k|
115
+ info[k] ||= []
116
+ info[k] << rinfo[k]
117
+ end
118
+ end
119
+ end
120
+ end
121
+
97
122
  def update_term_size!
98
- if RUBY_PLATFORM.match(/java/)
123
+ if RUBY_PLATFORM == 'java'
99
124
  require 'java'
100
125
  begin
101
- @term ||= Java::jline.Terminal.getTerminal
102
- @term_width = (@term.getTerminalWidth rescue DEFAULT_TERM_WIDTH)
103
- @term_height = (@term.getTerminalHeight rescue DEFAULT_TERM_HEIGHT) - 4
104
- return
126
+ case JRUBY_VERSION
127
+ when /^1\.7/
128
+ @term ||= Java::jline.console.ConsoleReader.new.getTerminal
129
+ @term_width = (@term.width rescue DEFAULT_TERM_WIDTH)
130
+ @term_height = (@term.height rescue DEFAULT_TERM_HEIGHT) - 4
131
+ return
132
+ when /^1\.6/
133
+ @term ||= Java::jline.ConsoleReader.new.getTerminal
134
+ @term_width = (@term.getTerminalWidth rescue DEFAULT_TERM_WIDTH)
135
+ @term_height = (@term.getTerminalHeight rescue DEFAULT_TERM_HEIGHT) - 4
136
+ return
137
+ end
105
138
  rescue Exception
106
139
  # Fallback to tput (which yields incorrect values as of now)
107
140
  end
@@ -130,9 +163,7 @@ private
130
163
  end)
131
164
  end
132
165
 
133
- def output info, prev_info, file
134
- info_output = process info, prev_info
135
-
166
+ def output info, info_output, file
136
167
  @table ||= init_table info_output
137
168
 
138
169
  movement = nil
@@ -238,9 +269,11 @@ private
238
269
 
239
270
  case key
240
271
  when :at
241
- Time.now.strftime('%H:%M:%S')
272
+ val = Time.now.strftime('%H:%M:%S')
273
+ [val, val]
242
274
  when :used_cpu_user, :used_cpu_sys
243
275
  val = get_diff.call(key)
276
+ val &&= (val * 100).round
244
277
  [humanize_number(val), val]
245
278
  when :keys
246
279
  val = Hash[ info.select { |k, v| k =~ /^db[0-9]+$/ } ].values.inject(0) { |sum, vs|
@@ -251,14 +284,12 @@ private
251
284
  :keyspace_misses_per_second, :total_commands_processed_per_second
252
285
  val = get_diff.call(key.to_s.gsub(/_per_second$/, '').to_sym)
253
286
  [humanize_number(val), val]
254
- when :total_commands_processed, :evicted_keys, :expired_keys, :keyspace_hits, :keyspace_misses
255
- val = info.sumf(key)
256
- [humanize_number(val.to_i), val]
257
287
  when :used_memory, :used_memory_rss, :aof_current_size, :aof_base_size
258
288
  val = info.sumf(key)
259
289
  [humanize_number(val.to_i, true), val]
260
290
  else
261
- humanize_number info.sumf(key)
291
+ val = info.sumf(key)
292
+ [humanize_number(val), val]
262
293
  end
263
294
  end
264
295
 
@@ -280,111 +311,4 @@ private
280
311
  ANSI::Code.ansi *args, &block
281
312
  end
282
313
  end
283
-
284
- MEASURES = {
285
- :static => [
286
- :redis_version,
287
- :process_id,
288
- :uptime_in_seconds,
289
- :uptime_in_days,
290
- :gcc_version,
291
- :role,
292
- :connected_slaves,
293
- :aof_enabled,
294
- :vm_enabled
295
- ],
296
- :default => [
297
- :at,
298
- :used_cpu_user,
299
- :used_cpu_sys,
300
- :connected_clients,
301
- :blocked_clients,
302
- :used_memory,
303
- :used_memory_rss,
304
- :keys,
305
- :total_commands_processed_per_second,
306
- :expired_keys_per_second,
307
- :evicted_keys_per_second,
308
- :keyspace_hits_per_second,
309
- :keyspace_misses_per_second,
310
- :aof_current_size,
311
- :pubsub_channels,
312
- ],
313
- :verbose => [
314
- :at,
315
- :used_cpu_user,
316
- :used_cpu_sys,
317
- :connected_clients,
318
- :blocked_clients,
319
- :used_memory,
320
- :used_memory_rss,
321
- :mem_fragmentation_ratio,
322
- :keys,
323
- :total_commands_processed_per_second,
324
- :total_commands_processed,
325
- :expired_keys_per_second,
326
- :expired_keys,
327
- :evicted_keys_per_second,
328
- :evicted_keys,
329
- :keyspace_hits_per_second,
330
- :keyspace_hits,
331
- :keyspace_misses_per_second,
332
- :keyspace_misses,
333
- :aof_current_size,
334
- :aof_base_size,
335
- :pubsub_channels,
336
- :pubsub_patterns,
337
- ]
338
- }
339
-
340
- COLORS = {
341
- :at => [:bold],
342
- :used_cpu_user => [:yellow, :bold],
343
- :used_cpu_sys => [:yellow],
344
- :connected_clients => [:cyan, :bold],
345
- :blocked_clients => [:cyan, :bold],
346
- :used_memory => [:green],
347
- :used_memory_rss => [:green],
348
- :mem_fragmentation_ratio => [:green],
349
- :keys => [:bold],
350
- :total_commands_processed => [:blue, :bold],
351
- :total_commands_processed_per_second => [:blue, :bold],
352
- :expired_keys => [:red],
353
- :expired_keys_per_second => [:red],
354
- :evicted_keys => [:red, :bold],
355
- :evicted_keys_per_second => [:red, :bold],
356
- :keyspace_hits => [:magenta, :bold],
357
- :keyspace_hits_per_second => [:magenta, :bold],
358
- :keyspace_misses => [:magenta],
359
- :keyspace_misses_per_second => [:magenta],
360
- :aof_current_size => [:cyan],
361
- :aof_base_size => [:cyan],
362
- :pubsub_channels => [:cyan, :bold],
363
- :pubsub_patterns => [:cyan, :bold],
364
- }
365
-
366
- LABELS = {
367
- :at => 'time',
368
- :used_cpu_user => 'us',
369
- :used_cpu_sys => 'sy',
370
- :connected_clients => 'cl',
371
- :blocked_clients => 'bcl',
372
- :used_memory => 'mem',
373
- :used_memory_rss => 'rss',
374
- :mem_fragmentation_ratio => 'frag',
375
- :total_commands_processed => 'cmd',
376
- :total_commands_processed_per_second => 'cmd/s',
377
- :expired_keys => 'exp',
378
- :expired_keys_per_second => 'exp/s',
379
- :evicted_keys => 'evt',
380
- :evicted_keys_per_second => 'evt/s',
381
- :keyspace_hits => 'hit',
382
- :keyspace_hits_per_second => 'hit/s',
383
- :keyspace_misses => 'mis',
384
- :keyspace_misses_per_second => 'mis/s',
385
- :aof_current_size => 'aofcs',
386
- :aof_base_size => 'aofbs',
387
- :pubsub_channels => 'psch',
388
- :pubsub_patterns => 'psp',
389
- }
390
314
  end
@@ -0,0 +1,118 @@
1
+ class RedisStat
2
+ DEFAULT_TERM_WIDTH = 180
3
+ DEFAULT_TERM_HEIGHT = 25
4
+ DEFAULT_SERVER_PORT = 63790
5
+ DEFAULT_REDIS_TIMEOUT = 30
6
+
7
+ MEASURES = {
8
+ :static => [
9
+ :redis_version,
10
+ :process_id,
11
+ :uptime_in_seconds,
12
+ :uptime_in_days,
13
+ :gcc_version,
14
+ :role,
15
+ :connected_slaves,
16
+ :aof_enabled,
17
+ :vm_enabled
18
+ ],
19
+ :default => [
20
+ :at,
21
+ :used_cpu_user,
22
+ :used_cpu_sys,
23
+ :connected_clients,
24
+ :blocked_clients,
25
+ :used_memory,
26
+ :used_memory_rss,
27
+ :keys,
28
+ :total_commands_processed_per_second,
29
+ :expired_keys_per_second,
30
+ :evicted_keys_per_second,
31
+ :keyspace_hits_per_second,
32
+ :keyspace_misses_per_second,
33
+ :aof_current_size,
34
+ :pubsub_channels,
35
+ ],
36
+ :verbose => [
37
+ :at,
38
+ :used_cpu_user,
39
+ :used_cpu_sys,
40
+ :connected_clients,
41
+ :blocked_clients,
42
+ :used_memory,
43
+ :used_memory_rss,
44
+ :mem_fragmentation_ratio,
45
+ :keys,
46
+ :total_commands_processed_per_second,
47
+ :total_commands_processed,
48
+ :expired_keys_per_second,
49
+ :expired_keys,
50
+ :evicted_keys_per_second,
51
+ :evicted_keys,
52
+ :keyspace_hits_per_second,
53
+ :keyspace_hits,
54
+ :keyspace_misses_per_second,
55
+ :keyspace_misses,
56
+ :aof_current_size,
57
+ :aof_base_size,
58
+ :changes_since_last_save,
59
+ :pubsub_channels,
60
+ :pubsub_patterns,
61
+ ]
62
+ }
63
+
64
+ COLORS = {
65
+ :at => [:bold],
66
+ :used_cpu_user => [:yellow, :bold],
67
+ :used_cpu_sys => [:yellow],
68
+ :connected_clients => [:cyan, :bold],
69
+ :blocked_clients => [:cyan, :bold],
70
+ :used_memory => [:green],
71
+ :used_memory_rss => [:green],
72
+ :mem_fragmentation_ratio => [:green],
73
+ :keys => [:bold],
74
+ :total_commands_processed => [:blue, :bold],
75
+ :total_commands_processed_per_second => [:blue, :bold],
76
+ :expired_keys => [:red],
77
+ :expired_keys_per_second => [:red],
78
+ :evicted_keys => [:red, :bold],
79
+ :evicted_keys_per_second => [:red, :bold],
80
+ :keyspace_hits => [:magenta, :bold],
81
+ :keyspace_hits_per_second => [:magenta, :bold],
82
+ :keyspace_misses => [:magenta],
83
+ :keyspace_misses_per_second => [:magenta],
84
+ :aof_current_size => [:cyan],
85
+ :aof_base_size => [:cyan],
86
+ :changes_since_last_save => [:green, :bold],
87
+ :pubsub_channels => [:cyan, :bold],
88
+ :pubsub_patterns => [:cyan, :bold],
89
+ }
90
+
91
+ LABELS = {
92
+ :at => 'time',
93
+ :used_cpu_user => 'us',
94
+ :used_cpu_sys => 'sy',
95
+ :connected_clients => 'cl',
96
+ :blocked_clients => 'bcl',
97
+ :used_memory => 'mem',
98
+ :used_memory_rss => 'rss',
99
+ :mem_fragmentation_ratio => 'frag',
100
+ :total_commands_processed => 'cmd',
101
+ :total_commands_processed_per_second => 'cmd/s',
102
+ :expired_keys => 'exp',
103
+ :expired_keys_per_second => 'exp/s',
104
+ :evicted_keys => 'evt',
105
+ :evicted_keys_per_second => 'evt/s',
106
+ :keys => 'keys',
107
+ :keyspace_hits => 'hit',
108
+ :keyspace_hits_per_second => 'hit/s',
109
+ :keyspace_misses => 'mis',
110
+ :keyspace_misses_per_second => 'mis/s',
111
+ :aof_current_size => 'aofcs',
112
+ :aof_base_size => 'aofbs',
113
+ :changes_since_last_save => 'chsv',
114
+ :pubsub_channels => 'psch',
115
+ :pubsub_patterns => 'psp',
116
+ }
117
+ end
118
+