promenade 0.12.2 → 0.12.4

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: 9be9950116dea78f1a07e2b4ec1cd0d8a290c48f390e75f95b88cb9687b5db48
4
- data.tar.gz: 24b9e9275600f6cfe014505b0752efad476bcb9498c6d1653db6c75b512db4c4
3
+ metadata.gz: 49d2e750dd0fdec89e701c966a98d411a8b9eceabd2ccb64024d413660ef82d0
4
+ data.tar.gz: e5bd7c4e94c30ae55b733bf8db4a18d7149f7f55786e167e0c1e8ad278f6a4bb
5
5
  SHA512:
6
- metadata.gz: 4a91f14302d8dc02706233f5d7c92819f7dd2878d07affdd9610018f3993b20ca737514e0ed88d6a1fd4cc9a82182f03dd00181d88242c25e9a2424347f39584
7
- data.tar.gz: 9c8399ffab1eb5b6d4166063e763b7d06f9e80440bdc42769f3dd149ba0399676212f3169480e4fb3599da5f51c2efae6b60a90e65862f9abea4d9e95c6d7ca6
6
+ metadata.gz: 07d9e832b3589d10022e2efa2a42a1be6cf7c3372baf12148b6fbb14a1c63e979b061ce71c9e00dca611b928eb3d4cad3b29fe32af05765fb54debf524265bf3
7
+ data.tar.gz: 32dd9293280f03230133283a72e78f1153b4e44116f65c4a3192e81f33ee1da4b50931238fc1327f83b30e4a58df26820dc60aa9b7a3d5b045e215baa5037256
@@ -9,12 +9,16 @@ jobs:
9
9
  strategy:
10
10
  fail-fast: false
11
11
  matrix:
12
- ruby: ["3.0", "3.1", "3.2", "3.3"]
12
+ ruby: ["3.1", "3.2", "3.3"]
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
- - uses: actions/checkout@v2
15
+ - uses: actions/checkout@v4
16
16
  - uses: ruby/setup-ruby@v1
17
17
  with:
18
18
  ruby-version: ${{ matrix.ruby }}
19
19
  bundler-cache: true
20
20
  - run: bundle exec rake
21
+ - name: Upload test results to Codecov
22
+ uses: codecov/codecov-action@v4
23
+ with:
24
+ token: ${{ secrets.CODECOV_TOKEN }}
data/Gemfile CHANGED
@@ -3,5 +3,4 @@ source "https://rubygems.org"
3
3
  # Specify your gem's dependencies in promenade.gemspec
4
4
  gemspec
5
5
 
6
- gem "codecov"
7
6
  gem "webrick"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- promenade (0.12.2)
4
+ promenade (0.12.4)
5
5
  actionpack
6
6
  activesupport (> 6.0, < 8.0)
7
7
  prometheus-client-mmap (~> 1.1)
@@ -11,35 +11,35 @@ PATH
11
11
  GEM
12
12
  remote: https://rubygems.org/
13
13
  specs:
14
- actioncable (7.1.3)
15
- actionpack (= 7.1.3)
16
- activesupport (= 7.1.3)
14
+ actioncable (7.1.3.4)
15
+ actionpack (= 7.1.3.4)
16
+ activesupport (= 7.1.3.4)
17
17
  nio4r (~> 2.0)
18
18
  websocket-driver (>= 0.6.1)
19
19
  zeitwerk (~> 2.6)
20
- actionmailbox (7.1.3)
21
- actionpack (= 7.1.3)
22
- activejob (= 7.1.3)
23
- activerecord (= 7.1.3)
24
- activestorage (= 7.1.3)
25
- activesupport (= 7.1.3)
20
+ actionmailbox (7.1.3.4)
21
+ actionpack (= 7.1.3.4)
22
+ activejob (= 7.1.3.4)
23
+ activerecord (= 7.1.3.4)
24
+ activestorage (= 7.1.3.4)
25
+ activesupport (= 7.1.3.4)
26
26
  mail (>= 2.7.1)
27
27
  net-imap
28
28
  net-pop
29
29
  net-smtp
