redis-stat 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -11,7 +11,7 @@ gem install redis-stat
11
11
  ## Usage
12
12
 
13
13
  ```
14
- usage: redis-stat [HOST[:PORT]] [INTERVAL [COUNT]]
14
+ usage: redis-stat [HOST[:PORT] ...] [INTERVAL [COUNT]]
15
15
 
16
16
  --csv=OUTPUT_CSV_FILE_PATH Save the result in CSV format
17
17
  -v, --verbose Show more info
@@ -26,11 +26,13 @@ redis-stat
26
26
 
27
27
  redis-stat 1
28
28
 
29
- redis-stat localhost:6380
29
+ redis-stat 1 10
30
30
 
31
31
  redis-stat localhost:6380 1 10
32
32
 
33
- redis-stat localhost:6380 1 10 --csv=/tmp/output.csv --verbose
33
+ redis-stat localhost localhost:6380 localhost:6381 5
34
+
35
+ redis-stat localhost localhost:6380 1 10 --csv=/tmp/output.csv --verbose
34
36
  ```
35
37
 
36
38
  ## Screenshot
data/lib/redis-stat.rb CHANGED
@@ -5,6 +5,7 @@ require 'redis'
5
5
  require 'tabularize'
6
6
  require 'ansi'
7
7
  require 'csv'
8
+ require 'parallelize'
8
9
 
9
10
  class RedisStat
10
11
  DEFAULT_TERM_WIDTH = 180
@@ -12,7 +13,11 @@ class RedisStat
12
13
 
13
14
  def initialize options = {}
14
15
  @options = RedisStat::Option::DEFAULT.merge options
15
- @redis = Redis.new(Hash[ @options.select { |k, _| [:host, :port].include? k } ])
16
+ @hosts = @options[:hosts]
17
+ @redises = @hosts.map { |e|
18
+ host, port = e.split(':')
19
+ Redis.new(Hash[ {:host => host, :port => port}.select { |k, v| v } ])
20
+ }
16
21
  @max_count = @options[:count]
17
22
  @count = 0
18
23
  @colors = @options[:colors] || COLORS
@@ -25,12 +30,30 @@ class RedisStat
25
30
  csv = File.open(@options[:csv], 'w') if @options[:csv]
26
31
  update_term_size!
27
32
 
28
- prev_info = nil
33
+
29
34
  begin
35
+ # Warm-up
36
+ @redises.each { |r| r.info }
37
+
30
38
  @started_at = Time.now
39
+ prev_info = nil
31
40
  loop do
32
- info = @redis.info.insensitive
41
+ info = {}.insensitive
42
+ class << info
43
+ def sumf label
44
+ (self[label] || []).map(&:to_f).inject(:+)
45
+ end
46
+ end
47
+
33
48
  info[:at] = Time.now.to_f
49
+ @redises.pmap(@redises.length) { |redis|
50
+ redis.info.insensitive
51
+ }.each do |rinfo|
52
+ rinfo.each do |k, v|
53
+ info[k] ||= []
54
+ info[k] << v
55
+ end
56
+ end
34
57
 
35
58
  output info, prev_info, csv
36
59
 
@@ -98,9 +121,9 @@ private
98
121
 
99
122
  movement = nil
100
123
  if @count == 0
101
- movement = 0
102
124
  output_static_info info
103
125
 
126
+ movement = 0
104
127
  if file
