sidekiq-job-stats 0.1.4 → 0.1.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: afde023b391c1dfda3aca053cb913865565e585cce1c8ae54eba4b425ef22af9
4
- data.tar.gz: 50e53c32fc5c466b51f052422410a42f26aa31f85289460acf092954db52543d
3
+ metadata.gz: f971c77fc2f53fd5b4264823f52f3acafee05584e9e9cf7f43b5c649e471f782
4
+ data.tar.gz: a6980a4641f6f69dec11b8ef1a68ef6fb1ccd4de18b99f19252201fc9246ef80
5
5
  SHA512:
6
- metadata.gz: b394dfc1c643313f5c10fbcba0c1c1927f5fe4d0943f5f9a4a3c4fed23050620a0a5885dd35fce7849ed8cb340d8fe2b2c13c6dfc98679050b70da04af4c3122
7
- data.tar.gz: 6aa3b0f88a8173a953bf31e52de248e64d2f4017898f0e33d89ff1e83b90238480620f096b84eddadbe0143f260312ad990c430abd5e30d96c07aa6cfda6998b
6
+ metadata.gz: d1e422ea264542dc53e457432f3d5ba37fabbaa27d14f22e128b59b8a2c062bf23561948dcd2a252db222e69d54d95330c1ab37a313d83cf93ad3ddc72843732
7
+ data.tar.gz: 3432cb1e96008daeb1353db8aad4c99e13a850a993b124b3ec3e82130cac11754ae2c426984359f563270930132eff4e9baaf79cf376fe935a94ae82bce3107f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sidekiq-job-stats (0.1.4)
4
+ sidekiq-job-stats (0.1.6)
5
5
  get_process_mem
6
6
  sidekiq (>= 6)
7
7
 
@@ -2,7 +2,15 @@ module SidekiqJobStats
2
2
  module Helpers
3
3
  module Stats
4
4
  def stat_header(stat_name)
5
- "<th class='header'>" + stat_name.to_s.gsub(/_/,' ').capitalize + "</th>"
5
+ label = stat_name.to_s.gsub(/_/, " ").capitalize
6
+ job_stats_sort_th(label, stat_name.to_s)
7
+ end
8
+
9
+ def job_stats_sort_th(label, key)
10
+ dir = (@sort == key && @direction == "asc") ? "desc" : "asc"
11
+ css = @sort == key ? "sort-#{@direction}" : ""
12
+ url = "#{root_path}job_stats?sort=#{key}&direction=#{dir}"
13
+ "<th class='#{css}'><a href='#{url}'>#{label}</a></th>"
6
14
  end
7
15
 
8
16
  def display_stat(stat, stat_name, format)
@@ -21,6 +29,16 @@ module SidekiqJobStats
21
29
  def mb_display(num)
22
30
  num.blank? ? "" : "#{num}MB"
23
31
  end
32
+
33
+ # Sidekiq 6/7 stores enqueued_at as seconds (~1.7e9).
34
+ # Sidekiq 8+ stores it as milliseconds (~1.7e12).
35
+ def format_enqueued_at(value)
36
+ return "" unless value
37
+ ts = value.to_f
38
+ return value if ts.zero?
39
+ ts /= 1000.0 if ts > 1_000_000_000_000
40
+ Time.at(ts)
41
+ end
24
42
  end
25
43
  end
26
44
  end
@@ -20,6 +20,12 @@ module SidekiqJobStats
20
20
  end
21
21
  end
22
22
 
23
+ def all_job_histories
24
+ Sidekiq.redis do |conn|
25
+ conn.lrange(job_history_key, 0, -1).map { |h| JSON.parse(h) }
26
+ end
27
+ end
28
+
23
29
  def histories_recorded
24
30
  Sidekiq.redis do |conn|
25
31
  conn.llen(job_history_key)
@@ -14,7 +14,7 @@ module SidekiqJobStats
14
14
  :longest_job_day, :longest_job_month, to: :duration
15
15
  delegate :job_memory_usage_avg_day, :job_memory_usage_avg_month, :peak_memory_usage_day,
16
16
  :peak_memory_usage_month, to: :memory_usage
17
- delegate :job_histories, :histories_recorded, to: :history
17
+ delegate :job_histories, :all_job_histories, :histories_recorded, to: :history
18
18
  delegate :name, to: :job_class