30
- actionmailer (7.1.3)
31
- actionpack (= 7.1.3)
32
- actionview (= 7.1.3)
33
- activejob (= 7.1.3)
34
- activesupport (= 7.1.3)
30
+ actionmailer (7.1.3.4)
31
+ actionpack (= 7.1.3.4)
32
+ actionview (= 7.1.3.4)
33
+ activejob (= 7.1.3.4)
34
+ activesupport (= 7.1.3.4)
35
35
  mail (~> 2.5, >= 2.5.4)
36
36
  net-imap
37
37
  net-pop
38
38
  net-smtp
39
39
  rails-dom-testing (~> 2.2)
40
- actionpack (7.1.3)
41
- actionview (= 7.1.3)
42
- activesupport (= 7.1.3)
40
+ actionpack (7.1.3.4)
41
+ actionview (= 7.1.3.4)
42
+ activesupport (= 7.1.3.4)
43
43
  nokogiri (>= 1.8.5)
44
44
  racc
45
45
  rack (>= 2.2.4)
@@ -47,35 +47,35 @@ GEM
47
47
  rack-test (>= 0.6.3)
48
48
  rails-dom-testing (~> 2.2)
49
49
  rails-html-sanitizer (~> 1.6)
50
- actiontext (7.1.3)
51
- actionpack (= 7.1.3)
52
- activerecord (= 7.1.3)
53
- activestorage (= 7.1.3)
54
- activesupport (= 7.1.3)
50
+ actiontext (7.1.3.4)
51
+ actionpack (= 7.1.3.4)
52
+ activerecord (= 7.1.3.4)
53
+ activestorage (= 7.1.3.4)
54
+ activesupport (= 7.1.3.4)
55
55
  globalid (>= 0.6.0)
56
56
  nokogiri (>= 1.8.5)
57
- actionview (7.1.3)
58
- activesupport (= 7.1.3)
57
+ actionview (7.1.3.4)
58
+ activesupport (= 7.1.3.4)
59
59
  builder (~> 3.1)
60
60
  erubi (~> 1.11)
61
61
  rails-dom-testing (~> 2.2)
62
62
  rails-html-sanitizer (~> 1.6)
63
- activejob (7.1.3)
64
- activesupport (= 7.1.3)
63
+ activejob (7.1.3.4)
64
+ activesupport (= 7.1.3.4)
65
65
  globalid (>= 0.3.6)
66
- activemodel (7.1.3)
67
- activesupport (= 7.1.3)
68
- activerecord (7.1.3)
69
- activemodel (= 7.1.3)
70
- activesupport (= 7.1.3)
66
+ activemodel (7.1.3.4)
67
+ activesupport (= 7.1.3.4)
68
+ activerecord (7.1.3.4)
69
+ activemodel (= 7.1.3.4)
70
+ activesupport (= 7.1.3.4)
71
71
  timeout (>= 0.4.0)
72
- activestorage (7.1.3)
73
- actionpack (= 7.1.3)
74
- activejob (= 7.1.3)
75
- activerecord (= 7.1.3)
76
- activesupport (= 7.1.3)
72
+ activestorage (7.1.3.4)
73
+ actionpack (= 7.1.3.4)
74
+ activejob (= 7.1.3.4)
75
+ activerecord (= 7.1.3.4)
76
+ activesupport (= 7.1.3.4)
77
77
  marcel (~> 1.0)
78
- activesupport (7.1.3)
78
+ activesupport (7.1.3.4)
79
79
  base64
80
80
  bigdecimal
81
81
  concurrent-ruby (~> 1.0, >= 1.0.2)
@@ -87,24 +87,21 @@ GEM
87
87
  tzinfo (~> 2.0)
88
88
  ast (2.4.2)
89
89
  base64 (0.2.0)
90
- bigdecimal (3.1.6)
91
- builder (3.2.4)
90
+ bigdecimal (3.1.8)
91
+ builder (3.3.0)
92
92
  byebug (11.1.3)
93
93
  climate_control (1.2.0)
