sidekiq-worker_stats 0.0.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dc301892db995ec508d5f9300d46fedece1bad94
4
+ data.tar.gz: 689357440d58ff1d72a62f3dd59670dfec7f2063
5
+ SHA512:
6
+ metadata.gz: 64b8a35dfb4a99dfd7613a5dca0979875b7bb9731e01df922d648af8f6ad739add9c86f73b1f46db11e967f8adda2c8481dde0f1638d9db790daee9b4d17d514
7
+ data.tar.gz: b7c1f6ae4c030359714f881e718080a315367fa5096aa24b5947e89f1bce609b0a9dedf1d66852e9d1cb4de38d9daa24105eda3e49c304996657314b28a5399b
data/.gitignore ADDED
@@ -0,0 +1,85 @@
1
+
2
+ # Created by https://www.gitignore.io/api/linux,vim,ruby
3
+
4
+ ### Linux ###
5
+ *~
6
+
7
+ # temporary files which can be created if a process still has a handle open of a deleted file
8
+ .fuse_hidden*
9
+
10
+ # KDE directory preferences
11
+ .directory
12
+
13
+ # Linux trash folder which might appear on any partition or disk
14
+ .Trash-*
15
+
16
+ # .nfs files are created when an open file is removed but is still being accessed
17
+ .nfs*
18
+
19
+
20
+ ### Vim ###
21
+ # swap
22
+ [._]*.s[a-w][a-z]
23
+ [._]s[a-w][a-z]
24
+ # session
25
+ Session.vim
26
+ # temporary
27
+ .netrwhist
28
+ # auto-generated tag files
29
+ tags
30
+
31
+
32
+ ### Ruby ###
33
+ *.gem
34
+ *.rbc
35
+ /.config
36
+ /coverage/
37
+ /InstalledFiles
38
+ /pkg/
39
+ /spec/reports/
40
+ /spec/examples.txt
41
+ /test/tmp/
42
+ /test/version_tmp/
43
+ /tmp/
44
+
45
+ # Used by dotenv library to load environment variables.
46
+ # .env
47
+
48
+ ## Specific to RubyMotion:
49
+ .dat*
50
+ .repl_history
51
+ build/
52
+ *.bridgesupport
53
+ build-iPhoneOS/
54
+ build-iPhoneSimulator/
55
+
56
+ ## Specific to RubyMotion (use of CocoaPods):
57
+ #
58
+ # We recommend against adding the Pods directory to your .gitignore. However
59
+ # you should judge for yourself, the pros and cons are mentioned at:
60
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
61
+ #
62
+ # vendor/Pods/
63
+
64
+ ## Documentation cache and generated files:
65
+ /.yardoc/
66
+ /_yardoc/
67
+ /doc/
68
+ /rdoc/
69
+
70
+ ## Environment normalization:
71
+ /.bundle/
72
+ /vendor/bundle
73
+ /lib/bundler/man/
74
+
75
+ # for a library or gem, you might want to ignore these files since the code is
76
+ # intended to run in multiple environments; otherwise, check them in:
77
+ Gemfile.lock
78
+ # .ruby-version
79
+ # .ruby-gemset
80
+
81
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
82
+ .rvmrc
83
+
84
+ dump.rdb
85
+ config.ru
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.1
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # sidekiq-worker\_stats
2
+
3
+ Statistics for sidekiq workers.
@@ -0,0 +1 @@
1
+ require 'sidekiq/worker_stats'
@@ -0,0 +1,30 @@
1
+ require 'sidekiq'
2
+
3
+ require 'sidekiq/worker_stats/configuration'
4
+ require 'sidekiq/worker_stats/middleware'
5
+ require 'sidekiq/worker_stats/web' if defined?(Sidekiq::Web)
6
+
7
+ module Sidekiq
8
+ module WorkerStats
9
+ REDIS_HASH = 'sidekiq:worker_stats'.freeze
10
+
11
+ class << self
12
+ attr_writer :configuration
13
+
14
+ def configuration
15
+ @configuration ||= Configuration.new
16
+ end
17
+
18
+ def configure
19
+ yield(configuration)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ Sidekiq.configure_server do |config|
26
+ config.server_middleware do |chain|
27
+ chain.add Sidekiq::WorkerStats::Middleware
28
+ end
29
+ end
30
+
@@ -0,0 +1,13 @@
1
+ module Sidekiq
2
+ module WorkerStats
3
+ class Configuration
4
+ attr_accessor :log_file
5
+ attr_accessor :time
6
+
7
+ def initialize
8
+ @log_file = 'log/sidekiq.log'
9
+ @time = 5
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,55 @@
1
+ require 'json'
2
+
3
+ module Sidekiq
4
+ module WorkerStats
5
+ class Middleware
6
+ def call(worker, msg, queue)
7
+ worker_stats = {}
8
+ worker_stats[:start] = Time.now.to_i
9
+ worker_stats[:status] = 'started'
10
+
11
+ worker_stats[:pid] = Process.pid
12
+ worker_stats[:jid] = worker.jid
13
+
14
+ worker_stats[:page_size] = `getconf PAGESIZE`.to_i
15
+ worker_stats[:mem] = {}
16
+ worker_stats[:mem][Time.now.to_i] = `awk '{ print $2 }' /proc/#{worker_stats[:pid]}/statm`.strip.to_i * worker_stats[:page_size]
17
+
18
+ thr = Thread.new do
19
+ while true do
20
+ sleep Sidekiq::WorkerStats.configuration.time
21
+ worker_stats[:mem][Time.now.to_i] = `awk '{ print $2 }' /proc/#{worker_stats[:pid]}/statm`.strip.to_i * worker_stats[:page_size]
22
+ end
23
+ end
24
+
25
+ yield
26
+
27
+ worker_stats[:status] = 'completed'
28
+ rescue => e
29
+ worker_stats[:status] = 'failed'
30
+
31
+ raise e
32
+ ensure
33
+ worker_stats[:stop] = Time.now.to_i
34
+ worker_stats[:runtime] = worker_stats[:stop] - worker_stats[:start]
35
+
36
+ worker_stats[:queue] = queue
37
+ worker_stats[:class] = worker.class.to_s
38
+
39
+ thr.exit if thr != nil
40
+
41
+ worker_key = "#{worker_stats[:class]}:#{worker_stats[:start]}:#{worker_stats[:jid]}"
42
+
43
+ save_worker_stats worker_key, worker_stats
44
+ end
45
+
46
+ private
47
+
48
+ def save_worker_stats(key, worker_stats)
49
+ Sidekiq.redis do |redis|
50
+ redis.hset REDIS_HASH, key, JSON.generate(worker_stats)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ module Sidekiq
2
+ module WorkerStats
3
+ VERSION = '0.0.2'.freeze
4
+ end
5
+ end
@@ -0,0 +1,31 @@
1
+ <div class="worker_stats">
2
+ <h2>Worker Stats</h2>
3
+
4
+ <div class="worker_stats__container">
5
+ <div class="worker_stats__table">
6
+ <table class="table table-hover table-bordered table-striped table-white live-reload">
7
+ <thead>
8
+ <th>Worker</th>
9
+ <th>Started at</th>
10
+ <th>Finished at</th>
11
+ <th>Runtime</th>
12
+ <th>Avg. Memory</th>
13
+ <th>Peak Memory</th>
14
+ </thead>
15
+
16
+ <tbody>
17
+ <% @workers.each do |key, worker| %>
18
+ <tr>
19
+ <td><a href="<%= root_path %>worker_stats/<%= key.to_s %>"><%= worker["class"].to_s %></a></td>
20
+ <td><%= Time.at(worker["start"]).strftime "%Y-%m-%d %H:%M:%S" %></td>
21
+ <td><%= Time.at(worker["stop"]).strftime "%Y-%m-%d %H:%M:%S" %></td>
22
+ <td><%= "#{worker["runtime"]} s" %></td>
23
+ <td><%= "#{(worker["mem"].values.inject(:+) / worker["mem"].count) / 1024 / 1024} Mb" %></td>
24
+ <td><%= "#{(worker["mem"].values.max / 1024 / 1024)} Mb" %></td>
25
+ </tr>
26
+ <% end %>
27
+ </tbody>
28
+ </table>
29
+ </div>
30
+ </div>
31
+ </div>
@@ -0,0 +1,69 @@
1
+ <div class="worker_stats">
2
+ <h2>Worker Stats for <%= @key.to_s %> </h2>
3
+
4
+ <div class="worker_stats__container">
5
+ <div class="worker_stats__info">
6
+ <h4>Info</h4>
7
+ <div class="worker_stats__info_table">
8
+ <table class="table table-hover table-bordered table-striped table-white">
9
+ <thead>
10
+ <th>Field</th>
11
+ <th>Value</th>
12
+ </thead>
13
+
14
+ <tbody>
15
+ <tr>
16
+ <td>Class</td>
17
+ <td><%= @worker["class"] %></td>
18
+ </tr>
19
+ <tr>
20
+ <td>Queue</td>
21
+ <td><%= @worker["queue"] %></td>
22
+ </tr>
23
+ <tr>
24
+ <td>Status</td>
25
+ <td><%= @worker["status"] %></td>
26
+ </tr>
27
+ <tr>
28
+ <td>Job ID</td>
29
+ <td><%= @worker["jid"] %></td>
30
+ </tr>
31
+ <tr>
32
+ <td>Start</td>
33
+ <td><%= Time.at(@worker["start"]).strftime "%Y-%m-%d %H:%M:%S" %></td>
34
+ </tr>
35
+ <tr>
36
+ <td>Stop</td>
37
+ <td><%= Time.at(@worker["stop"]).strftime "%Y-%m-%d %H:%M:%S" %></td>
38
+ </tr>
39
+ <tr>
40
+ <td>Runtime</td>
41
+ <td><%= @worker["runtime"] %> seconds</td>
42
+ </tr>
43
+ </tbody>
44
+ </table>
45
+ </div>
46
+ </div>
47
+
48
+ <div class="worker_stats__memory">
49
+ <h4>Memory</h4>
50
+ <div class="worker_stats__memory_table">
51
+ <table class="table table-hover table-bordered table-striped table-white">
52
+ <thead>
53
+ <th>Time (after start)</th>
54
+ <th>Memory</th>
55
+ </thead>
56
+
57
+ <tbody>
58
+ <% @worker["mem"].each do |time, mem| %>
59
+ <tr>
60
+ <td><%= (time.to_i - @worker["start"]).to_s %> seconds</td>
61
+ <td><%= "#{mem / 1024 / 1024} Mb" %></td>
62
+ </tr>
63
+ <% end %>
64
+ </tbody>
65
+ </table>
66
+ </div>
67
+ </div>
68
+ </div>
69
+ </div>
@@ -0,0 +1,38 @@
1
+ require 'json'
2
+
3
+ require 'sidekiq/web' unless defined?(Sidekiq::Web)
4
+
5
+ module Sidekiq
6
+ module WorkerStats
7
+ module Web
8
+ def self.registered(app)
9
+ view_path = File.join(File.expand_path('..', __FILE__), 'views')
10
+
11
+ app.get '/worker_stats' do
12
+ @workers = {}
13
+ Sidekiq.redis do |redis|
14
+ keys = redis.hkeys REDIS_HASH
15
+ keys.each do |key|
16
+ @workers[key] = JSON.parse(redis.hget(REDIS_HASH, key))
17
+ end
18
+ end
19
+
20
+ render(:erb, File.read(File.join(view_path, 'worker_stats.erb')))
21
+ end
22
+
23
+ app.get '/worker_stats/:key' do
24
+ @key = params[:key]
25
+ @worker = {}
26
+ Sidekiq.redis do |redis|
27
+ @worker = JSON.parse(redis.hget(REDIS_HASH, @key))
28
+ end
29
+
30
+ render(:erb, File.read(File.join(view_path, 'worker_stats_single.erb')))
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ Sidekiq::Web.register Sidekiq::WorkerStats::Web
38
+ Sidekiq::Web.tabs['Worker Stats'] = 'worker_stats'
@@ -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/worker_stats/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'sidekiq-worker_stats'
8
+ s.version = Sidekiq::WorkerStats::VERSION
9
+ s.license = 'MIT'
10
+ s.summary = 'System statistics for your sidekiq workers'
11
+ s.description = 'Save and see on the sidekiq dashboard your workers statistics'
12
+
13
+ s.authors = ['Alexandre Jesus']
14
+ s.email = ['adbjesus@gmail.com']
15
+ s.homepage = 'https://github.com/whitesmith/sidekiq-worker_stats'
16
+
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.require_paths = ['lib']
21
+
22
+ s.add_dependency 'sidekiq', '~> 4.1', '>= 4.1.4', '< 5'
23
+ s.add_dependency 'redis', '~> 3.3', '>= 3.3.0'
24
+
25
+ s.add_development_dependency 'minitest', '~> 5.0'
26
+ s.add_development_dependency 'rack-test', '~> 0.6'
27
+ end
@@ -0,0 +1,60 @@
1
+ require 'minitest/autorun'
2
+
3
+ require 'rack/test'
4
+
5
+ require 'sidekiq'
6
+ require 'sidekiq/testing'
7
+ require 'sidekiq/worker_stats'
8
+
9
+
10
+ class WorkerHelper
11
+ include Sidekiq::Worker
12
+
13
+ def perform
14
+ # Let's use some memory
15
+ a = []
16
+ for i in 1..10000000
17
+ a << i.to_s * 10
18
+ end
19
+ end
20
+ end
21
+
22
+ class ErrorWorkerHelper
23
+ include Sidekiq::Worker
24
+
25
+ def perform
26
+ raise StandardError.new("Error")
27
+ end
28
+ end
29
+
30
+ class TestMiddleware < Minitest::Test
31
+ include Rack::Test::Methods
32
+
33
+ def app
34
+ Sidekiq::Web
35
+ end
36
+
37
+ def setup
38
+ Sidekiq::Testing.server_middleware do |chain|
39
+ chain.add Sidekiq::WorkerStats::Middleware
40
+ end
41
+ end
42
+
43
+ def test_that_middleware_reports_start
44
+ Sidekiq::Testing.inline! do
45
+ WorkerHelper.perform_async
46
+ end
47
+ end
48
+
49
+ def test_that_middleware_reports_end
50
+ skip 'todo'
51
+ end
52
+
53
+ def test_that_middleware_raises_error
54
+ Sidekiq::Testing.inline! do
55
+ assert_raises StandardError do
56
+ ErrorWorkerHelper.perform_async
57
+ end
58
+ end
59
+ end
60
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sidekiq-worker_stats
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Alexandre Jesus
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-11-07 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: '4.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 4.1.4
23
+ - - "<"
24
+ - !ruby/object:Gem::Version
25
+ version: '5'
26
+ type: :runtime
27
+ prerelease: false
28
+ version_requirements: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '4.1'
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: 4.1.4
36
+ - - "<"
37
+ - !ruby/object:Gem::Version
38
+ version: '5'
39
+ - !ruby/object:Gem::Dependency
40
+ name: redis
41
+ requirement: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - "~>"
44
+ - !ruby/object:Gem::Version
45
+ version: '3.3'
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: 3.3.0
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '3.3'
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 3.3.0
59
+ - !ruby/object:Gem::Dependency
60
+ name: minitest
61
+ requirement: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - "~>"
64
+ - !ruby/object:Gem::Version
65
+ version: '5.0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - "~>"
71
+ - !ruby/object:Gem::Version
72
+ version: '5.0'
73
+ - !ruby/object:Gem::Dependency
74
+ name: rack-test
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '0.6'
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: '0.6'
87
+ description: Save and see on the sidekiq dashboard your workers statistics
88
+ email:
89
+ - adbjesus@gmail.com
90
+ executables: []
91
+ extensions: []
92
+ extra_rdoc_files: []
93
+ files:
94
+ - ".gitignore"
95
+ - ".ruby-version"
96
+ - Gemfile
97
+ - README.md
98
+ - lib/sidekiq-worker_stats.rb
99
+ - lib/sidekiq/worker_stats.rb
100
+ - lib/sidekiq/worker_stats/configuration.rb
101
+ - lib/sidekiq/worker_stats/middleware.rb
102
+ - lib/sidekiq/worker_stats/version.rb
103
+ - lib/sidekiq/worker_stats/views/worker_stats.erb
104
+ - lib/sidekiq/worker_stats/views/worker_stats_single.erb
105
+ - lib/sidekiq/worker_stats/web.rb
106
+ - sidekiq-worker_stats.gemspec
107
+ - test/worker_stats/test_middleware.rb
108
+ homepage: https://github.com/whitesmith/sidekiq-worker_stats
109
+ licenses:
110
+ - MIT
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 2.5.1
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: System statistics for your sidekiq workers
132
+ test_files:
133
+ - test/worker_stats/test_middleware.rb