19
19
 
20
20
  def self.find_all
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SidekiqJobStats
4
- VERSION = "0.1.4"
4
+ VERSION = "0.1.6"
5
5
  end
@@ -6,30 +6,73 @@ module SidekiqJobStats
6
6
  module WebExtension
7
7
  ROOT = File.expand_path('../web', __dir__)
8
8
 
9
+ STAT_SORT_KEYS = %w[
10
+ name jobs_enqueued jobs_performed_day jobs_performed_month
11
+ job_rolling_avg_day job_rolling_avg_month longest_job_day longest_job_month
12
+ job_memory_usage_avg_day job_memory_usage_avg_month
13
+ peak_memory_usage_day peak_memory_usage_month
14
+ ].freeze
15
+
9
16
  def self.registered(app)
10
17
  app.helpers Helpers::Stats
11
18
 
12
19
  app.get '/job_stats' do
13
- @jobs = SidekiqJobStats::Statistic.find_all.sort
20
+ sort_param = respond_to?(:url_params) ? url_params("sort") : params[:sort]
21
+ dir_param = respond_to?(:url_params) ? url_params("direction") : params[:direction]
22
+ @sort = WebExtension::STAT_SORT_KEYS.include?(sort_param.to_s) ? sort_param.to_s : "name"
23
+ @direction = %w[asc desc].include?(dir_param) ? dir_param : "asc"
24
+
25
+ @jobs = SidekiqJobStats::Statistic.find_all
26
+ @jobs.sort! do |a, b|
27
+ av = @sort == "name" ? a.name.to_s : a.send(@sort.to_sym)
28
+ bv = @sort == "name" ? b.name.to_s : b.send(@sort.to_sym)
29
+ result = begin
30
+ Float(av.to_s) <=> Float(bv.to_s)
31
+ rescue ArgumentError, TypeError
32
+ av.to_s <=> bv.to_s
33
+ end
34
+ @direction == "desc" ? -(result || 0) : (result || 0)
35
+ end
14
36
 
15
37
  render(:erb, File.read("#{ROOT}/views/job_stats.erb"))
16
38
  end
17
39
 
18
40
  app.get '/job_stats/job_history/:job_class' do
19
- @job_class = SidekiqJobStats::Statistic.find_all.find { |j| j.job_class.to_s == params[:job_class] }
41
+ klass = route_params(:job_class) || params[:job_class]
42
+ @job_class = SidekiqJobStats::Statistic.find_all.find { |j| j.job_class.to_s == klass }
20
43
 
21
44
  @start = 0
22
- @start = params[:start].to_i if params[:start]
45
+ start_param = respond_to?(:url_params) ? url_params("start") : params[:start]
46
+ @start = start_param.to_i if start_param && !start_param.empty?
23
47
  @limit = 100
24
- @limit = params[:limit].to_i if params[:limit]
48
+ limit_param = respond_to?(:url_params) ? url_params("limit") : params[:limit]
49
+ @limit = limit_param.to_i if limit_param && !limit_param.empty?
50
+
51
+ sort_param = respond_to?(:url_params) ? url_params("sort") : params[:sort]
52
+ dir_param = respond_to?(:url_params) ? url_params("direction") : params[:direction]
53
+ @sort = sort_param.to_s
54
+ @direction = %w[asc desc].include?(dir_param) ? dir_param : "asc"
25
55
 
26
- @histories = @job_class.job_histories(@start, @limit)
27
56
  @size = @job_class.histories_recorded
28
57
 
58
+ if @sort.empty?
59
+ @histories = @job_class.job_histories(@start, @limit)
60
+ else
61
+ all = @job_class.all_job_histories
62
+ all.sort! do |a, b|
63
+ av, bv = a[@sort], b[@sort]
64
+ result = begin
65
+ Float(av.to_s) <=> Float(bv.to_s)
66
+ rescue ArgumentError
67
+ av.to_s <=> bv.to_s
68
+ end
69
+ @direction == "desc" ? -(result || 0) : (result || 0)
70
+ end
71
+ @histories = all[@start, @limit] || []
72
+ end
73
+
29
74
  render(:erb, File.read("#{ROOT}/views/job_histories.erb"))
30
75
  end
31
-
32
- app.settings.locales << File.expand_path('locales', ROOT)
33
76
  end
34
77
  end
35
78
  end