94
- codecov (0.6.0)
95
- simplecov (>= 0.15, < 0.22)
96
- concurrent-ruby (1.2.3)
94
+ concurrent-ruby (1.3.4)
97
95
  connection_pool (2.4.1)
98
96
  crass (1.0.6)
99
97
  date (3.3.4)
100
98
  diff-lcs (1.5.1)
101
99
  docile (1.4.0)
102
- drb (2.2.0)
103
- ruby2_keywords
104
- erubi (1.12.0)
100
+ drb (2.2.1)
101
+ erubi (1.13.0)
105
102
  globalid (1.2.1)
106
103
  activesupport (>= 6.1)
107
- i18n (1.14.1)
104
+ i18n (1.14.5)
108
105
  concurrent-ruby (~> 1.0)
109
106
  io-console (0.7.2)
110
107
  irb (1.11.2)
@@ -120,9 +117,9 @@ GEM
120
117
  net-imap
121
118
  net-pop
122
119
  net-smtp
123
- marcel (1.0.2)
120
+ marcel (1.0.4)
124
121
  mini_mime (1.1.5)
125
- minitest (5.22.2)
122
+ minitest (5.25.0)
126
123
  mutex_m (0.2.0)
127
124
  net-imap (0.4.10)
128
125
  date
@@ -134,20 +131,16 @@ GEM
134
131
  net-smtp (0.4.0.1)
135
132
  net-protocol
136
133
  nio4r (2.7.0)
137
- nokogiri (1.16.2-arm-linux)
134
+ nokogiri (1.16.7-arm64-darwin)
138
135
  racc (~> 1.4)
139
- nokogiri (1.16.2-arm64-darwin)
136
+ nokogiri (1.16.7-x86_64-darwin)
140
137
  racc (~> 1.4)
141
- nokogiri (1.16.2-x86_64-darwin)
142
- racc (~> 1.4)
143
- nokogiri (1.16.2-x86_64-linux)
138
+ nokogiri (1.16.7-x86_64-linux)
144
139
  racc (~> 1.4)
145
140
  parallel (1.24.0)
146
141
  parser (3.3.0.5)
147
142
  ast (~> 2.4.1)
148
143
  racc
149
- prometheus-client-mmap (1.1.1)
150
- rb_sys (~> 0.9.86)
151
144
  prometheus-client-mmap (1.1.1-arm64-darwin)
152
145
  rb_sys (~> 0.9.86)
153
146
  prometheus-client-mmap (1.1.1-x86_64-darwin)
@@ -156,8 +149,8 @@ GEM
156
149
  rb_sys (~> 0.9.86)
157
150
  psych (5.1.2)
158
151
  stringio
159
- racc (1.7.3)
160
- rack (3.0.9)
152
+ racc (1.8.1)
153
+ rack (3.1.7)
161
154
  rack-session (2.0.0)
162
155
  rack (>= 3.0.0)
163
156
  rack-test (2.1.0)
@@ -165,20 +158,20 @@ GEM
165
158
  rackup (2.1.0)
166
159
  rack (>= 3)
167
160
  webrick (~> 1.8)
168
- rails (7.1.3)
169
- actioncable (= 7.1.3)
170
- actionmailbox (= 7.1.3)
171
- actionmailer (= 7.1.3)
172
- actionpack (= 7.1.3)
173
- actiontext (= 7.1.3)
174
- actionview (= 7.1.3)
175
- activejob (= 7.1.3)
176
- activemodel (= 7.1.3)
177
- activerecord (= 7.1.3)
178
- activestorage (= 7.1.3)
179
- activesupport (= 7.1.3)
161
+ rails (7.1.3.4)
162
+ actioncable (= 7.1.3.4)
163
+ actionmailbox (= 7.1.3.4)
164
+ actionmailer (= 7.1.3.4)
165
+ actionpack (= 7.1.3.4)
166
+ actiontext (= 7.1.3.4)
167
+ actionview (= 7.1.3.4)
168
+ activejob (= 7.1.3.4)
169
+ activemodel (= 7.1.3.4)
170
+ activerecord (= 7.1.3.4)
171
+ activestorage (= 7.1.3.4)
172
+ activesupport (= 7.1.3.4)
180
173
  bundler (>= 1.15.0)