105
128
  file.puts CSV.generate_line(info_output.map { |pair|
106
129
  LABELS[pair.first] || pair.first
@@ -147,30 +170,28 @@ private
147
170
  end
148
171
 
149
172
  def output_static_info info
150
- data =
151
- {
152
- :redis_stat_version => RedisStat::VERSION,
153
- :redis_host => @options[:host],
154
- :redis_port => @options[:port],
155
- :csv => @options[:csv],
156
- }.merge(
157
- Hash[
158
- [
159
- :redis_version,
160
- :process_id,
161
- :uptime_in_seconds,
162
- :uptime_in_days,
163
- :gcc_version,
164
- :role,
165
- :connected_slaves, # FIXME: not so static
166
- :aof_enabled,
167
- :vm_enabled
168
- ].map { |k| [k, info[k]] }
169
- ]
170
- ).reject { |k, v| v.nil? }.to_a
171
- @os.puts Tabularize.it(data, :align => :left).map { |pair|
172
- ansi(:bold) { pair.first } + ' : ' + pair.last
173
- }
173
+ tab = Tabularize.new(
174
+ :unicode => false, :align => :right,
175
+ :hborder => ansi(:black, :bold) { '-' },
176
+ :vborder => ansi(:black, :bold) { '|' },
177
+ :iborder => ansi(:black, :bold) { '+' }
178
+ )
179
+ tab << [nil] + @hosts.map { |h| ansi(:bold, :green) { h } }
180
+ tab.separator!
181
+ [
182
+ :redis_version,
183
+ :process_id,
184
+ :uptime_in_seconds,
185
+ :uptime_in_days,
186
+ :gcc_version,
187
+ :role,
188
+ :connected_slaves,
189
+ :aof_enabled,
190
+ :vm_enabled
191
+ ].each do |key|
192
+ tab << [ansi(:bold) { key }] + info[key]
193
+ end
194
+ @os.puts tab
174
195
  end
175
196
 
176
197
  def init_table info_output
@@ -179,6 +200,7 @@ private
179
200
  :hborder => ansi(:black, :bold) { '-' },
180
201
  :iborder => ansi(:black, :bold) { '+' },
181
202
  :vborder => ' ',
203
+ :ellipsis => ansi(:bold) { '>' },
182
204
  :pad_left => 0,
183
205
  :pad_right => 0,
184
206
  :screen_width => @term_width
@@ -200,8 +222,8 @@ private
200
222
  dur = prev_info && (info[:at] - prev_info[:at])
201
223
 
202
224
  get_diff = lambda do |label|
203
- if dur
204
- (info[label].to_f - prev_info[label].to_f) / dur
225
+ if dur && dur > 0
226
+ (info.sumf(label) - prev_info.sumf(label)) / dur
205
227
  else
206
228
  nil
207
229
  end
@@ -214,8 +236,8 @@ private
214
236
  val = get_diff.call(key)
215
237
  [humanize_number(val), val]
216
238
  when :keys
217
- val = Hash[ info.select { |k, v| k =~ /^db[0-9]+$/ } ].values.inject(0) { |sum, v|
218
- sum + Hash[ v.split(',').map { |e| e.split '=' } ]['keys'].to_i
239
+ val = Hash[ info.select { |k, v| k =~ /^db[0-9]+$/ } ].values.inject(0) { |sum, vs|
240
+ sum + vs.map { |v| Hash[ v.split(',').map { |e| e.split '=' } ]['keys'].to_i }.inject(:+)
219
241
  }
220
242
  [humanize_number(val), val]
221
243
  when :evicted_keys_per_second, :expired_keys_per_second, :keyspace_hits_per_second,
@@ -223,11 +245,13 @@ private
223
245
  val = get_diff.call(key.to_s.gsub(/_per_second$/, '').to_sym)
224
246
  [humanize_number(val), val]
225
247
  when :total_commands_processed, :evicted_keys, :expired_keys, :keyspace_hits, :keyspace_misses
226
- [humanize_number(info[key].to_i), info[key]]
248
+ val = info.sumf(key)
249
+ [humanize_number(val.to_i), val]
227
250
  when :used_memory, :used_memory_rss, :aof_current_size, :aof_base_size
228
- [humanize_number(info[key].to_i, 1024, 'B'), info[key]]
251
+ val = info.sumf(key)
252
+ [humanize_number(val.to_i, 1024, 'B'), val]
229
253
  else
230
- info[key]
254
+ format_number info.sumf(key)
231
255
  end
232
256
  end
233
257
 
@@ -3,8 +3,7 @@ require 'optparse'
3
3
  class RedisStat
4
4
  module Option
5
5
  DEFAULT = {
6
- :host => '127.0.0.1',
7
- :port => 6379,
6
+ :hosts => ['127.0.0.1:6379'],
8
7
  :interval => 2,
9
8
  :count => nil,
10
9
  :csv => nil
@@ -15,7 +14,7 @@ module Option
15
14
 
16
15
  options = DEFAULT.dup
17
16
  opts = ::OptionParser.new { |opts|
18
- opts.banner = "usage: redis-stat [HOST[:PORT]] [INTERVAL [COUNT]]"
17
+ opts.banner = "usage: redis-stat [HOST[:PORT] ...] [INTERVAL [COUNT]]"
19
18
  opts.separator ''
20
19
 
21
20
  opts.on('--csv=OUTPUT_CSV_FILE_PATH', 'Save the result in CSV format') do |v|
@@ -41,33 +40,13 @@ module Option
41
40
  opts.parse! argv
42
41
 
43
42
  is_number = lambda { |str| str =~ /^([0-9]\.?[0-9]*)$|^([1-9][0-9]*)$/ }
44
- set_options = lambda { |host_port, interval, count|
45
- if host_port
46
- host, port = host_port.split(':')
47
- options[:host] = host
48
- options[:port] = port.to_i if port
49
- end
50
43
 
51
- options[:interval] = interval.to_f if interval
52
- options[:count] = count.to_i if count
53
- }
44
+ numbers, hosts = argv.partition { |e| is_number.call e }
45
+ interval, count = numbers.map(&:to_f)
54
46
 
55
- case argv.length
56
- when 1
57
- if is_number.call argv.first
58
- set_options.call nil, argv.first, nil
59
- else
60
- set_options.call argv.first, nil, nil
61
- end
62
- when 2
63
- if is_number.call argv.first
64
- set_options.call nil, argv.first, argv.last
65
- else
66
- set_options.call argv.first, argv.last, nil
67
- end
68
- when 3
69
- set_options.call *argv
70
- end
47
+ options[:interval] = interval if interval
48
+ options[:count] = count if count
49
+ options[:hosts] = hosts unless hosts.empty?
71
50
 
72
51
  validate options
73
52
 
@@ -92,9 +71,19 @@ module Option
92
71
  raise ArgumentError.new("Invalid count: #{count}")
93
72
  end
94
73
 
95
- port = options[:port]
96
- unless port.is_a?(Fixnum) && port > 0 && port < 65536
97
- raise ArgumentError.new("Invalid port: #{port}")
74
+ hosts = options[:hosts]
75
+ if hosts.empty?
76
+ raise ArgumentError.new("Redis host not given")
77
+ end
78
+
79
+ hosts.each do |host|
80
+ host, port = host.split(':')
81
+ if port
82
+ port = port.to_i
83
+ unless port > 0 && port < 65536
84
+ raise ArgumentError.new("Invalid port: #{port}")
85
+ end
86
+ end
98
87
  end
99
88
  end
100
89
  end
@@ -1,3 +1,3 @@
1
1
  class RedisStat
2
- VERSION = "0.1.4"
2
+ VERSION = "0.2.0"
3
3
  end
data/redis-stat.gemspec CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |gem|
19
19
  gem.add_runtime_dependency "redis", '~> 3.0.1'
20
20
  gem.add_runtime_dependency "tabularize", '~> 0.2.4'
21
21
  gem.add_runtime_dependency "insensitive_hash", '~> 0.2.4'
22
+ gem.add_runtime_dependency "parallelize", '~> 0.4.0'
22
23
 
23
24
  gem.add_development_dependency 'test-unit'
24
25
  end
@@ -43,8 +43,7 @@ class TestRedisStat < Test::Unit::TestCase
43
43
 
44
44
  options = RedisStat::Option.parse(%w[localhost:1000 20])
45
45
  assert_equal({
46
- :host => 'localhost',
47
- :port => 1000,
46
+ :hosts => ['localhost:1000'],
48
47
  :interval => 20,
49
48
  :count => nil,
50
49
  :csv => nil
@@ -52,8 +51,7 @@ class TestRedisStat < Test::Unit::TestCase
52
51
 
53
52
  options = RedisStat::Option.parse(%w[localhost:1000 20 30])
54
53
  assert_equal({
55
- :host => 'localhost',
56
- :port => 1000,
54
+ :hosts => ['localhost:1000'],
57
55
  :interval => 20,
58
56
  :count => 30,
59
57
  :csv => nil
@@ -61,8 +59,7 @@ class TestRedisStat < Test::Unit::TestCase
61
59
 
62
60
  options = RedisStat::Option.parse(%w[20])
63
61
  assert_equal({
64
- :host => '127.0.0.1',
65
- :port => 6379,
62
+ :hosts => ['127.0.0.1:6379'],
66
63
  :interval => 20,
67
64
  :count => nil,
68
65
  :csv => nil
@@ -70,8 +67,7 @@ class TestRedisStat < Test::Unit::TestCase
70
67
 
71
68
  options = RedisStat::Option.parse(%w[20 30])
72
69
  assert_equal({
73
- :host => '127.0.0.1',
74
- :port => 6379,
70
+ :hosts => ['127.0.0.1:6379'],
75
71
  :interval => 20,
76
72
  :count => 30,
77
73
  :csv => nil
@@ -79,8 +75,7 @@ class TestRedisStat < Test::Unit::TestCase
79
75
 
80
76
  options = RedisStat::Option.parse(%w[localhost:8888 10 --csv=/tmp/a.csv])
81
77
  assert_equal({
82
- :port => 8888,
83
- :host => 'localhost',
78
+ :hosts => ['localhost:8888'],
84
79
  :interval => 10,
85
80
  :count => nil,
86
81
  :csv => '/tmp/a.csv',
@@ -101,7 +96,7 @@ class TestRedisStat < Test::Unit::TestCase
101
96
  def test_start
102
97
  csv = '/tmp/redis-stat.csv'
103
98
  cnt = 50
104
- rs = RedisStat.new :interval => 0.01, :count => cnt, :verbose => true, :csv => csv
99
+ rs = RedisStat.new :hosts => %w[localhost] * 5, :interval => 0.1, :count => cnt, :verbose => true, :csv => csv
105
100
  rs.start $stdout
106
101
 
107
102
  assert_equal cnt + 1, File.read(csv).lines.to_a.length
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.1.4
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -75,6 +75,22 @@ dependencies:
75
75
  - - ~>
76
76
  - !ruby/object:Gem::Version
77
77
  version: 0.2.4
78
+ - !ruby/object:Gem::Dependency
79
+ name: parallelize
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 0.4.0
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 0.4.0
78
94
  - !ruby/object:Gem::Dependency
79
95
  name: test-unit
80
96
  requirement: !ruby/object:Gem::Requirement