@@ -19,5 +19,22 @@ module Sidekiq
19
19
  end
20
20
  end
21
21
 
22
- Sidekiq::Web.register(SidekiqJobStats::WebExtension)
23
- Sidekiq::Web.tabs['Job stats'] = 'job_stats'
22
+ if Sidekiq::MAJOR >= 8
23
+ Sidekiq::Web.configure do |config|
24
+ config.register_extension(
25
+ SidekiqJobStats::WebExtension,
26
+ name: "job_stats",
27
+ tab: ["Job stats"],
28
+ index: "job_stats",
29
+ root_dir: File.expand_path("../web", __FILE__),
30
+ asset_paths: ["css"]
31
+ )
32
+ end
33
+ else
34
+ Sidekiq::Web.register(SidekiqJobStats::WebExtension)
35
+ Sidekiq::Web.tabs['Job stats'] = 'job_stats'
36
+ end
37
+
38
+
39
+
40
+
@@ -0,0 +1,39 @@
1
+ .sortable-table .table_container {
2
+ max-height: 500px;
3
+ overflow: auto;
4
+ }
5
+
6
+ .sortable-table th {
7
+ position: sticky;
8
+ top: -1px;
9
+ background-color: var(--color-elevated);
10
+ }
11
+
12
+ .sortable-table th a {
13
+ display: block;
14
+ color: inherit;
15
+ text-decoration: none;
16
+ padding-right: 1.4em;
17
+ position: relative;
18
+ }
19
+
20
+ .sortable-table th a:hover {
21
+ text-decoration: underline;
22
+ }
23
+
24
+ .sortable-table th a::after {
25
+ content: "⇅";
26
+ position: absolute;
27
+ right: 0;
28
+ opacity: 0.25;
29
+ font-size: 0.8em;
30
+ font-weight: normal;
31
+ }
32
+
33
+ .sortable-table th.sort-asc,
34
+ .sortable-table th.sort-desc {
35
+ background-color: var(--color-selected);
36
+ }
37
+
38
+ .sortable-table th.sort-asc a::after { content: "▲"; opacity: 1; color: var(--color-primary); }
39
+ .sortable-table th.sort-desc a::after { content: "▼"; opacity: 1; color: var(--color-primary); }
@@ -1,23 +1,56 @@
1
+ <% if respond_to?(:style_tag) %>
2
+ <% style_tag "job_stats/css/job_stats.css" %>
3
+ <% else %>
1
4
  <style>
2
- table {
3
- text-align: left;
4
- position: relative;
5
- border-collapse: separate;
6
- border-spacing: 0;
7
- }
5
+ .sortable-table .fixTableHead { max-height: 500px; overflow: auto; }
8
6
 