181
- railties (= 7.1.3)
174
+ railties (= 7.1.3.4)
182
175
  rails-dom-testing (2.2.0)
183
176
  activesupport (>= 5.0.0)
184
177
  minitest
@@ -186,23 +179,25 @@ GEM
186
179
  rails-html-sanitizer (1.6.0)
187
180
  loofah (~> 2.21)
188
181
  nokogiri (~> 1.14)
189
- railties (7.1.3)
190
- actionpack (= 7.1.3)
191
- activesupport (= 7.1.3)
182
+ railties (7.1.3.4)
183
+ actionpack (= 7.1.3.4)
184
+ activesupport (= 7.1.3.4)
192
185
  irb
193
186
  rackup (>= 1.0.0)
194
187
  rake (>= 12.2)
195
188
  thor (~> 1.0, >= 1.2.2)
196
189
  zeitwerk (~> 2.6)
197
190
  rainbow (3.1.1)
191
+ raindrops (0.20.1)
198
192
  rake (13.1.0)
199
193
  rb_sys (0.9.87)
200
- rdoc (6.6.2)
194
+ rdoc (6.6.3.1)
201
195
  psych (>= 4.0.0)
202
196
  regexp_parser (2.9.0)
203
- reline (0.4.2)
197
+ reline (0.4.3)
204
198
  io-console (~> 0.5)
205
- rexml (3.2.6)
199
+ rexml (3.3.6)
200
+ strscan
206
201
  rspec (3.13.0)
207
202
  rspec-core (~> 3.13.0)
208
203
  rspec-expectations (~> 3.13.0)
@@ -254,15 +249,18 @@ GEM
254
249
  rubocop-capybara (~> 2.17)
255
250
  rubocop-factory_bot (~> 2.22)
256
251
  ruby-progressbar (1.13.0)
257
- ruby2_keywords (0.0.5)
258
252
  simplecov (0.21.2)
259
253
  docile (~> 1.1)
260
254
  simplecov-html (~> 0.11)
261
255
  simplecov_json_formatter (~> 0.1)
256
+ simplecov-cobertura (2.1.0)
257
+ rexml
258
+ simplecov (~> 0.19)
262
259
  simplecov-html (0.12.3)
263
260
  simplecov_json_formatter (0.1.4)
264
261
  stringio (3.1.0)
265
- thor (1.3.0)
262
+ strscan (3.1.0)
263
+ thor (1.3.1)
266
264
  timeout (0.4.1)
267
265
  tzinfo (2.0.6)
268
266
  concurrent-ruby (~> 1.0)
@@ -274,8 +272,8 @@ GEM
274
272
  zeitwerk (2.6.13)
275
273
 
276
274
  PLATFORMS
275
+ arm64-darwin-21
277
276
  arm64-darwin-22
278
- arm64-linux
279
277
  x86_64-darwin-22
280
278
  x86_64-linux
281
279
 
@@ -283,9 +281,9 @@ DEPENDENCIES
283
281
  bundler (~> 2.0)
284
282
  byebug
285
283
  climate_control
286
- codecov
287
284
  promenade!
288
285
  rails (> 3.0, < 8.0)
286
+ raindrops
289
287
  rake
290
288
  rspec (~> 3.11)
291
289
  rspec-rails (~> 5.1)
@@ -294,6 +292,7 @@ DEPENDENCIES
294
292
  rubocop-rails
295
293
  rubocop-rspec
296
294
  simplecov
295
+ simplecov-cobertura
297
296
  webrick
298
297
 
