sidekiq-spy 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +119 -0
- data/Rakefile +11 -0
- data/bin/sidekiq-spy +99 -0
- data/lib/sidekiq-spy.rb +11 -0
- data/lib/sidekiq-spy/app.rb +74 -0
- data/lib/sidekiq-spy/config.rb +34 -0
- data/lib/sidekiq-spy/display/panel.rb +81 -0
- data/lib/sidekiq-spy/display/screen.rb +82 -0
- data/lib/sidekiq-spy/display/subpanel.rb +47 -0
- data/lib/sidekiq-spy/spy/stats.rb +73 -0
- data/lib/sidekiq-spy/translatable.rb +32 -0
- data/lib/sidekiq-spy/version.rb +5 -0
- data/sidekiq-spy.gemspec +27 -0
- data/test/fixtures/redis_info.json +61 -0
- data/test/helper.rb +6 -0
- data/test/sidekiq-spy/app_test.rb +60 -0
- data/test/sidekiq-spy/config_test.rb +140 -0
- data/test/sidekiq-spy/spy/stats_test.rb +125 -0
- data/test/sidekiq-spy/version_test.rb +12 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7a20cacb912beed5baf1c80012a87e5115dae2bf
|
4
|
+
data.tar.gz: 1db3848aa6af319f5037ee72dc6720683735d53d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ed49f93281287bbc32d5a5b7629a85d5489e50e35bbae88e16369e764644d87f697593c610a5e149e65d9a4aff8041dc902b2901782d4b2e061e7930e8bc0cef
|
7
|
+
data.tar.gz: d16b91fb061442fb4ec76ed66e415cb10e3ab5776bab6b7c77e5893c88d666072c09559b35870b222151a68005a22f5332be5e57b9aad0a7ce06a014d54a38ed
|
data/.gitignore
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
sidekiq-spy
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.0.0
|
data/.travis.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
- jruby-19mode
|
5
|
+
- rbx-19mode
|
6
|
+
- 2.0.0
|
7
|
+
notifications:
|
8
|
+
email:
|
9
|
+
recipients:
|
10
|
+
- tp@tiredpixel.com
|
11
|
+
- sidekiq.spy@librelist.com
|
12
|
+
matrix:
|
13
|
+
allow_failures:
|
14
|
+
- rvm: 1.9.3
|
15
|
+
- rvm: jruby-19mode
|
16
|
+
- rvm: rbx-19mode
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 tiredpixel
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# Sidekiq Spy
|
2
|
+
|
3
|
+
[](http://badge.fury.io/rb/sidekiq-spy)
|
4
|
+
[](https://travis-ci.org/tiredpixel/sidekiq-spy)
|
5
|
+
[](https://codeclimate.com/github/tiredpixel/sidekiq-spy)
|
6
|
+
[](https://coveralls.io/r/tiredpixel/sidekiq-spy)
|
7
|
+
|
8
|
+
[Sidekiq](https://github.com/mperham/sidekiq) monitoring in the console.
|
9
|
+
A bit like Sidekiq::Web. But without the web.
|
10
|
+
|
11
|
+
So, Sidekiq is a beautiful thing. :) But if you know the sadness of wanting to
|
12
|
+
see how your workers are doing at-a-glance when SSHed into a remote box with
|
13
|
+
no web server, this one's for you. <3
|
14
|
+
|
15
|
+
This project is so hot out of the oven you might need mitts. But it's already
|
16
|
+
functional, with the main statistics from the Sidekiq::Web homepage. In time,
|
17
|
+
it would be nice to add the Workers, Queues, Retries, and Scheduled tabs, too.
|
18
|
+
|
19
|
+
More sleep lost by [tiredpixel](http://www.tiredpixel.com).
|
20
|
+
|
21
|
+
|
22
|
+
## Installation
|
23
|
+
|
24
|
+
Install using:
|
25
|
+
|
26
|
+
$ gem install sidekiq-spy
|
27
|
+
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
View the available options:
|
32
|
+
|
33
|
+
$ sidekiq-spy --help
|
34
|
+
|
35
|
+
If you're connecting to `redis://127.0.0.1:6379/0` with no namespace you can
|
36
|
+
simply:
|
37
|
+
|
38
|
+
$ sidekiq-spy
|
39
|
+
|
40
|
+
To use a connection string URL:
|
41
|
+
|
42
|
+
$ sidekiq-spy -u redis://da.example.com:237/42
|
43
|
+
|
44
|
+
Or, if you prefer your options like your Hi-Fi:
|
45
|
+
|
46
|
+
$ sidekiq-spy -h da.example.com -p 237 -d 42
|
47
|
+
|
48
|
+
Maybe you're using [Resque](https://github.com/resque/resque)? Sssh!
|
49
|
+
We won't tell anyone! ;) (Resque is awesome, too!)
|
50
|
+
|
51
|
+
$ sidekiq-spy -n resque
|
52
|
+
|
53
|
+
That's about it.
|
54
|
+
|
55
|
+
|
56
|
+
## ASCII Art (a.k.a. Screenshot)
|
57
|
+
|
58
|
+
Sidekiq Spy 0.0.1 | 01:02:58 +0100
|
59
|
+
redis: 127.0.0.1:6379/0|namespace:
|
60
|
+
redis version: 2.6.11|uptime (d): 8|connections: 3
|
61
|
+
memory: 4.84M|memory peak: 13.52M|
|
62
|
+
|
63
|
+
busy: 0|retries: 0|processed: 1304
|
64
|
+
enqueued: 0|scheduled: 0|failed: 1236
|
65
|
+
|
66
|
+
|
67
|
+
## Stay Tuned
|
68
|
+
|
69
|
+
We have a [Librelist](http://librelist.com) mailing list!
|
70
|
+
To subscribe, send an email to <sidekiq.spy@librelist.com>.
|
71
|
+
To unsubscribe, send an email to <sidekiq.spy-unsubscribe@librelist.com>.
|
72
|
+
There be [archives](http://librelist.com/browser/sidekiq.spy/).
|
73
|
+
That was easy.
|
74
|
+
|
75
|
+
|
76
|
+
## Growing Like Flowers
|
77
|
+
|
78
|
+
Dear Me, Here is a vague wishlist:
|
79
|
+
|
80
|
+
- more tests for the display parts
|
81
|
+
- Workers table on main page
|
82
|
+
- Queues page
|
83
|
+
- Retries page
|
84
|
+
- Scheduled page
|
85
|
+
- a little control to go with your monitoring, maybe...
|
86
|
+
|
87
|
+
|
88
|
+
## Contributions
|
89
|
+
|
90
|
+
Contributions are embraced with much love and affection!
|
91
|
+
Please fork the repository and wizard your magic, preferably with plenty of
|
92
|
+
fairy-dust sprinkled over the tests. ;)
|
93
|
+
Then send me a pull request. Simples!
|
94
|
+
If you'd like to discuss what you're doing or planning to do, or if you get
|
95
|
+
stuck on something, then just wave. :)
|
96
|
+
|
97
|
+
Do whatever makes you happy. We'll probably still like you. :)
|
98
|
+
|
99
|
+
Tests are written using [minitest](https://github.com/seattlerb/minitest),
|
100
|
+
which is included by default in Ruby 1.9 onwards. To run all tests:
|
101
|
+
|
102
|
+
rake test
|
103
|
+
|
104
|
+
Or, if you're of that turn of mind, use [TURN](https://github.com/TwP/turn)
|
105
|
+
(`gem install turn`):
|
106
|
+
|
107
|
+
turn test/sidekiq-spy/
|
108
|
+
|
109
|
+
|
110
|
+
## Blessing
|
111
|
+
|
112
|
+
May you find peace, and help others to do likewise.
|
113
|
+
|
114
|
+
|
115
|
+
## Licence
|
116
|
+
|
117
|
+
© [tiredpixel](http://www.tiredpixel.com) 2013.
|
118
|
+
It is free software, released under the MIT License, and may be redistributed
|
119
|
+
under the terms specified in `LICENSE`.
|
data/Rakefile
ADDED
data/bin/sidekiq-spy
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$stdout.sync = true
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
|
7
|
+
require File.expand_path('../../lib/sidekiq-spy', __FILE__)
|
8
|
+
|
9
|
+
|
10
|
+
# = Parse opts
|
11
|
+
|
12
|
+
options = {}
|
13
|
+
|
14
|
+
OptionParser.new do |opts|
|
15
|
+
opts.version = "v#{SidekiqSpy::VERSION}"
|
16
|
+
|
17
|
+
opts.banner = opts.ver
|
18
|
+
|
19
|
+
opts.separator ""
|
20
|
+
opts.separator "Usage: sidekiq-spy [OPTIONS]"
|
21
|
+
|
22
|
+
opts.on("-u", "--url URL",
|
23
|
+
"Redis connection string URL"
|
24
|
+
) { |o| options[:url] = o }
|
25
|
+
|
26
|
+
opts.on("-h", "--host HOSTNAME",
|
27
|
+
"Redis hostname (default: 127.0.0.1)"
|
28
|
+
) { |o| options[:host] = o }
|
29
|
+
|
30
|
+
opts.on("-p", "--port PORT", Integer,
|
31
|
+
"Redis port (default: 6379)"
|
32
|
+
) { |o| options[:port] = o }
|
33
|
+
|
34
|
+
opts.on("-d", "--database DATABASE", Integer,
|
35
|
+
"Redis database (default: 0)"
|
36
|
+
) { |o| options[:database] = o }
|
37
|
+
|
38
|
+
opts.on("-n", "--namespace NAMESPACE",
|
39
|
+
"Redis namespace (default: '')"
|
40
|
+
) { |o| options[:namespace] = o }
|
41
|
+
|
42
|
+
opts.on("-i", "--interval INTERVAL", Integer,
|
43
|
+
"Refresh every INTERVAL s (default: 5)"
|
44
|
+
) { |o| options[:interval] = o }
|
45
|
+
|
46
|
+
opts.separator ""
|
47
|
+
opts.separator "Examples:"
|
48
|
+
|
49
|
+
opts.separator [
|
50
|
+
"sidekiq-spy",
|
51
|
+
"sidekiq-spy -u redis://da.example.com:237/42",
|
52
|
+
"sidekiq-spy -h da.example.com -p 237 -d 42",
|
53
|
+
"sidekiq-spy -n resque -i 1",
|
54
|
+
].map { |e| " #{e}" }
|
55
|
+
|
56
|
+
opts.separator ""
|
57
|
+
|
58
|
+
opts.on_tail("--help",
|
59
|
+
"Output (this) help and exit"
|
60
|
+
) do
|
61
|
+
puts opts
|
62
|
+
exit
|
63
|
+
end
|
64
|
+
|
65
|
+
opts.on_tail("--version",
|
66
|
+
"Output version and exit"
|
67
|
+
) do
|
68
|
+
puts opts.ver
|
69
|
+
exit
|
70
|
+
end
|
71
|
+
end.parse!
|
72
|
+
|
73
|
+
|
74
|
+
# = Create app
|
75
|
+
|
76
|
+
@app = SidekiqSpy::App.new
|
77
|
+
|
78
|
+
|
79
|
+
# = Configure
|
80
|
+
|
81
|
+
@app.configure do |c|
|
82
|
+
params = [
|
83
|
+
:url,
|
84
|
+
:host,
|
85
|
+
:port,
|
86
|
+
:database,
|
87
|
+
:namespace,
|
88
|
+
:interval,
|
89
|
+
]
|
90
|
+
|
91
|
+
params.each { |p| c.send("#{p}=", options[p]) unless options[p].nil? }
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# = Run app
|
96
|
+
|
97
|
+
trap('INT') { @app.stop }
|
98
|
+
|
99
|
+
@app.start
|
data/lib/sidekiq-spy.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require File.expand_path('../sidekiq-spy/version', __FILE__)
|
2
|
+
require File.expand_path('../sidekiq-spy/config', __FILE__)
|
3
|
+
|
4
|
+
require File.expand_path('../sidekiq-spy/translatable', __FILE__)
|
5
|
+
require File.expand_path('../sidekiq-spy/app', __FILE__)
|
6
|
+
|
7
|
+
require File.expand_path('../sidekiq-spy/spy/stats', __FILE__)
|
8
|
+
|
9
|
+
require File.expand_path('../sidekiq-spy/display/screen', __FILE__)
|
10
|
+
require File.expand_path('../sidekiq-spy/display/panel', __FILE__)
|
11
|
+
require File.expand_path('../sidekiq-spy/display/subpanel', __FILE__)
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
|
3
|
+
|
4
|
+
module SidekiqSpy
|
5
|
+
class App
|
6
|
+
|
7
|
+
attr_reader :running
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@running = false
|
11
|
+
end
|
12
|
+
|
13
|
+
def config
|
14
|
+
@config ||= Config.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def configure
|
18
|
+
yield config
|
19
|
+
|
20
|
+
configure_sidekiq
|
21
|
+
end
|
22
|
+
|
23
|
+
def start
|
24
|
+
begin
|
25
|
+
@running = true
|
26
|
+
|
27
|
+
setup
|
28
|
+
|
29
|
+
while @running do
|
30
|
+
refresh
|
31
|
+
|
32
|
+
@sleep_timer = config.interval
|
33
|
+
|
34
|
+
while @running && @sleep_timer > 0
|
35
|
+
sleep 1
|
36
|
+
|
37
|
+
@sleep_timer -= 1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
ensure
|
41
|
+
cleanup
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def stop
|
46
|
+
@running = false
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def configure_sidekiq
|
52
|
+
Sidekiq.configure_client do |sidekiq_config|
|
53
|
+
sidekiq_config.logger = nil
|
54
|
+
sidekiq_config.redis = {
|
55
|
+
:url => config.url,
|
56
|
+
:namespace => config.namespace,
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def setup
|
62
|
+
@screen = Display::Screen.new
|
63
|
+
end
|
64
|
+
|
65
|
+
def refresh
|
66
|
+
@screen.refresh
|
67
|
+
end
|
68
|
+
|
69
|
+
def cleanup
|
70
|
+
@screen.close if @screen
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
|
4
|
+
module SidekiqSpy
|
5
|
+
class Config
|
6
|
+
|
7
|
+
attr_accessor :host
|
8
|
+
attr_accessor :port
|
9
|
+
attr_accessor :database
|
10
|
+
attr_accessor :namespace
|
11
|
+
attr_accessor :interval
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@host = '127.0.0.1'
|
15
|
+
@port = 6379
|
16
|
+
@database = 0
|
17
|
+
@namespace = nil
|
18
|
+
@interval = 5
|
19
|
+
end
|
20
|
+
|
21
|
+
def url=(url)
|
22
|
+
url = URI.parse(url)
|
23
|
+
|
24
|
+
@host = url.host unless url.host.empty?
|
25
|
+
@port = url.port unless url.path.empty?
|
26
|
+
@database = url.path.tr('/', '').to_i unless url.path.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
def url
|
30
|
+
"redis://#{@host}:#{@port}/#{@database}"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'curses'
|
2
|
+
|
3
|
+
|
4
|
+
module SidekiqSpy
|
5
|
+
module Display
|
6
|
+
class Panel
|
7
|
+
|
8
|
+
def initialize(height, width, top, left, structure, opts = {})
|
9
|
+
@height = height
|
10
|
+
@width = width
|
11
|
+
@top = top
|
12
|
+
@left = left
|
13
|
+
|
14
|
+
@dividers = {
|
15
|
+
:left => opts[:divider_l].to_s,
|
16
|
+
:right => opts[:divider_r].to_s,
|
17
|
+
}
|
18
|
+
|
19
|
+
@divider_length = @dividers.values.map(&:length).inject(:+)
|
20
|
+
|
21
|
+
@window = Curses::Window.new(@height, @width, @top, @left)
|
22
|
+
|
23
|
+
@subpanels = build_subpanels(structure)
|
24
|
+
end
|
25
|
+
|
26
|
+
def close
|
27
|
+
@window.close
|
28
|
+
end
|
29
|
+
|
30
|
+
def refresh
|
31
|
+
@subpanels.each(&:refresh) # build changes
|
32
|
+
|
33
|
+
@window.refresh # push changes to window
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def build_subpanels(structure)
|
39
|
+
subpanels = []
|
40
|
+
|
41
|
+
structure.each_with_index do |row, i|
|
42
|
+
next if row.nil? # skip blank rows
|
43
|
+
|
44
|
+
row_cols = row.map { |e| e[0] }.inject(:+)
|
45
|
+
|
46
|
+
col_width = (@width / row_cols) + @divider_length
|
47
|
+
|
48
|
+
col_i = 0
|
49
|
+
|
50
|
+
row.each_with_index do |(tag_cols, data_l, data_r), row_i|
|
51
|
+
first_col = row_i == 0
|
52
|
+
last_col = row_i + 1 == row.length
|
53
|
+
|
54
|
+
tag_col_width = if last_col
|
55
|
+
@width - ((row_cols - tag_cols) * col_width)
|
56
|
+
else
|
57
|
+
tag_cols * col_width
|
58
|
+
end
|
59
|
+
|
60
|
+
subpanels << Display::Subpanel.new(
|
61
|
+
@window,
|
62
|
+
1,
|
63
|
+
tag_col_width,
|
64
|
+
i,
|
65
|
+
col_i,
|
66
|
+
:data_l => data_l,
|
67
|
+
:data_r => data_r,
|
68
|
+
:divider_l => (@dividers[:left] unless first_col),
|
69
|
+
:divider_r => (@dividers[:right] unless last_col)
|
70
|
+
)
|
71
|
+
|
72
|
+
col_i += tag_col_width
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
subpanels
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'curses'
|
2
|
+
|
3
|
+
|
4
|
+
module SidekiqSpy
|
5
|
+
module Display
|
6
|
+
class Screen
|
7
|
+
|
8
|
+
include Translatable
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
Curses.init_screen
|
12
|
+
Curses.nl
|
13
|
+
Curses.noecho
|
14
|
+
Curses.curs_set(0)
|
15
|
+
|
16
|
+
@height = Curses.lines
|
17
|
+
@width = Curses.cols
|
18
|
+
|
19
|
+
@panels = {
|
20
|
+
:header => panel_header,
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def close
|
25
|
+
@panels.each { |pname, panel| panel.close }
|
26
|
+
|
27
|
+
Curses.close_screen
|
28
|
+
end
|
29
|
+
|
30
|
+
def refresh
|
31
|
+
@panels.each { |pname, panel| panel.refresh }
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def panel_header
|
37
|
+
stats = Spy::Stats.new
|
38
|
+
|
39
|
+
structure = [
|
40
|
+
[
|
41
|
+
[1, t[:program], nil],
|
42
|
+
[1, nil, -> { Time.now.strftime("%T %z") }],
|
43
|
+
],
|
44
|
+
[
|
45
|
+
[2, t[:redis][:connection], -> { stats.connection }],
|
46
|
+
[1, t[:redis][:namespace], -> { stats.namespace }],
|
47
|
+
],
|
48
|
+
[
|
49
|
+
[1, t[:redis][:version], -> { stats.redis_version }],
|
50
|
+
[1, t[:redis][:uptime], -> { stats.uptime }],
|
51
|
+
[1, t[:redis][:connections], -> { stats.connections }],
|
52
|
+
],
|
53
|
+
[
|
54
|
+
[1, t[:redis][:memory], -> { stats.memory }],
|
55
|
+
[1, t[:redis][:memory_peak], -> { stats.memory_peak }],
|
56
|
+
[1, nil, nil],
|
57
|
+
],
|
58
|
+
nil,
|
59
|
+
[
|
60
|
+
[1, t[:sidekiq][:busy], -> { stats.busy }],
|
61
|
+
[1, t[:sidekiq][:retries], -> { stats.retries }],
|
62
|
+
[1, t[:sidekiq][:processed], -> { stats.processed }],
|
63
|
+
],
|
64
|
+
[
|
65
|
+
[1, t[:sidekiq][:enqueued], -> { stats.enqueued }],
|
66
|
+
[1, t[:sidekiq][:scheduled], -> { stats.scheduled }],
|
67
|
+
[1, t[:sidekiq][:failed], -> { stats.failed }],
|
68
|
+
],
|
69
|
+
nil,
|
70
|
+
]
|
71
|
+
|
72
|
+
opts = {
|
73
|
+
:divider_l => t[:divider][:left],
|
74
|
+
:divider_r => t[:divider][:right],
|
75
|
+
}
|
76
|
+
|
77
|
+
Display::Panel.new(structure.length, @width, 0, 0, structure, opts)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module SidekiqSpy
|
2
|
+
module Display
|
3
|
+
class Subpanel
|
4
|
+
|
5
|
+
def initialize(window, height, width, top, left, opts = {})
|
6
|
+
@window = window
|
7
|
+
@height = height
|
8
|
+
@width = width
|
9
|
+
@top = top
|
10
|
+
@left = left
|
11
|
+
|
12
|
+
@data = {
|
13
|
+
:left => opts[:data_l],
|
14
|
+
:right => opts[:data_r],
|
15
|
+
}
|
16
|
+
|
17
|
+
@dividers = {
|
18
|
+
:left => opts[:divider_l].to_s,
|
19
|
+
:right => opts[:divider_r].to_s,
|
20
|
+
}
|
21
|
+
|
22
|
+
@content_width = @width - @dividers.values.map(&:length).inject(:+)
|
23
|
+
end
|
24
|
+
|
25
|
+
def refresh
|
26
|
+
new_current = content(@data[:left], @data[:right], @content_width)
|
27
|
+
|
28
|
+
unless new_current == @data[:current] # don't redraw if hasn't changed
|
29
|
+
@window.setpos(@top, @left)
|
30
|
+
@window.addstr(@dividers[:left] + new_current + @dividers[:right])
|
31
|
+
end
|
32
|
+
|
33
|
+
@data[:current] = new_current
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def content(data_l, data_r, width)
|
39
|
+
l = data_l.is_a?(Proc) ? data_l.call : data_l.to_s
|
40
|
+
r = data_r.is_a?(Proc) ? data_r.call : data_r.to_s
|
41
|
+
|
42
|
+
l + "%#{width - l.length}s" % r
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
|
3
|
+
|
4
|
+
module SidekiqSpy
|
5
|
+
module Spy
|
6
|
+
class Stats
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@stats = Sidekiq::Stats.new
|
10
|
+
@workers = Sidekiq::Workers.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def connection
|
14
|
+
redis { |c| "#{c.client.location}/#{c.client.db}" }
|
15
|
+
end
|
16
|
+
|
17
|
+
def namespace
|
18
|
+
redis { |c| c.namespace if c.respond_to?(:namespace) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def redis_version
|
22
|
+
redis { |c| c.info['redis_version'] }
|
23
|
+
end
|
24
|
+
|
25
|
+
def uptime
|
26
|
+
redis { |c| c.info['uptime_in_days'] }
|
27
|
+
end
|
28
|
+
|
29
|
+
def connections
|
30
|
+
redis { |c| c.info['connected_clients'] }
|
31
|
+
end
|
32
|
+
|
33
|
+
def memory
|
34
|
+
redis { |c| c.info['used_memory_human'] }
|
35
|
+
end
|
36
|
+
|
37
|
+
def memory_peak
|
38
|
+
redis { |c| c.info['used_memory_peak_human'] }
|
39
|
+
end
|
40
|
+
|
41
|
+
def busy
|
42
|
+
@workers.size
|
43
|
+
end
|
44
|
+
|
45
|
+
def enqueued
|
46
|
+
@stats.enqueued
|
47
|
+
end
|
48
|
+
|
49
|
+
def retries
|
50
|
+
@stats.retry_size
|
51
|
+
end
|
52
|
+
|
53
|
+
def scheduled
|
54
|
+
@stats.scheduled_size
|
55
|
+
end
|
56
|
+
|
57
|
+
def processed
|
58
|
+
@stats.processed
|
59
|
+
end
|
60
|
+
|
61
|
+
def failed
|
62
|
+
@stats.failed
|
63
|
+
end
|
64
|
+
|
65
|
+
# private
|
66
|
+
|
67
|
+
def redis
|
68
|
+
Sidekiq.redis { |c| yield c }
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module SidekiqSpy
|
2
|
+
module Translatable
|
3
|
+
|
4
|
+
def t
|
5
|
+
{
|
6
|
+
divider: {
|
7
|
+
left: "",
|
8
|
+
right: "|",
|
9
|
+
},
|
10
|
+
program: "Sidekiq Spy #{VERSION}",
|
11
|
+
redis: {
|
12
|
+
connection: "redis:",
|
13
|
+
namespace: "namespace:",
|
14
|
+
version: "redis version:",
|
15
|
+
uptime: "uptime (d):",
|
16
|
+
connections: "connections:",
|
17
|
+
memory: "memory:",
|
18
|
+
memory_peak: "memory peak:",
|
19
|
+
},
|
20
|
+
sidekiq: {
|
21
|
+
busy: "busy:",
|
22
|
+
retries: "retries:",
|
23
|
+
processed: "processed:",
|
24
|
+
enqueued: "enqueued:",
|
25
|
+
scheduled: "scheduled:",
|
26
|
+
failed: "failed:",
|
27
|
+
},
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
data/sidekiq-spy.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sidekiq-spy/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sidekiq-spy"
|
8
|
+
spec.version = SidekiqSpy::VERSION
|
9
|
+
spec.authors = ["tiredpixel"]
|
10
|
+
spec.email = ["tp@tiredpixel.com"]
|
11
|
+
spec.description = %q{Sidekiq monitoring in the console. A bit like Sidekiq::Web. But without the web.}
|
12
|
+
spec.summary = %q{Sidekiq monitoring in the console.}
|
13
|
+
spec.homepage = "https://github.com/tiredpixel/sidekiq-spy"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "sidekiq", "~> 2.15"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
|
26
|
+
spec.add_development_dependency 'coveralls'
|
27
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
{
|
2
|
+
"redis_version":"666.6.11",
|
3
|
+
"redis_git_sha1":"00000000",
|
4
|
+
"redis_git_dirty":"0",
|
5
|
+
"redis_mode":"standalone",
|
6
|
+
"os":"Darwin 12.5.0 x86_64",
|
7
|
+
"arch_bits":"64",
|
8
|
+
"multiplexing_api":"kqueue",
|
9
|
+
"gcc_version":"4.2.1",
|
10
|
+
"process_id":"339",
|
11
|
+
"run_id":"9b69467d5190215ef1ce1f8a0c78818c3cf54576",
|
12
|
+
"tcp_port":"6379",
|
13
|
+
"uptime_in_seconds":"648366",
|
14
|
+
"uptime_in_days":"7",
|
15
|
+
"hz":"10",
|
16
|
+
"lru_clock":"1852328",
|
17
|
+
"connected_clients":"8",
|
18
|
+
"client_longest_output_list":"0",
|
19
|
+
"client_biggest_input_buf":"0",
|
20
|
+
"blocked_clients":"1",
|
21
|
+
"used_memory":"5406656",
|
22
|
+
"used_memory_human":"5.16M",
|
23
|
+
"used_memory_rss":"643072",
|
24
|
+
"used_memory_peak":"5388592",
|
25
|
+
"used_memory_peak_human":"5.14M",
|
26
|
+
"used_memory_lua":"31744",
|
27
|
+
"mem_fragmentation_ratio":"0.12",
|
28
|
+
"mem_allocator":"libc",
|
29
|
+
"loading":"0",
|
30
|
+
"rdb_changes_since_last_save":"0",
|
31
|
+
"rdb_bgsave_in_progress":"0",
|
32
|
+
"rdb_last_save_time":"1381023714",
|
33
|
+
"rdb_last_bgsave_status":"ok",
|
34
|
+
"rdb_last_bgsave_time_sec":"-1",
|
35
|
+
"rdb_current_bgsave_time_sec":"-1",
|
36
|
+
"aof_enabled":"0",
|
37
|
+
"aof_rewrite_in_progress":"0",
|
38
|
+
"aof_rewrite_scheduled":"0",
|
39
|
+
"aof_last_rewrite_time_sec":"-1",
|
40
|
+
"aof_current_rewrite_time_sec":"-1",
|
41
|
+
"aof_last_bgrewrite_status":"ok",
|
42
|
+
"total_connections_received":"18",
|
43
|
+
"total_commands_processed":"110742",
|
44
|
+
"instantaneous_ops_per_sec":"5",
|
45
|
+
"rejected_connections":"0",
|
46
|
+
"expired_keys":"0",
|
47
|
+
"evicted_keys":"0",
|
48
|
+
"keyspace_hits":"21487",
|
49
|
+
"keyspace_misses":"59742",
|
50
|
+
"pubsub_channels":"0",
|
51
|
+
"pubsub_patterns":"0",
|
52
|
+
"latest_fork_usec":"0",
|
53
|
+
"role":"master",
|
54
|
+
"connected_slaves":"0",
|
55
|
+
"used_cpu_sys":"57.24",
|
56
|
+
"used_cpu_user":"47.85",
|
57
|
+
"used_cpu_sys_children":"0.00",
|
58
|
+
"used_cpu_user_children":"0.00",
|
59
|
+
"db0":"keys=49,expires=3",
|
60
|
+
"db1":"keys=3,expires=0"
|
61
|
+
}
|
data/test/helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.expand_path('../../helper', __FILE__)
|
2
|
+
|
3
|
+
require File.expand_path('../../../lib/sidekiq-spy', __FILE__)
|
4
|
+
|
5
|
+
|
6
|
+
describe SidekiqSpy::App do
|
7
|
+
|
8
|
+
before do
|
9
|
+
@app = SidekiqSpy::App.new
|
10
|
+
end
|
11
|
+
|
12
|
+
it "sets status not-running" do
|
13
|
+
@app.running.must_equal false
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#start" do
|
17
|
+
before do
|
18
|
+
@app.configure do |c|
|
19
|
+
c.interval = 10
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "sets status running within 1s" do
|
24
|
+
thread_app = Thread.new { @app.start }
|
25
|
+
|
26
|
+
sleep 1 # patience, patience; give app time to start
|
27
|
+
|
28
|
+
@app.running.must_equal true
|
29
|
+
|
30
|
+
Thread.kill(thread_app)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "stops running within 2s" do
|
34
|
+
thread_app = Thread.new { @app.start }
|
35
|
+
|
36
|
+
sleep 1 # patience, patience; give app time to start
|
37
|
+
|
38
|
+
@app.stop; t0 = Time.now
|
39
|
+
|
40
|
+
thread_app.join(3)
|
41
|
+
|
42
|
+
Thread.kill(thread_app)
|
43
|
+
|
44
|
+
assert_operator (Time.now - t0), :<=, 2
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#stop" do
|
49
|
+
before do
|
50
|
+
@app.instance_variable_set(:@running, true)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "sets status not-running" do
|
54
|
+
@app.stop
|
55
|
+
|
56
|
+
@app.running.must_equal false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require File.expand_path('../../helper', __FILE__)
|
2
|
+
|
3
|
+
require File.expand_path('../../../lib/sidekiq-spy/config', __FILE__)
|
4
|
+
require File.expand_path('../../../lib/sidekiq-spy/app', __FILE__)
|
5
|
+
|
6
|
+
|
7
|
+
describe SidekiqSpy::Config do
|
8
|
+
|
9
|
+
before do
|
10
|
+
@app = SidekiqSpy::App.new
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "default" do
|
14
|
+
before do
|
15
|
+
@config = SidekiqSpy::Config.new
|
16
|
+
end
|
17
|
+
|
18
|
+
it "sets host to 127.0.0.1" do
|
19
|
+
@config.host.must_equal '127.0.0.1'
|
20
|
+
end
|
21
|
+
|
22
|
+
it "sets port to 6379" do
|
23
|
+
@config.port.must_equal 6379
|
24
|
+
end
|
25
|
+
|
26
|
+
it "sets database to 0" do
|
27
|
+
@config.database.must_equal 0
|
28
|
+
end
|
29
|
+
|
30
|
+
it "sets namespace to nil" do
|
31
|
+
@config.namespace.must_be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
it "sets interval to 5" do
|
35
|
+
@config.interval.must_equal 5
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "configure block main" do
|
40
|
+
before do
|
41
|
+
@app.configure do |c|
|
42
|
+
c.namespace = 'resque'
|
43
|
+
c.interval = 1
|
44
|
+
end
|
45
|
+
|
46
|
+
@config = @app.config
|
47
|
+
end
|
48
|
+
|
49
|
+
it "configures namespace" do
|
50
|
+
@config.namespace.must_equal 'resque'
|
51
|
+
end
|
52
|
+
|
53
|
+
it "configures interval" do
|
54
|
+
@config.interval.must_equal 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "configure block url" do
|
59
|
+
before do
|
60
|
+
@app.configure do |c|
|
61
|
+
c.url = 'redis://da.example.com:237/42'
|
62
|
+
end
|
63
|
+
|
64
|
+
@config = @app.config
|
65
|
+
end
|
66
|
+
|
67
|
+
it "configures host" do
|
68
|
+
@config.host.must_equal 'da.example.com'
|
69
|
+
end
|
70
|
+
|
71
|
+
it "configures port" do
|
72
|
+
@config.port.must_equal 237
|
73
|
+
end
|
74
|
+
|
75
|
+
it "configures database" do
|
76
|
+
@config.database.must_equal 42
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "configure block url-brief" do
|
81
|
+
before do
|
82
|
+
@app.configure do |c|
|
83
|
+
c.url = 'redis://da.example.com'
|
84
|
+
end
|
85
|
+
|
86
|
+
@config = @app.config
|
87
|
+
end
|
88
|
+
|
89
|
+
it "configures host" do
|
90
|
+
@config.host.must_equal 'da.example.com'
|
91
|
+
end
|
92
|
+
|
93
|
+
it "configures port" do
|
94
|
+
@config.port.must_equal 6379
|
95
|
+
end
|
96
|
+
|
97
|
+
it "configures database" do
|
98
|
+
@config.database.must_equal 0
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "configure block non-url" do
|
103
|
+
before do
|
104
|
+
@app.configure do |c|
|
105
|
+
c.host = 'da.example.com'
|
106
|
+
c.port = 237
|
107
|
+
c.database = 42
|
108
|
+
end
|
109
|
+
|
110
|
+
@config = @app.config
|
111
|
+
end
|
112
|
+
|
113
|
+
it "configures host" do
|
114
|
+
@config.host.must_equal 'da.example.com'
|
115
|
+
end
|
116
|
+
|
117
|
+
it "configures port" do
|
118
|
+
@config.port.must_equal 237
|
119
|
+
end
|
120
|
+
|
121
|
+
it "configures database" do
|
122
|
+
@config.database.must_equal 42
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "#url" do
|
127
|
+
before do
|
128
|
+
@config = SidekiqSpy::Config.new
|
129
|
+
|
130
|
+
@config.host = 'da.example.com'
|
131
|
+
@config.port = 237
|
132
|
+
@config.database = 42
|
133
|
+
end
|
134
|
+
|
135
|
+
it "returns connection string URL" do
|
136
|
+
@config.url.must_equal 'redis://da.example.com:237/42'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'redis/namespace'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require File.expand_path('../../../helper', __FILE__)
|
5
|
+
|
6
|
+
require File.expand_path('../../../../lib/sidekiq-spy/spy/stats', __FILE__)
|
7
|
+
|
8
|
+
|
9
|
+
describe SidekiqSpy::Spy::Stats do
|
10
|
+
|
11
|
+
before do
|
12
|
+
@redis = Redis::Namespace.new('resque', :redis => Redis.new)
|
13
|
+
|
14
|
+
Sidekiq.configure_client do |config|
|
15
|
+
config.redis = ConnectionPool.new(:size => 1, &proc { @redis })
|
16
|
+
end
|
17
|
+
|
18
|
+
@fixtures = {
|
19
|
+
:redis_info => JSON.parse(File.read(
|
20
|
+
File.expand_path('../../../fixtures/redis_info.json', __FILE__)
|
21
|
+
)),
|
22
|
+
}
|
23
|
+
|
24
|
+
@sidekiq_stats = Minitest::Mock.new
|
25
|
+
@sidekiq_stats.expect(:enqueued, 16776977673)
|
26
|
+
@sidekiq_stats.expect(:retry_size, 924984826746)
|
27
|
+
@sidekiq_stats.expect(:scheduled_size, 317321542620)
|
28
|
+
@sidekiq_stats.expect(:processed, 923531545885)
|
29
|
+
@sidekiq_stats.expect(:failed, 779187529140)
|
30
|
+
|
31
|
+
@sidekiq_workers = Minitest::Mock.new
|
32
|
+
@sidekiq_workers.expect(:size, 162165179294)
|
33
|
+
|
34
|
+
Sidekiq::Stats.stub(:new, @sidekiq_stats) do
|
35
|
+
Sidekiq::Workers.stub(:new, @sidekiq_workers) do
|
36
|
+
@stats = SidekiqSpy::Spy::Stats.new
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#connection" do
|
42
|
+
it "returns stat connection" do
|
43
|
+
@redis.client.stub(:location, 'da.example.com:237') do
|
44
|
+
@redis.client.stub(:db, 42) do
|
45
|
+
@stats.connection.must_equal 'da.example.com:237/42'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#namespace" do
|
52
|
+
it "returns stat namespace" do
|
53
|
+
@stats.namespace.must_equal 'resque'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#uptime" do
|
58
|
+
it "returns stat uptime" do
|
59
|
+
@redis.stub(:info, @fixtures[:redis_info]) do
|
60
|
+
@stats.uptime.must_equal '7'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#connections" do
|
66
|
+
it "returns stat connections" do
|
67
|
+
@redis.stub(:info, @fixtures[:redis_info]) do
|
68
|
+
@stats.connections.must_equal '8'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#memory" do
|
74
|
+
it "returns stat memory" do
|
75
|
+
@redis.stub(:info, @fixtures[:redis_info]) do
|
76
|
+
@stats.memory.must_equal '5.16M'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#memory_peak" do
|
82
|
+
it "returns stat memory_peak" do
|
83
|
+
@redis.stub(:info, @fixtures[:redis_info]) do
|
84
|
+
@stats.memory_peak.must_equal '5.14M'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "#busy" do
|
90
|
+
it "returns stat busy" do
|
91
|
+
@stats.busy.must_equal 162165179294
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#enqueued" do
|
96
|
+
it "returns stat enqueued" do
|
97
|
+
@stats.enqueued.must_equal 16776977673
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "#retries" do
|
102
|
+
it "returns stat retries" do
|
103
|
+
@stats.retries.must_equal 924984826746
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#scheduled" do
|
108
|
+
it "returns stat scheduled" do
|
109
|
+
@stats.scheduled.must_equal 317321542620
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "#processed" do
|
114
|
+
it "returns stat processed" do
|
115
|
+
@stats.processed.must_equal 923531545885
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "#failed" do
|
120
|
+
it "returns stat failed" do
|
121
|
+
@stats.failed.must_equal 779187529140
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path('../../helper', __FILE__)
|
2
|
+
|
3
|
+
require File.expand_path('../../../lib/sidekiq-spy/version', __FILE__)
|
4
|
+
|
5
|
+
|
6
|
+
describe "SidekiqSpy::VERSION" do
|
7
|
+
|
8
|
+
it "uses major.minor.patch" do
|
9
|
+
SidekiqSpy::VERSION.must_match /\A\d+\.\d+\.\d+\z/
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sidekiq-spy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- tiredpixel
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: sidekiq
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.15'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: coveralls
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Sidekiq monitoring in the console. A bit like Sidekiq::Web. But without
|
70
|
+
the web.
|
71
|
+
email:
|
72
|
+
- tp@tiredpixel.com
|
73
|
+
executables:
|
74
|
+
- sidekiq-spy
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- .gitignore
|
79
|
+
- .ruby-gemset
|
80
|
+
- .ruby-version
|
81
|
+
- .travis.yml
|
82
|
+
- Gemfile
|
83
|
+
- LICENSE.txt
|
84
|
+
- README.md
|
85
|
+
- Rakefile
|
86
|
+
- bin/sidekiq-spy
|
87
|
+
- lib/sidekiq-spy.rb
|
88
|
+
- lib/sidekiq-spy/app.rb
|
89
|
+
- lib/sidekiq-spy/config.rb
|
90
|
+
- lib/sidekiq-spy/display/panel.rb
|
91
|
+
- lib/sidekiq-spy/display/screen.rb
|
92
|
+
- lib/sidekiq-spy/display/subpanel.rb
|
93
|
+
- lib/sidekiq-spy/spy/stats.rb
|
94
|
+
- lib/sidekiq-spy/translatable.rb
|
95
|
+
- lib/sidekiq-spy/version.rb
|
96
|
+
- sidekiq-spy.gemspec
|
97
|
+
- test/fixtures/redis_info.json
|
98
|
+
- test/helper.rb
|
99
|
+
- test/sidekiq-spy/app_test.rb
|
100
|
+
- test/sidekiq-spy/config_test.rb
|
101
|
+
- test/sidekiq-spy/spy/stats_test.rb
|
102
|
+
- test/sidekiq-spy/version_test.rb
|
103
|
+
homepage: https://github.com/tiredpixel/sidekiq-spy
|
104
|
+
licenses:
|
105
|
+
- MIT
|
106
|
+
metadata: {}
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 2.1.9
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: Sidekiq monitoring in the console.
|
127
|
+
test_files:
|
128
|
+
- test/fixtures/redis_info.json
|
129
|
+
- test/helper.rb
|
130
|
+
- test/sidekiq-spy/app_test.rb
|
131
|
+
- test/sidekiq-spy/config_test.rb
|
132
|
+
- test/sidekiq-spy/spy/stats_test.rb
|
133
|
+
- test/sidekiq-spy/version_test.rb
|