9
- th {
7
+ .sortable-table th {
10
8
  position: sticky;
11
9
  top: 0;
12
10
  background-color: #F9F8F8;
13
- border-bottom: 1px solid #EB9486;
11
+ border-bottom: 1px solid #ddd;
12
+ white-space: nowrap;
13
+ }
14
+
15
+ .sortable-table th a {
16
+ display: block;
17
+ color: inherit;
18
+ text-decoration: none;
19
+ padding-right: 1.4em;
20
+ position: relative;
14
21
  }
15
22
 
16
- .fixTableHead {
17
- max-height: 500px;
18
- overflow: auto;
23
+ .sortable-table th a:hover { text-decoration: underline; }
24
+
25
+ .sortable-table th a::after {
26
+ content: "⇅";
27
+ position: absolute;
28
+ right: 0;
29
+ opacity: 0.25;
30
+ font-size: 0.8em;
31
+ font-weight: normal;
19
32
  }
33
+
34
+ .sortable-table th.sort-asc,
35
+ .sortable-table th.sort-desc { background-color: #EEF4FF; }
36
+
37
+ .sortable-table th.sort-asc a::after { content: "▲"; opacity: 1; color: #4A7FD4; }
38
+ .sortable-table th.sort-desc a::after { content: "▼"; opacity: 1; color: #4A7FD4; }
20
39
  </style>
40
+ <% end %>
41
+
42
+ <%
43
+ def history_sort_url(root, path, sort_key, current_sort, current_dir, start, limit)
44
+ dir = (current_sort == sort_key && current_dir == "asc") ? "desc" : "asc"
45
+ "#{root}#{path}?sort=#{sort_key}&direction=#{dir}&start=0&limit=#{limit}"
46
+ end
47
+
48
+ def pagination_url(root, path, start, limit, sort, direction)
49
+ url = "#{root}#{path}?start=#{start}&limit=#{limit}"
50
+ url += "&sort=#{sort}&direction=#{direction}" unless sort.to_s.empty?
51
+ url
52
+ end
53
+ %>
21
54
 
22
55
  <h1>Sidekiq Job Histories</h1>
23
56
 
@@ -26,33 +59,52 @@
26
59
  </p>
27
60
  <h2><%= @job_class.job_class.to_s %></h2>
28
61
 
29
- <div class="fixTableHead">
30
- <table class="table table-hover table-bordered table-striped">
62
+ <%if @start > 0 || @start + @limit <= @size %>
63
+ <p class='pagination'>
64
+ <% if @start > 0 %>
65
+ <a href="<%= pagination_url(root_path, request.path_info, [0, @start - @limit].max, @limit, @sort, @direction) %>" class='less'>&laquo; less</a>
66
+ <% end %>
67
+ <% if @start + @limit <= @size %>
68
+ <a href="<%= pagination_url(root_path, request.path_info, @start + @limit, @limit, @sort, @direction) %>" class='more'>more &raquo;</a>
69
+ <% end %>
70
+ </p>
71
+ <%end%>
72
+
73
+ <div class="sortable-table">
74
+ <div class="table_container">
75
+ <table>
31
76
  <thead>
32
77
  <tr>
33
- <th class="header">Process</th>
34
- <th class="header">Enqueued time</th>
35
- <th class="header">Started at</th>
36
- <th class="header">Finished at</th>
37
- <th class="header">Duration</th>
38
- <th class="header">Arguments</th>
39
- <th class="header">Success</th>
40
- <th class="header">Exception</th>
78
+ <% [
79
+ ["Process", "process"],
80
+ ["Enqueued time", "enqueued_at"],
81
+ ["Started at", "started_at"],
82
+ ["Finished at", "finished_at"],
83
+ ["Duration", "duration"],
84
+ ["Arguments", "payload"],
85
+ ["Success", "status"],
86
+ ["Exception", "exception"],
87
+ ].each do |label, key| %>
88
+ <% css = @sort == key ? "sort-#{@direction}" : "" %>
89
+ <th class="<%= css %>">
90
+ <a href="<%= history_sort_url(root_path, request.path_info, key, @sort, @direction, @start, @limit) %>"><%= label %></a>
91
+ </th>
92
+ <% end %>
41
93
  </tr>
42
94
  </thead>
43
95
  <tbody>
44
96
  <% @histories.each do |history| %>
45
97
  <% if history.is_a? Hash %>
46
98
  <tr>
47
- <td>
99
+ <td>
48
100
  <%= history["process"] %>
49
101
  <% Array(history["tags"]).each do |tag| %>
50
102
  <span class="label label-info jobtag"><%= tag %></span>
51
103
  <% end %>
52
104
  </td>
53
- <td><span class="time"><%= Time.at(history["enqueued_at"]) %></span></td>
105
+ <td><span class="time"><%= format_enqueued_at(history["enqueued_at"]) %></span></td>
54
106
  <td><span class="time"><%= history["started_at"] %></span></td>
55
- <td><span class="time"><%= history["finished_at"]%></span></td>
107
+ <td><span class="time"><%= history["finished_at"] %></span></td>
56
108
  <td><%= history["duration"] %>s</td>
57
109
  <td><div class="args"><%= history["payload"] %></div></td>
58
110
  <td><%= history["status"] %></td>
@@ -62,16 +114,16 @@
62
114
  <% end %>
63
115
  </tbody>
64
116
  </table>
117
+ </div>
65
118
  </div>
66
119
 
67
120
  <%if @start > 0 || @start + @limit <= @size %>
68
121
  <p class='pagination'>
69
- <% if @start - @limit >= 0 %>
70
- <a href="<%= root_path %><%= request.path_info %>?start=<%= [0, @start - @limit].max %>&limit=<%= @limit %>" class='less'>&laquo; less</a>
122
+ <% if @start > 0 %>
123
+ <a href="<%= pagination_url(root_path, request.path_info, [0, @start - @limit].max, @limit, @sort, @direction) %>" class='less'>&laquo; less</a>
71
124
  <% end %>
72
125
  <% if @start + @limit <= @size %>
73
- <a href="<%= root_path %><%= request.path_info %>?start=<%= @start + @limit %>&limit=<%= @limit %>" class='more'>more &raquo;</a>
126
+ <a href="<%= pagination_url(root_path, request.path_info, @start + @limit, @limit, @sort, @direction) %>" class='more'>more &raquo;</a>
74
127
  <% end %>
75
128
  </p>
76
129
  <%end%>
77
-
@@ -1,23 +1,43 @@
1
+ <% if respond_to?(:style_tag) %>
2
+ <% style_tag "job_stats/css/job_stats.css" %>
3
+ <% else %>
1
4
  <style>
2
- table {
3
- text-align: left;
4
- position: relative;
5
- border-collapse: separate;
6
- border-spacing: 0;
7
- }
5
+ .sortable-table .fixTableHead { max-height: 500px; overflow: auto; }
8
6
 
9
- th {
7
+ .sortable-table th {
10
8
  position: sticky;
11
9
  top: 0;
12
10
  background-color: #F9F8F8;
13
- border-bottom: 1px solid #EB9486;
11
+ border-bottom: 1px solid #ddd;
12
+ white-space: nowrap;
13
+ }
14
+
15
+ .sortable-table th a {
16
+ display: block;
17
+ color: inherit;
18
+ text-decoration: none;
19
+ padding-right: 1.4em;
20
+ position: relative;
14
21
  }
15
22
 
16
- .fixTableHead {
17
- max-height: 500px;
18
- overflow: auto;
23
+ .sortable-table th a:hover { text-decoration: underline; }
24
+
25
+ .sortable-table th a::after {
26
+ content: "⇅";
27
+ position: absolute;
28
+ right: 0;
29
+ opacity: 0.25;
30
+ font-size: 0.8em;
31
+ font-weight: normal;
19
32
  }
33
+
34
+ .sortable-table th.sort-asc,
35
+ .sortable-table th.sort-desc { background-color: #EEF4FF; }
36
+
37
+ .sortable-table th.sort-asc a::after { content: "▲"; opacity: 1; color: #4A7FD4; }
38
+ .sortable-table th.sort-desc a::after { content: "▼"; opacity: 1; color: #4A7FD4; }
20
39
  </style>
40
+ <% end %>
21
41
 
22
42
  <h1>Sidekiq Job Stats</h1>
23
43
 
@@ -25,44 +45,46 @@
25
45
  This page displays statistics about jobs that have been executed.
26
46
  </p>
27
47
 
28
- <div class="fixTableHead">
29
- <table class="table table-hover table-bordered table-striped">
30
- <thead class="fixedHeader">
31
- <tr>
32
- <th class="header">Name</th>
33
- <%= stat_header(:jobs_enqueued) %>
34
- <%= stat_header(:jobs_performed_day) %>
35
- <%= stat_header(:jobs_performed_month) %>
36
- <%= stat_header(:job_rolling_avg_day) %>
37
- <%= stat_header(:job_rolling_avg_month) %>
38
- <%= stat_header(:longest_job_day) %>
39
- <%= stat_header(:longest_job_month) %>
40
- <%= stat_header(:job_memory_usage_avg_day) %>
41
- <%= stat_header(:job_memory_usage_avg_month) %>
42
- <%= stat_header(:peak_memory_usage_day) %>
43
- <%= stat_header(:peak_memory_usage_month) %>
44
- </tr>
45
- </thead>
46
- <tbody class="scrollContent">
47
- <% @jobs.each do |job| %>
48
- <tr>
49
- <td>
50
- <%= job.name %>
51
- <a href='<%= "#{root_path}job_stats/job_history/#{job.name}" %>'>[history]</a>
52
- </td>
53
- <%= display_stat(job, :jobs_enqueued, :number_display) %>
54
- <%= display_stat(job, :jobs_performed_day, :number_display) %>
55
- <%= display_stat(job, :jobs_performed_month, :number_display) %>
56
- <%= display_stat(job, :job_rolling_avg_day, :time_display) %>
57
- <%= display_stat(job, :job_rolling_avg_month, :time_display) %>
58
- <%= display_stat(job, :longest_job_day, :time_display) %>
59
- <%= display_stat(job, :longest_job_month, :time_display) %>
60
- <%= display_stat(job, :job_memory_usage_avg_day, :mb_display) %>
61
- <%= display_stat(job, :job_memory_usage_avg_month, :mb_display) %>
62
- <%= display_stat(job, :peak_memory_usage_day, :mb_display) %>
63
- <%= display_stat(job, :peak_memory_usage_month, :mb_display) %>
64
- </tr>
65
- <% end %>
66
- </tbody>
67
- </table>
68
- </div>
48
+ <div class="sortable-table">
49
+ <div class="table_container">
50
+ <table>
51
+ <thead>
52
+ <tr>
53
+ <%= job_stats_sort_th("Name", "name") %>
54
+ <%= stat_header(:jobs_enqueued) %>
55
+ <%= stat_header(:jobs_performed_day) %>
56
+ <%= stat_header(:jobs_performed_month) %>
57
+ <%= stat_header(:job_rolling_avg_day) %>
58
+ <%= stat_header(:job_rolling_avg_month) %>
59
+ <%= stat_header(:longest_job_day) %>
60
+ <%= stat_header(:longest_job_month) %>
61
+ <%= stat_header(:job_memory_usage_avg_day) %>
62
+ <%= stat_header(:job_memory_usage_avg_month) %>
63
+ <%= stat_header(:peak_memory_usage_day) %>
64
+ <%= stat_header(:peak_memory_usage_month) %>
65
+ </tr>
66
+ </thead>
67
+ <tbody>
68
+ <% @jobs.each do |job| %>
69
+ <tr>
70
+ <td>
71
+ <%= job.name %>
72
+ <a href='<%= "#{root_path}job_stats/job_history/#{job.name}" %>'>[history]</a>
73
+ </td>
74
+ <%= display_stat(job, :jobs_enqueued, :number_display) %>
75
+ <%= display_stat(job, :jobs_performed_day, :number_display) %>
76
+ <%= display_stat(job, :jobs_performed_month, :number_display) %>
77
+ <%= display_stat(job, :job_rolling_avg_day, :time_display) %>
78
+ <%= display_stat(job, :job_rolling_avg_month, :time_display) %>
79
+ <%= display_stat(job, :longest_job_day, :time_display) %>
80
+ <%= display_stat(job, :longest_job_month, :time_display) %>
81
+ <%= display_stat(job, :job_memory_usage_avg_day, :mb_display) %>
82
+ <%= display_stat(job, :job_memory_usage_avg_month, :mb_display) %>
83
+ <%= display_stat(job, :peak_memory_usage_day, :mb_display) %>
84
+ <%= display_stat(job, :peak_memory_usage_month, :mb_display) %>
85
+ </tr>
86
+ <% end %>
87
+ </tbody>
88
+ </table>
89
+ </div>
90
+ </div>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-job-stats
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - isliusar
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-02-03 00:00:00.000000000 Z
11
+ date: 2026-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq
@@ -64,6 +64,7 @@ files:
64
64
  - lib/sidekiq_job_stats/statistic.rb
65
65
  - lib/sidekiq_job_stats/version.rb
66
66
  - lib/sidekiq_job_stats/web_extension.rb
67
+ - lib/web/assets/job_stats/css/job_stats.css
67
68
  - lib/web/views/job_histories.erb
68
69
  - lib/web/views/job_stats.erb
69
70
  - sidekiq-job-stats.gemspec
@@ -75,7 +76,7 @@ metadata:
75
76
  homepage_uri: https://github.com/sliusar-ihor/sidekiq-job-stats
76
77
  source_code_uri: https://github.com/sliusar-ihor/sidekiq-job-stats
77
78
  changelog_uri: https://github.com/sliusar-ihor/sidekiq-job-stats
78
- post_install_message:
79
+ post_install_message:
79
80
  rdoc_options: []
80
81
  require_paths:
81
82
  - lib
@@ -90,8 +91,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
91
  - !ruby/object:Gem::Version
91
92
  version: '0'
92
93
  requirements: []
93
- rubygems_version: 3.5.11
94
- signing_key:
94
+ rubygems_version: 3.0.3.1
95
+ signing_key:
95
96
  specification_version: 4
96
97
  summary: Tracks jobs performed, failed, and the duration of the last 100 jobs for
97
98
  each job type.