299
298
  BUNDLED WITH
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![CI](https://github.com/errm/promenade/actions/workflows/ci.yaml/badge.svg)](https://github.com/errm/promenade/actions/workflows/ci.yaml)
4
4
  [![Gem Version](https://badge.fury.io/rb/promenade.svg)](https://badge.fury.io/rb/promenade)
5
+ [![codecov](https://codecov.io/github/errm/promenade/graph/badge.svg?token=Xreh8NR1nh)](https://codecov.io/github/errm/promenade)
5
6
 
6
7
  Promenade is a library to simplify instrumenting Ruby applications with Prometheus.
7
8
 
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "promenade"
5
+ require "promenade/yjit/stats"
6
+ require "prometheus/client"
7
+ require "prometheus/client/formats/text"
8
+
9
+ Promenade.setup
10
+ Promenade::YJIT::Stats.instrument
11
+ puts Prometheus::Client::Formats::Text.marshal_multiprocess
data/codecove.yml ADDED
@@ -0,0 +1,2 @@
1
+ ignore:
2
+ - "lib/promenade/railtie.rb"
@@ -0,0 +1,32 @@
1
+ begin
2
+ require "pitchfork/mem_info"
3
+ rescue LoadError
4
+ # No pitchfork available, dont do anything
5
+ end
6
+
7
+ module Promenade
8
+ module Pitchfork
9
+ class MemStats
10
+ Promenade.gauge :pitchfork_memory_usage_bytes do
11
+ doc "Memory usage in bytes, broken down by type (RSS, PSS, SHARED_MEMORY)"
12
+ end
13
+
14
+ def initialize
15
+ return unless defined?(::Pitchfork) && defined?(::Pitchfork::MemInfo)
16
+
17
+ @mem_info = ::Pitchfork::MemInfo.new(Process.pid)
18
+ end
19
+
20
+ def instrument
21
+ Promenade.metric(:pitchfork_memory_usage_bytes).set({ type: "RSS" }, @mem_info.rss * 1024)
22
+ Promenade.metric(:pitchfork_memory_usage_bytes).set({ type: "PSS" }, @mem_info.pss * 1024)
23
+ Promenade.metric(:pitchfork_memory_usage_bytes).set({ type: "Shared" }, @mem_info.shared_memory * 1024)
24
+ end
25
+
26
+ def self.instrument
27
+ new.instrument
28
+ rescue StandardError
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,28 @@
1
+ require "promenade/pitchfork/stats"
2
+ require "promenade/pitchfork/mem_stats"
3
+
4
+ module Promenade
5
+ module Pitchfork
6
+ class Middleware
7
+ RACK_AFTER_REPLY = "rack.after_reply".freeze
8
+
9
+ def initialize(app)
10
+ @app = app
11
+ end
12
+
13
+ def call(env)
14
+ if env.key?(RACK_AFTER_REPLY)
15
+ env[RACK_AFTER_REPLY] << -> { instrument }
16
+ end
17
+ @app.call(env)
18
+ end
19
+
20
+ private
21
+
22
+ def instrument
23
+ Promenade::Pitchfork::Stats.instrument
24
+ Promenade::Pitchfork::MemStats.instrument
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,62 @@
1
+ require "promenade/raindrops/stats"
2
+
3
+ module Promenade
4
+ module Pitchfork
5
+ class Stats
6
+ Promenade.gauge :pitchfork_workers_count do
7
+ doc "Number of workers configured"
8
+ end
9
+
10
+ Promenade.gauge :pitchfork_live_workers_count do
11
+ doc "Number of live / booted workers"
12
+ end
13
+
14
+ Promenade.gauge :pitchfork_capacity do
15
+ doc "Number of workers that are currently idle"
16
+ end
17
+
18
+ Promenade.gauge :pitchfork_busy_percent do
19
+ doc "Percentage of workers that are currently busy"
20
+ end
21
+
22
+ def initialize
23
+ return unless defined?(::Pitchfork) && defined?(::Pitchfork::Info)
24
+
25
+ @workers_count = ::Pitchfork::Info.workers_count
26
+ @live_workers_count = ::Pitchfork::Info.live_workers_count
27
+
28
+ raindrops_stats = Raindrops::Stats.new
29
+
30
+ @active_workers = raindrops_stats.active_workers || 0
31
+ @queued_requests = raindrops_stats.queued_requests || 0
32
+ end
33
+
34
+ def instrument
35
+ Promenade.metric(:pitchfork_workers_count).set({}, workers_count)
36
+ Promenade.metric(:pitchfork_live_workers_count).set({}, live_workers_count)
37
+ Promenade.metric(:pitchfork_capacity).set({}, capacity)
38
+ Promenade.metric(:pitchfork_busy_percent).set({}, busy_percent)
39
+ end
40
+
41
+ def self.instrument
42
+ new.instrument
43
+ end
44
+
45
+ private
46
+
47
+ attr_reader :workers_count, :live_workers_count, :active_workers, :queued_requests
48
+
49
+ def capacity
50
+ return 0 if live_workers_count.nil? || live_workers_count == 0
51
+
52
+ live_workers_count - active_workers
53
+ end
54
+
55
+ def busy_percent
56
+ return 0 if live_workers_count == 0
57
+
58
+ (active_workers.to_f / live_workers_count) * 100
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,31 @@
1
+ module Promenade
2
+ module Pitchfork
3
+ class WorkerPidProvider
4
+ def self.fetch
5
+ worker_id || "process_id_#{Process.pid}"
6
+ end
7
+
8
+ def self.object_based_worker_id
9
+ return unless defined?(::Pitchfork::Worker)
10
+
11
+ workers = ObjectSpace.each_object(::Pitchfork::Worker)
12
+ return if workers.nil?
13
+
14
+ workers_first = workers.first
15
+ workers_first&.nr
16
+ end
17
+
18
+ def self.program_name
19
+ $PROGRAM_NAME
20
+ end
21
+
22
+ def self.worker_id
23
+ if matchdata = program_name.match(/pitchfork.*worker\[(.+)\]/) # rubocop:disable Lint/AssignmentInCondition
24
+ "pitchfork_#{matchdata[1]}"
25
+ elsif object_worker_id = object_based_worker_id # rubocop:disable Lint/AssignmentInCondition
26
+ "pitchfork_#{object_worker_id}"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -13,6 +13,16 @@ module Promenade
13
13
  Promenade::Client::Rack::HTTPRequestDurationCollector
14
14
  Rails.application.config.middleware.insert 0,
15
15
  Promenade::Client::Rack::HTTPRequestQueueTimeCollector
16
+
17
+ if defined?(::Raindrops) && (defined?(::Pitchfork) || defined?(::Unicorn))
18
+ require "promenade/raindrops/middleware"
19
+ Rails.application.config.middleware.use Promenade::Raindrops::Middleware
20
+ end
21
+
22
+ if defined?(::Pitchfork)
23
+ require "promenade/pitchfork/middleware"
24
+ Rails.application.config.middleware.use Promenade::Pitchfork::Middleware
25
+ end
16
26
  end
17
27
  end
18
28
  end
@@ -0,0 +1,39 @@
1
+ require "promenade/raindrops/stats"
2
+
3
+ module Promenade
4
+ module Raindrops
5
+ class Middleware
6
+ RACK_AFTER_REPLY = "rack.after_reply".freeze
7
+
8
+ def initialize(app)
9
+ @app = app
10
+ end
11
+
12
+ def call(env)
13
+ if env.key?(RACK_AFTER_REPLY)
14
+ env[RACK_AFTER_REPLY] << -> { instrument }
15
+ end
16
+ @app.call(env)
17
+ end
18
+
19
+ private
20
+
21
+ def tcp_listener_names
22
+ if defined?(::Pitchfork)
23
+ ::Pitchfork.listener_names
24
+ elsif defined?(::Unicorn)
25
+ ::Unicorn.listener_names
26
+ else
27
+ raise StandardError,
28
+ "Promenade::Raindrops::Middleware expects either ::Pitchfork or ::Unicorn to be defined"
29
+ end
30
+ end
31
+
32
+ def instrument
33
+ tcp_listener_names.each do |name|
34
+ Promenade::Raindrops::Stats.instrument(listener_address: name)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ begin
2
+ require "raindrops"
3
+ rescue LoadError
4
+ # No raindrops available, dont do anything
5
+ end
6
+
7
+ module Promenade
8
+ module Raindrops
9
+ Promenade.gauge :rack_active_workers do
10
+ doc "Number of active workers in the Application Server"
11
+ end
12
+
13
+ Promenade.gauge :rack_queued_requests do
14
+ doc "Number of requests waiting to be processed by the Application Server"
15
+ end
16
+
17
+ class Stats
18
+ attr_reader :active_workers, :queued_requests, :listener_address
19
+
20
+ def initialize(listener_address: nil)
21
+ return unless defined?(::Raindrops)
22
+ return unless defined?(::Raindrops::Linux.tcp_listener_stats)
23
+
24
+ @listener_address = listener_address || "127.0.0.1:#{ENV.fetch('PORT', 3000)}"
25
+
26
+ stats = ::Raindrops::Linux.tcp_listener_stats([@listener_address])[@listener_address]
27
+
28
+ @active_workers = stats.active
29
+ @queued_requests = stats.queued
30
+ end
31
+
32
+ def instrument
33
+ Promenade.metric(:rack_active_workers).set({}, active_workers) if active_workers
34
+ Promenade.metric(:rack_queued_requests).set({}, queued_requests) if queued_requests
35
+ end
36
+
37
+ def self.instrument(listener_address: nil)
38
+ new(listener_address: listener_address).instrument
39
+ end
40
+ end
41
+ end
42
+ end
@@ -27,11 +27,31 @@ module Promenade
27
27
  ENV["prometheus_multiproc_dir"] = multiprocess_files_dir.to_s
28
28
 
29
29
  require "prometheus/client"
30
- require "prometheus/client/support/unicorn"
31
30
 
32
31
  ::Prometheus::Client.configure do |config|
33
32
  config.multiprocess_files_dir = multiprocess_files_dir
34
- config.pid_provider = ::Prometheus::Client::Support::Unicorn.method(:worker_pid_provider)
33
+
34
+ config.pid_provider = pid_provider_method
35
+ end
36
+ end
37
+
38
+ def pid_provider_method
39
+ # This workaround enables us to utilize the same PID provider for both Unicorn, Pitchfork and Puma.
40
+ # We cannot employ the same method directly because Unicorn and Pitchfork are not loaded simultaneously.
41
+ # Instead, we define a method that dynamically loads the appropriate PID provider based on the active server.
42
+ # As a fallback, we use the process ID.
43
+
44
+ if defined?(::Unicorn)
45
+ require "prometheus/client/support/unicorn"
46
+ ::Prometheus::Client::Support::Unicorn.method(:worker_pid_provider)
47
+ elsif defined?(::Pitchfork)
48
+ require "promenade/pitchfork/worker_pid_provider"
49
+ Pitchfork::WorkerPidProvider.method(:fetch)
50
+ elsif defined?(::Puma)
51
+ require "prometheus/client/support/puma"
52
+ ::Prometheus::Client::Support::Puma.method(:worker_pid_provider)
53
+ else
54
+ -> { "process_id_#{Process.pid}" }
35
55
  end
36
56
  end
37
57
  end
@@ -1,3 +1,3 @@
1
1
  module Promenade
2
- VERSION = "0.12.2".freeze
2
+ VERSION = "0.12.4".freeze
3
3
  end
@@ -1,14 +1,25 @@
1
1
  module Promenade
2
2
  module YJIT
3
3
  class Stats
4
+ RUNTIME_STATS = %i(
5
+ code_region_size
6
+ ratio_in_yjit
7
+ ).freeze
8
+
4
9
  Promenade.gauge :ruby_yjit_code_region_size do
5
10
  doc "Ruby YJIT code size"
6
11
  end
7
12
 
13
+ Promenade.gauge :ruby_yjit_ratio_in_yjit do
14
+ doc "Shows the ratio of YJIT-executed instructions in %"
15
+ end
16
+
8
17
  def self.instrument
9
18
  return unless defined?(::RubyVM::YJIT) && ::RubyVM::YJIT.enabled?
10
19
 
11
- Promenade.metric(:ruby_yjit_code_region_size).set({}, ::RubyVM::YJIT.runtime_stats[:code_region_size])
20
+ ::RubyVM::YJIT.runtime_stats.select { |stat, _| RUNTIME_STATS.include? stat }.each do |stat, value|
21
+ Promenade.metric(:"ruby_yjit_#{stat}").set({}, value)
22
+ end
12
23
  end
13
24
  end
14
25
  end
data/promenade.gemspec CHANGED
@@ -33,6 +33,7 @@ Gem::Specification.new do |spec|
33
33
  spec.add_development_dependency "byebug"
34
34
  spec.add_development_dependency "climate_control"
35
35
  spec.add_development_dependency "rails", "> 3.0", "< 8.0"
36
+ spec.add_development_dependency "raindrops"
36
37
  spec.add_development_dependency "rake"
37
38
  spec.add_development_dependency "rspec", "~> 3.11"
38
39
  spec.add_development_dependency "rspec-rails", "~> 5.1"
@@ -41,5 +42,6 @@ Gem::Specification.new do |spec|
41
42
  spec.add_development_dependency "rubocop-rails"
42
43
  spec.add_development_dependency "rubocop-rspec"
43
44
  spec.add_development_dependency "simplecov"
45
+ spec.add_development_dependency "simplecov-cobertura"
44
46
  spec.metadata["rubygems_mfa_required"] = "true"
45
47
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: promenade
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.2
4
+ version: 0.12.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ed Robinson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-26 00:00:00.000000000 Z
11
+ date: 2024-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -148,6 +148,20 @@ dependencies:
148
148
  - - "<"
149
149
  - !ruby/object:Gem::Version
150
150
  version: '8.0'
151
+ - !ruby/object:Gem::Dependency
152
+ name: raindrops
153
+ requirement: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ type: :development
159
+ prerelease: false
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
151
165
  - !ruby/object:Gem::Dependency
152
166
  name: rake
153
167
  requirement: !ruby/object:Gem::Requirement
@@ -260,6 +274,20 @@ dependencies:
260
274
  - - ">="
261
275
  - !ruby/object:Gem::Version
262
276
  version: '0'
277
+ - !ruby/object:Gem::Dependency
278
+ name: simplecov-cobertura
279
+ requirement: !ruby/object:Gem::Requirement
280
+ requirements:
281
+ - - ">="
282
+ - !ruby/object:Gem::Version
283
+ version: '0'
284
+ type: :development
285
+ prerelease: false
286
+ version_requirements: !ruby/object:Gem::Requirement
287
+ requirements:
288
+ - - ">="
289
+ - !ruby/object:Gem::Version
290
+ version: '0'
263
291
  description:
264
292
  email:
265
293
  - edward-robinson@cookpad.com
@@ -283,6 +311,8 @@ files:
283
311
  - bin/integration_test
284
312
  - bin/rails
285
313
  - bin/setup
314
+ - bin/yjit_intergration_test
315
+ - codecove.yml
286
316
  - exe/promenade
287
317
  - lib/promenade.rb
288
318
  - lib/promenade/client/rack/exception_handler.rb
@@ -307,8 +337,14 @@ files:
307
337
  - lib/promenade/karafka/error_subscriber.rb
308
338
  - lib/promenade/karafka/statistics_subscriber.rb
309
339
  - lib/promenade/karafka/subscriber.rb
340
+ - lib/promenade/pitchfork/mem_stats.rb
341
+ - lib/promenade/pitchfork/middleware.rb
342
+ - lib/promenade/pitchfork/stats.rb
343
+ - lib/promenade/pitchfork/worker_pid_provider.rb
310
344
  - lib/promenade/prometheus.rb
311
345
  - lib/promenade/railtie.rb
346
+ - lib/promenade/raindrops/middleware.rb
347
+ - lib/promenade/raindrops/stats.rb
312
348
  - lib/promenade/setup.rb
313
349
  - lib/promenade/version.rb
314
350
  - lib/promenade/waterdrop.rb
@@ -339,7 +375,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
339
375
  - !ruby/object:Gem::Version
340
376
  version: '0'
341
377
  requirements: []
342
- rubygems_version: 3.5.3
378
+ rubygems_version: 3.5.7
343
379
  signing_key:
344
380
  specification_version: 4
345
381
  summary: Promenade makes it simple to instrument Ruby apps for prometheus scraping