promenade 0.2.2 → 0.6.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 +4 -4
- data/.github/workflows/ci.yaml +2 -2
- data/.gitignore +10 -8
- data/.rubocop.yml +1 -1
- data/Gemfile.lock +185 -47
- data/README.md +70 -0
- data/bin/integration_test +10 -1
- data/bin/rails +14 -0
- data/lib/promenade/client/rack/exception_handler.rb +51 -0
- data/lib/promenade/client/rack/http_request_duration_collector.rb +92 -0
- data/lib/promenade/client/rack/http_request_queue_time_collector.rb +55 -0
- data/lib/promenade/client/rack/middleware_base.rb +36 -0
- data/lib/promenade/client/rack/queue_time_duration.rb +50 -0
- data/lib/promenade/client/rack/request_labeler.rb +50 -0
- data/lib/promenade/client/rack/singleton_caller.rb +19 -0
- data/lib/promenade/configuration.rb +14 -0
- data/lib/promenade/engine.rb +5 -0
- data/lib/promenade/prometheus.rb +1 -1
- data/lib/promenade/railtie.rb +7 -0
- data/lib/promenade/setup.rb +14 -5
- data/lib/promenade/version.rb +1 -1
- data/lib/promenade.rb +9 -0
- data/promenade.gemspec +10 -6
- metadata +93 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 235f95d0b77870a9975ff9870428ed5a995b9174380b981c2df7d8a338519ffb
|
|
4
|
+
data.tar.gz: 7d6e327e2d602fd2b07342fb45c9be29e36ad266212ad4ed98a72eafee58bc9e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e8596f53e3110b636696cb38f2d3bfa872715de3e331fdf260da62e30c31949a1753702b935c3343545c7be19da56f0e30a65d89568eefd419b94a5ef80fe2f9
|
|
7
|
+
data.tar.gz: 7e65f494c50b2bc25b05b169794f73c02c64ad1548c3425399b1d2cb4e7077d930e0e7d9c99ea88088c76e1026bb64cfbda246ab1a6b09c057b4f2b717b130d8
|
data/.github/workflows/ci.yaml
CHANGED
|
@@ -2,14 +2,14 @@ name: CI
|
|
|
2
2
|
on:
|
|
3
3
|
push:
|
|
4
4
|
branches:
|
|
5
|
-
-master
|
|
5
|
+
- master
|
|
6
6
|
pull_request:
|
|
7
7
|
jobs:
|
|
8
8
|
test:
|
|
9
9
|
strategy:
|
|
10
10
|
fail-fast: false
|
|
11
11
|
matrix:
|
|
12
|
-
ruby: ['2.
|
|
12
|
+
ruby: ['2.7', '3.0', "3.1"]
|
|
13
13
|
runs-on: ubuntu-latest
|
|
14
14
|
steps:
|
|
15
15
|
- uses: actions/checkout@v2
|
data/.gitignore
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
.rspec_status
|
|
2
|
+
.byebug_history
|
|
3
|
+
.rubocop-https*yml
|
|
1
4
|
/.bundle/
|
|
2
|
-
/.yardoc
|
|
3
|
-
/_yardoc/
|
|
4
5
|
/coverage/
|
|
5
6
|
/doc/
|
|
7
|
+
/log/
|
|
6
8
|
/pkg/
|
|
9
|
+
/.sass-cache/
|
|
7
10
|
/spec/reports/
|
|
11
|
+
/spec/dummy/log
|
|
12
|
+
/spec/dummy/tmp
|
|
8
13
|
/tmp/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# rspec failure tracking
|
|
14
|
-
.rspec_status
|
|
14
|
+
/vendor/
|
|
15
|
+
/.yardoc
|
|
16
|
+
/_yardoc/
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,29 +1,92 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
promenade (0.
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
promenade (0.6.0)
|
|
5
|
+
actionpack
|
|
6
|
+
activesupport (> 6.0, < 8.0)
|
|
7
|
+
prometheus-client-mmap (~> 0.16.0)
|
|
7
8
|
rack
|
|
8
9
|
|
|
9
10
|
GEM
|
|
10
11
|
remote: https://rubygems.org/
|
|
11
12
|
specs:
|
|
12
|
-
|
|
13
|
+
actioncable (7.0.3)
|
|
14
|
+
actionpack (= 7.0.3)
|
|
15
|
+
activesupport (= 7.0.3)
|
|
16
|
+
nio4r (~> 2.0)
|
|
17
|
+
websocket-driver (>= 0.6.1)
|
|
18
|
+
actionmailbox (7.0.3)
|
|
19
|
+
actionpack (= 7.0.3)
|
|
20
|
+
activejob (= 7.0.3)
|
|
21
|
+
activerecord (= 7.0.3)
|
|
22
|
+
activestorage (= 7.0.3)
|
|
23
|
+
activesupport (= 7.0.3)
|
|
24
|
+
mail (>= 2.7.1)
|
|
25
|
+
net-imap
|
|
26
|
+
net-pop
|
|
27
|
+
net-smtp
|
|
28
|
+
actionmailer (7.0.3)
|
|
29
|
+
actionpack (= 7.0.3)
|
|
30
|
+
actionview (= 7.0.3)
|
|
31
|
+
activejob (= 7.0.3)
|
|
32
|
+
activesupport (= 7.0.3)
|
|
33
|
+
mail (~> 2.5, >= 2.5.4)
|
|
34
|
+
net-imap
|
|
35
|
+
net-pop
|
|
36
|
+
net-smtp
|
|
37
|
+
rails-dom-testing (~> 2.0)
|
|
38
|
+
actionpack (7.0.3)
|
|
39
|
+
actionview (= 7.0.3)
|
|
40
|
+
activesupport (= 7.0.3)
|
|
41
|
+
rack (~> 2.0, >= 2.2.0)
|
|
42
|
+
rack-test (>= 0.6.3)
|
|
43
|
+
rails-dom-testing (~> 2.0)
|
|
44
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
|
45
|
+
actiontext (7.0.3)
|
|
46
|
+
actionpack (= 7.0.3)
|
|
47
|
+
activerecord (= 7.0.3)
|
|
48
|
+
activestorage (= 7.0.3)
|
|
49
|
+
activesupport (= 7.0.3)
|
|
50
|
+
globalid (>= 0.6.0)
|
|
51
|
+
nokogiri (>= 1.8.5)
|
|
52
|
+
actionview (7.0.3)
|
|
53
|
+
activesupport (= 7.0.3)
|
|
54
|
+
builder (~> 3.1)
|
|
55
|
+
erubi (~> 1.4)
|
|
56
|
+
rails-dom-testing (~> 2.0)
|
|
57
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
58
|
+
activejob (7.0.3)
|
|
59
|
+
activesupport (= 7.0.3)
|
|
60
|
+
globalid (>= 0.3.6)
|
|
61
|
+
activemodel (7.0.3)
|
|
62
|
+
activesupport (= 7.0.3)
|
|
63
|
+
activerecord (7.0.3)
|
|
64
|
+
activemodel (= 7.0.3)
|
|
65
|
+
activesupport (= 7.0.3)
|
|
66
|
+
activestorage (7.0.3)
|
|
67
|
+
actionpack (= 7.0.3)
|
|
68
|
+
activejob (= 7.0.3)
|
|
69
|
+
activerecord (= 7.0.3)
|
|
70
|
+
activesupport (= 7.0.3)
|
|
71
|
+
marcel (~> 1.0)
|
|
72
|
+
mini_mime (>= 1.1.0)
|
|
73
|
+
activesupport (7.0.3)
|
|
13
74
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
14
75
|
i18n (>= 1.6, < 2)
|
|
15
76
|
minitest (>= 5.1)
|
|
16
77
|
tzinfo (~> 2.0)
|
|
17
|
-
zeitwerk (~> 2.3)
|
|
18
78
|
ast (2.4.2)
|
|
19
|
-
backports (3.
|
|
79
|
+
backports (3.23.0)
|
|
20
80
|
binding_of_caller (1.0.0)
|
|
21
81
|
debug_inspector (>= 0.0.1)
|
|
22
|
-
|
|
23
|
-
|
|
82
|
+
builder (3.2.4)
|
|
83
|
+
byebug (11.1.3)
|
|
84
|
+
climate_control (1.1.1)
|
|
85
|
+
codecov (0.6.0)
|
|
24
86
|
simplecov (>= 0.15, < 0.22)
|
|
25
87
|
coderay (1.1.3)
|
|
26
|
-
concurrent-ruby (1.1.
|
|
88
|
+
concurrent-ruby (1.1.10)
|
|
89
|
+
crass (1.0.6)
|
|
27
90
|
debug_inspector (1.1.0)
|
|
28
91
|
deep-cover (1.1.0)
|
|
29
92
|
deep-cover-core (= 1.1.0)
|
|
@@ -37,53 +100,120 @@ GEM
|
|
|
37
100
|
pry
|
|
38
101
|
term-ansicolor
|
|
39
102
|
terminal-table
|
|
40
|
-
diff-lcs (1.
|
|
103
|
+
diff-lcs (1.5.0)
|
|
104
|
+
digest (3.1.0)
|
|
41
105
|
docile (1.4.0)
|
|
106
|
+
erubi (1.10.0)
|
|
107
|
+
globalid (1.0.0)
|
|
108
|
+
activesupport (>= 5.0)
|
|
42
109
|
highline (2.0.3)
|
|
43
|
-
i18n (1.
|
|
110
|
+
i18n (1.10.0)
|
|
44
111
|
concurrent-ruby (~> 1.0)
|
|
112
|
+
loofah (2.18.0)
|
|
113
|
+
crass (~> 1.0.2)
|
|
114
|
+
nokogiri (>= 1.5.9)
|
|
115
|
+
mail (2.7.1)
|
|
116
|
+
mini_mime (>= 0.1.1)
|
|
117
|
+
marcel (1.0.2)
|
|
45
118
|
method_source (1.0.0)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
119
|
+
mini_mime (1.1.2)
|
|
120
|
+
mini_portile2 (2.8.0)
|
|
121
|
+
minitest (5.16.0)
|
|
122
|
+
net-imap (0.2.3)
|
|
123
|
+
digest
|
|
124
|
+
net-protocol
|
|
125
|
+
strscan
|
|
126
|
+
net-pop (0.1.1)
|
|
127
|
+
digest
|
|
128
|
+
net-protocol
|
|
129
|
+
timeout
|
|
130
|
+
net-protocol (0.1.3)
|
|
131
|
+
timeout
|
|
132
|
+
net-smtp (0.3.1)
|
|
133
|
+
digest
|
|
134
|
+
net-protocol
|
|
135
|
+
timeout
|
|
136
|
+
nio4r (2.5.8)
|
|
137
|
+
nokogiri (1.13.6)
|
|
138
|
+
mini_portile2 (~> 2.8.0)
|
|
139
|
+
racc (~> 1.4)
|
|
140
|
+
parallel (1.22.1)
|
|
141
|
+
parser (3.1.2.0)
|
|
49
142
|
ast (~> 2.4.1)
|
|
50
|
-
prometheus-client-mmap (0.
|
|
143
|
+
prometheus-client-mmap (0.16.2)
|
|
51
144
|
pry (0.14.1)
|
|
52
145
|
coderay (~> 1.1)
|
|
53
146
|
method_source (~> 1.0)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
147
|
+
racc (1.6.0)
|
|
148
|
+
rack (2.2.3.1)
|
|
149
|
+
rack-test (1.1.0)
|
|
150
|
+
rack (>= 1.0, < 3)
|
|
151
|
+
rails (7.0.3)
|
|
152
|
+
actioncable (= 7.0.3)
|
|
153
|
+
actionmailbox (= 7.0.3)
|
|
154
|
+
actionmailer (= 7.0.3)
|
|
155
|
+
actionpack (= 7.0.3)
|
|
156
|
+
actiontext (= 7.0.3)
|
|
157
|
+
actionview (= 7.0.3)
|
|
158
|
+
activejob (= 7.0.3)
|
|
159
|
+
activemodel (= 7.0.3)
|
|
160
|
+
activerecord (= 7.0.3)
|
|
161
|
+
activestorage (= 7.0.3)
|
|
162
|
+
activesupport (= 7.0.3)
|
|
163
|
+
bundler (>= 1.15.0)
|
|
164
|
+
railties (= 7.0.3)
|
|
165
|
+
rails-dom-testing (2.0.3)
|
|
166
|
+
activesupport (>= 4.2.0)
|
|
167
|
+
nokogiri (>= 1.6)
|
|
168
|
+
rails-html-sanitizer (1.4.3)
|
|
169
|
+
loofah (~> 2.3)
|
|
170
|
+
railties (7.0.3)
|
|
171
|
+
actionpack (= 7.0.3)
|
|
172
|
+
activesupport (= 7.0.3)
|
|
173
|
+
method_source
|
|
174
|
+
rake (>= 12.2)
|
|
175
|
+
thor (~> 1.0)
|
|
176
|
+
zeitwerk (~> 2.5)
|
|
177
|
+
rainbow (3.1.1)
|
|
178
|
+
rake (13.0.6)
|
|
179
|
+
regexp_parser (2.5.0)
|
|
58
180
|
rexml (3.2.5)
|
|
59
|
-
rspec (3.
|
|
60
|
-
rspec-core (~> 3.
|
|
61
|
-
rspec-expectations (~> 3.
|
|
62
|
-
rspec-mocks (~> 3.
|
|
63
|
-
rspec-core (3.
|
|
64
|
-
rspec-support (~> 3.
|
|
65
|
-
rspec-expectations (3.
|
|
181
|
+
rspec (3.11.0)
|
|
182
|
+
rspec-core (~> 3.11.0)
|
|
183
|
+
rspec-expectations (~> 3.11.0)
|
|
184
|
+
rspec-mocks (~> 3.11.0)
|
|
185
|
+
rspec-core (3.11.0)
|
|
186
|
+
rspec-support (~> 3.11.0)
|
|
187
|
+
rspec-expectations (3.11.0)
|
|
66
188
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
67
|
-
rspec-support (~> 3.
|
|
68
|
-
rspec-mocks (3.
|
|
189
|
+
rspec-support (~> 3.11.0)
|
|
190
|
+
rspec-mocks (3.11.1)
|
|
69
191
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
70
|
-
rspec-support (~> 3.
|
|
71
|
-
rspec-
|
|
72
|
-
|
|
192
|
+
rspec-support (~> 3.11.0)
|
|
193
|
+
rspec-rails (5.1.2)
|
|
194
|
+
actionpack (>= 5.2)
|
|
195
|
+
activesupport (>= 5.2)
|
|
196
|
+
railties (>= 5.2)
|
|
197
|
+
rspec-core (~> 3.10)
|
|
198
|
+
rspec-expectations (~> 3.10)
|
|
199
|
+
rspec-mocks (~> 3.10)
|
|
200
|
+
rspec-support (~> 3.10)
|
|
201
|
+
rspec-support (3.11.0)
|
|
202
|
+
rubocop (1.30.1)
|
|
73
203
|
parallel (~> 1.10)
|
|
74
|
-
parser (>= 3.
|
|
204
|
+
parser (>= 3.1.0.0)
|
|
75
205
|
rainbow (>= 2.2.2, < 4.0)
|
|
76
206
|
regexp_parser (>= 1.8, < 3.0)
|
|
77
|
-
rexml
|
|
78
|
-
rubocop-ast (>= 1.
|
|
207
|
+
rexml (>= 3.2.5, < 4.0)
|
|
208
|
+
rubocop-ast (>= 1.18.0, < 2.0)
|
|
79
209
|
ruby-progressbar (~> 1.7)
|
|
80
210
|
unicode-display_width (>= 1.4.0, < 3.0)
|
|
81
|
-
rubocop-ast (1.
|
|
82
|
-
parser (>= 3.
|
|
83
|
-
rubocop-performance (1.
|
|
211
|
+
rubocop-ast (1.18.0)
|
|
212
|
+
parser (>= 3.1.1.0)
|
|
213
|
+
rubocop-performance (1.14.2)
|
|
84
214
|
rubocop (>= 1.7.0, < 2.0)
|
|
85
215
|
rubocop-ast (>= 0.4.0)
|
|
86
|
-
rubocop-rails (2.
|
|
216
|
+
rubocop-rails (2.15.0)
|
|
87
217
|
activesupport (>= 4.2.0)
|
|
88
218
|
rack (>= 1.1)
|
|
89
219
|
rubocop (>= 1.7.0, < 2.0)
|
|
@@ -93,34 +223,42 @@ GEM
|
|
|
93
223
|
simplecov-html (~> 0.11)
|
|
94
224
|
simplecov_json_formatter (~> 0.1)
|
|
95
225
|
simplecov-html (0.12.3)
|
|
96
|
-
simplecov_json_formatter (0.1.
|
|
226
|
+
simplecov_json_formatter (0.1.4)
|
|
227
|
+
strscan (3.0.3)
|
|
97
228
|
sync (0.5.0)
|
|
98
229
|
term-ansicolor (1.7.1)
|
|
99
230
|
tins (~> 1.0)
|
|
100
|
-
terminal-table (3.0.
|
|
231
|
+
terminal-table (3.0.2)
|
|
101
232
|
unicode-display_width (>= 1.1.1, < 3)
|
|
102
|
-
thor (1.1
|
|
103
|
-
|
|
233
|
+
thor (1.2.1)
|
|
234
|
+
timeout (0.3.0)
|
|
235
|
+
tins (1.31.1)
|
|
104
236
|
sync
|
|
105
237
|
tzinfo (2.0.4)
|
|
106
238
|
concurrent-ruby (~> 1.0)
|
|
107
|
-
unicode-display_width (2.
|
|
239
|
+
unicode-display_width (2.1.0)
|
|
108
240
|
webrick (1.7.0)
|
|
241
|
+
websocket-driver (0.7.5)
|
|
242
|
+
websocket-extensions (>= 0.1.0)
|
|
243
|
+
websocket-extensions (0.1.5)
|
|
109
244
|
with_progress (1.0.1)
|
|
110
245
|
ruby-progressbar (~> 1.4)
|
|
111
|
-
zeitwerk (2.
|
|
246
|
+
zeitwerk (2.6.0)
|
|
112
247
|
|
|
113
248
|
PLATFORMS
|
|
114
249
|
ruby
|
|
115
250
|
|
|
116
251
|
DEPENDENCIES
|
|
117
252
|
bundler (~> 2.0)
|
|
253
|
+
byebug
|
|
118
254
|
climate_control
|
|
119
255
|
codecov
|
|
120
256
|
deep-cover
|
|
121
257
|
promenade!
|
|
122
|
-
|
|
123
|
-
|
|
258
|
+
rails (> 3.0, < 8.0)
|
|
259
|
+
rake
|
|
260
|
+
rspec (~> 3.11)
|
|
261
|
+
rspec-rails (~> 5.1)
|
|
124
262
|
rubocop
|
|
125
263
|
rubocop-performance
|
|
126
264
|
rubocop-rails
|
|
@@ -128,4 +266,4 @@ DEPENDENCIES
|
|
|
128
266
|
webrick
|
|
129
267
|
|
|
130
268
|
BUNDLED WITH
|
|
131
|
-
2.
|
|
269
|
+
2.3.16
|
data/README.md
CHANGED
|
@@ -129,6 +129,72 @@ This is ideal if you are worried about accidentally exposing your metrics, are c
|
|
|
129
129
|
|
|
130
130
|
The exporter runs by default on port `9394` and the metrics are available at the standard path of `/metrics`, the stand-alone exporter is configured to use gzip.
|
|
131
131
|
|
|
132
|
+
|
|
133
|
+
### Rails Middleware
|
|
134
|
+
|
|
135
|
+
Promenade provides custom Rack middleware to track HTTP response times for requests in your Rails application.
|
|
136
|
+
|
|
137
|
+
This was originally inspired by [prometheus-client-mmap](https://gitlab.com/gitlab-org/prometheus-client-mmap/-/blob/master/lib/prometheus/client/rack/collector.rb).
|
|
138
|
+
|
|
139
|
+
**This middleware is automatically added to your Rack stack if your application is a Ruby on Rails app.**
|
|
140
|
+
|
|
141
|
+
We recommend you add the middleware after `ActionDispatch::ShowExceptions` in your stack, so you can accurately record the controller and action where an exception was raised.
|
|
142
|
+
|
|
143
|
+
If you want to change the position, or customise the labels and exception handling behaviour, simply remove the middleware from the stack and re-insert it with your own preferences.
|
|
144
|
+
|
|
145
|
+
``` ruby
|
|
146
|
+
Rails.application.middleware.delete(Promenade::Client::Rack::Collector)
|
|
147
|
+
Rails.application.middleware.insert_after(Rails::Rack::Logger, Promenade::Client::Rack::Collector)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### Customising the labels recorded for each request
|
|
151
|
+
|
|
152
|
+
If you would like to collect different labels with each request, you may do so by customising the middleware installation:
|
|
153
|
+
|
|
154
|
+
``` ruby
|
|
155
|
+
label_builder = Proc.new do |env|
|
|
156
|
+
{
|
|
157
|
+
method: env["REQUEST_METHOD"].to_s.downcase,
|
|
158
|
+
host: env["HTTP_HOST"].to_s,
|
|
159
|
+
controller: env.dig("action_dispatch.request.parameters", "controller") || "unknown",
|
|
160
|
+
action: env.dig("action_dispatch.request.parameters", "action") || "unknown"
|
|
161
|
+
}
|
|
162
|
+
end
|
|
163
|
+
Rails.application.config.middleware.insert_after ActionDispatch::ShowExceptions,
|
|
164
|
+
Promenade::Client::Rack::Collector
|
|
165
|
+
label_builder: label_builder
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### Customising how the middleware handles exceptions
|
|
169
|
+
|
|
170
|
+
The default implementation will capture exceptions, count the execption class name (e.g. `"StandardError"`), and then re-raise the exception.
|
|
171
|
+
|
|
172
|
+
If you would like to customise this behaviour, you may do so by customising the middleware installation:
|
|
173
|
+
|
|
174
|
+
``` ruby
|
|
175
|
+
exception_handler = Proc.new do |exception, exception_counter, env_hash, request_duration_seconds|
|
|
176
|
+
# This simple example just re-raises the execption
|
|
177
|
+
raise exception
|
|
178
|
+
end
|
|
179
|
+
Rails.application.config.middleware.insert_after ActionDispatch::ShowExceptions,
|
|
180
|
+
Promenade::Client::Rack::Collector
|
|
181
|
+
exception_handler: exception_handler
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### Customising the histogram buckets
|
|
185
|
+
|
|
186
|
+
The default buckets cover a range of latencies from 5 ms to 10s see [Promenade::Configuration::DEFAULT_RACK_LATENCY_BUCKETS](https://github.com/errm/promenade/blob/ea7eb54c04257770a601b7e28b3e13db5d2430bb/lib/promenade/configuration.rb#L5). This is intended to capture the typical range of latencies for a web application. However, this might not be suitable for your Service-Level Agreements (SLAs), and other bucket size intervals may be required (see [histogram bins](https://en.wikipedia.org/wiki/Histogram#Number_of_bins_and_width)).
|
|
187
|
+
|
|
188
|
+
If you would like to customise the histogram buckets, you can do so by configuring Promenade in an initializer:
|
|
189
|
+
|
|
190
|
+
```ruby
|
|
191
|
+
# config/initializers/promenade.rb
|
|
192
|
+
|
|
193
|
+
Promenade.configure do |config|
|
|
194
|
+
config.rack_latency_buckets = [0.25, 0.350, 0.5, 1, 1.5, 2.5, 5, 10, 15, 19]
|
|
195
|
+
end
|
|
196
|
+
```
|
|
197
|
+
|
|
132
198
|
### Configuration
|
|
133
199
|
|
|
134
200
|
If you are using rails it should load a railtie and configure promenade.
|
|
@@ -153,6 +219,10 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/errm/p
|
|
|
153
219
|
|
|
154
220
|
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
|
155
221
|
|
|
222
|
+
## Acknowledgements
|
|
223
|
+
|
|
224
|
+
The original code for the Rack middleware collector class was copied from [Prometheus Client MMap](https://gitlab.com/gitlab-org/prometheus-client-mmap/-/blob/master/lib/prometheus/client/rack/collector.rb).
|
|
225
|
+
|
|
156
226
|
## License
|
|
157
227
|
|
|
158
228
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/bin/integration_test
CHANGED
|
@@ -4,14 +4,23 @@ require "bundler/setup"
|
|
|
4
4
|
require "promenade"
|
|
5
5
|
require "fileutils"
|
|
6
6
|
require "net/http"
|
|
7
|
+
require "./spec/support/integration_tests/metrics_line"
|
|
8
|
+
require "./spec/support/integration_tests/label_value"
|
|
7
9
|
|
|
8
10
|
def test_http_body(expected)
|
|
11
|
+
expectation = MetricsLine.new(expected)
|
|
9
12
|
uri = URI("http://localhost:9394/metrics")
|
|
10
13
|
|
|
11
14
|
Net::HTTP.start(uri.host, uri.port) do |http|
|
|
12
15
|
request = Net::HTTP::Get.new uri
|
|
13
16
|
response = http.request request
|
|
14
|
-
|
|
17
|
+
unless response.body.each_line.detect do |string|
|
|
18
|
+
next if string.start_with?("#")
|
|
19
|
+
|
|
20
|
+
MetricsLine.new(string) == expectation
|
|
21
|
+
end
|
|
22
|
+
fail "#{response.body} didn't include #{expected}"
|
|
23
|
+
end
|
|
15
24
|
end
|
|
16
25
|
end
|
|
17
26
|
|
data/bin/rails
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# This command will automatically be run when you run "rails" with Rails gems
|
|
3
|
+
# installed from the root of your application.
|
|
4
|
+
|
|
5
|
+
ENGINE_ROOT = File.expand_path("..", __dir__)
|
|
6
|
+
ENGINE_PATH = File.expand_path("../lib/promenade/engine", __dir__)
|
|
7
|
+
APP_PATH = File.expand_path("../spec/dummy/config/application", __dir__)
|
|
8
|
+
|
|
9
|
+
# Set up gems listed in the Gemfile.
|
|
10
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
11
|
+
require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
|
|
12
|
+
|
|
13
|
+
require "rails/all"
|
|
14
|
+
require "rails/engine/commands"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require "action_dispatch/middleware/exception_wrapper"
|
|
2
|
+
require_relative "singleton_caller"
|
|
3
|
+
require_relative "request_labeler"
|
|
4
|
+
|
|
5
|
+
module Promenade
|
|
6
|
+
module Client
|
|
7
|
+
module Rack
|
|
8
|
+
class ExceptionHandler
|
|
9
|
+
extend SingletonCaller
|
|
10
|
+
|
|
11
|
+
attr_reader :histogram_name, :requests_counter_name, :exceptions_counter_name, :registry
|
|
12
|
+
|
|
13
|
+
def initialize(histogram_name:, requests_counter_name:, exceptions_counter_name:, registry:)
|
|
14
|
+
@histogram_name = histogram_name
|
|
15
|
+
@requests_counter_name = requests_counter_name
|
|
16
|
+
@exceptions_counter_name = exceptions_counter_name
|
|
17
|
+
@registry = registry
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call(exception, env_hash, duration)
|
|
21
|
+
labels = RequestLabeler.call(env_hash)
|
|
22
|
+
labels.merge!(code: status_code_for_exception(exception))
|
|
23
|
+
|
|
24
|
+
histogram.observe(labels, duration.to_f)
|
|
25
|
+
requests_counter.increment(labels)
|
|
26
|
+
exceptions_counter.increment(exception: exception.class.name)
|
|
27
|
+
|
|
28
|
+
raise exception
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def histogram
|
|
34
|
+
registry.get(histogram_name)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def requests_counter
|
|
38
|
+
registry.get(requests_counter_name)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def exceptions_counter
|
|
42
|
+
registry.get(exceptions_counter_name)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def status_code_for_exception(exception)
|
|
46
|
+
ActionDispatch::ExceptionWrapper.new(nil, exception).status_code.to_s
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
require "prometheus/client"
|
|
2
|
+
require_relative "middleware_base"
|
|
3
|
+
require_relative "request_labeler"
|
|
4
|
+
require_relative "exception_handler"
|
|
5
|
+
require_relative "queue_time_duration"
|
|
6
|
+
|
|
7
|
+
module Promenade
|
|
8
|
+
module Client
|
|
9
|
+
module Rack
|
|
10
|
+
class HTTPRequestDurationCollector < MiddlwareBase
|
|
11
|
+
REQUEST_DURATION_HISTOGRAM_NAME = :http_req_duration_seconds
|
|
12
|
+
|
|
13
|
+
REQUESTS_COUNTER_NAME = :http_requests_total
|
|
14
|
+
|
|
15
|
+
EXCEPTIONS_COUNTER_NAME = :http_exceptions_total
|
|
16
|
+
|
|
17
|
+
private_constant :REQUEST_DURATION_HISTOGRAM_NAME,
|
|
18
|
+
:REQUESTS_COUNTER_NAME,
|
|
19
|
+
:EXCEPTIONS_COUNTER_NAME
|
|
20
|
+
|
|
21
|
+
def initialize(app,
|
|
22
|
+
registry: ::Prometheus::Client.registry,
|
|
23
|
+
label_builder: RequestLabeler,
|
|
24
|
+
exception_handler: nil)
|
|
25
|
+
|
|
26
|
+
@latency_buckets = Promenade.configuration.rack_latency_buckets
|
|
27
|
+
@_exception_handler = exception_handler
|
|
28
|
+
|
|
29
|
+
super(app, registry: registry, label_builder: label_builder)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
attr_reader :latency_buckets, :queue_time_buckets
|
|
35
|
+
|
|
36
|
+
def trace(env)
|
|
37
|
+
start = current_time
|
|
38
|
+
begin
|
|
39
|
+
response = yield
|
|
40
|
+
record_request_duration(labels(env, response), duration_since(start))
|
|
41
|
+
response
|
|
42
|
+
rescue StandardError => e
|
|
43
|
+
exception_handler.call(e, env, duration_since(start))
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def record_request_duration(labels, duration)
|
|
48
|
+
requests_counter.increment(labels)
|
|
49
|
+
durations_histogram.observe(labels, duration)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def duration_since(start_time)
|
|
53
|
+
current_time - start_time
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def current_time
|
|
57
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def durations_histogram
|
|
61
|
+
registry.get(REQUEST_DURATION_HISTOGRAM_NAME)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def requests_counter
|
|
65
|
+
registry.get(REQUESTS_COUNTER_NAME)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def register_metrics!
|
|
69
|
+
registry.counter(REQUESTS_COUNTER_NAME,
|
|
70
|
+
"A counter of the total number of HTTP requests made.")
|
|
71
|
+
registry.histogram(REQUEST_DURATION_HISTOGRAM_NAME,
|
|
72
|
+
"A histogram of the response latency.", {}, latency_buckets)
|
|
73
|
+
registry.counter(EXCEPTIONS_COUNTER_NAME,
|
|
74
|
+
"A counter of the total number of exceptions raised.")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def exception_handler
|
|
78
|
+
@_exception_handler ||= default_exception_handler
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def default_exception_handler
|
|
82
|
+
ExceptionHandler.initialize_singleton(
|
|
83
|
+
histogram_name: REQUEST_DURATION_HISTOGRAM_NAME,
|
|
84
|
+
requests_counter_name: REQUESTS_COUNTER_NAME,
|
|
85
|
+
exceptions_counter_name: EXCEPTIONS_COUNTER_NAME,
|
|
86
|
+
registry: registry,
|
|
87
|
+
)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require "prometheus/client"
|
|
2
|
+
require_relative "middleware_base"
|
|
3
|
+
require_relative "request_labeler"
|
|
4
|
+
require_relative "queue_time_duration"
|
|
5
|
+
|
|
6
|
+
module Promenade
|
|
7
|
+
module Client
|
|
8
|
+
module Rack
|
|
9
|
+
class HTTPRequestQueueTimeCollector < MiddlwareBase
|
|
10
|
+
REQUEST_QUEUE_TIME_HISTOGRAM_NAME = :http_req_queue_time_seconds
|
|
11
|
+
|
|
12
|
+
private_constant :REQUEST_QUEUE_TIME_HISTOGRAM_NAME
|
|
13
|
+
|
|
14
|
+
def initialize(app,
|
|
15
|
+
registry: ::Prometheus::Client.registry,
|
|
16
|
+
label_builder: RequestLabeler)
|
|
17
|
+
|
|
18
|
+
@queue_time_buckets = Promenade.configuration.queue_time_buckets
|
|
19
|
+
|
|
20
|
+
super(app, registry: registry, label_builder: label_builder)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
attr_reader :queue_time_buckets
|
|
26
|
+
|
|
27
|
+
def trace(env)
|
|
28
|
+
start_timestamp = Time.now.utc
|
|
29
|
+
response = yield
|
|
30
|
+
record_request_queue_time(labels: labels(env, response),
|
|
31
|
+
env: env,
|
|
32
|
+
request_received_time: start_timestamp)
|
|
33
|
+
response
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def record_request_queue_time(labels:, env:, request_received_time:)
|
|
37
|
+
request_queue_duration = QueueTimeDuration.new(env: env,
|
|
38
|
+
request_received_time: request_received_time)
|
|
39
|
+
return unless request_queue_duration.valid_header_present?
|
|
40
|
+
|
|
41
|
+
queue_time_histogram.observe(labels, request_queue_duration.queue_time_seconds)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def register_metrics!
|
|
45
|
+
registry.histogram(REQUEST_QUEUE_TIME_HISTOGRAM_NAME,
|
|
46
|
+
"A histogram of request queue time", {}, queue_time_buckets)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def queue_time_histogram
|
|
50
|
+
registry.get(REQUEST_QUEUE_TIME_HISTOGRAM_NAME)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Promenade
|
|
2
|
+
module Client
|
|
3
|
+
module Rack
|
|
4
|
+
class MiddlwareBase
|
|
5
|
+
def initialize(app, registry:, label_builder:)
|
|
6
|
+
@app = app
|
|
7
|
+
@registry = registry
|
|
8
|
+
@label_builder = label_builder
|
|
9
|
+
|
|
10
|
+
register_metrics!
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call(env)
|
|
14
|
+
trace(env) { app.call(env) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
attr_reader :app, :label_builder, :registry
|
|
20
|
+
|
|
21
|
+
def trace(env)
|
|
22
|
+
raise NotImplementedError,
|
|
23
|
+
"Please define #{__method__} in #{self.class}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def labels(env, response)
|
|
27
|
+
label_builder.call(env).merge!(code: response.first.to_s)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def register_metrics!
|
|
31
|
+
# :noop:
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Promenade
|
|
2
|
+
module Client
|
|
3
|
+
module Rack
|
|
4
|
+
class QueueTimeDuration
|
|
5
|
+
REQUEST_START_HEADER = "HTTP_X_REQUEST_START".freeze
|
|
6
|
+
|
|
7
|
+
QUEUE_START_HEADER = "HTTP_X_QUEUE_START".freeze
|
|
8
|
+
|
|
9
|
+
HEADER_VALUE_MATCHER = /^(?:t=)(?<timestamp>\d{10}(?:\.\d+))$/.freeze
|
|
10
|
+
|
|
11
|
+
def initialize(env:, request_received_time:)
|
|
12
|
+
@env = env
|
|
13
|
+
@request_queued_time_ms = extract_request_queued_time_from_env(env)
|
|
14
|
+
@valid_header_present = @request_queued_time_ms.is_a?(Float)
|
|
15
|
+
@request_received_time_ms = request_received_time.utc.to_f
|
|
16
|
+
|
|
17
|
+
freeze
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def valid_header_present?
|
|
21
|
+
@valid_header_present
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def queue_time_seconds
|
|
25
|
+
return unless valid_header_present?
|
|
26
|
+
|
|
27
|
+
queue_time.round(3)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
attr_reader :env, :request_queued_time_ms, :request_received_time_ms
|
|
33
|
+
|
|
34
|
+
def queue_time
|
|
35
|
+
request_received_time_ms - request_queued_time_ms
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def extract_request_queued_time_from_env(env_hash)
|
|
39
|
+
header_value = env_hash[REQUEST_START_HEADER] || env_hash[QUEUE_START_HEADER]
|
|
40
|
+
return if header_value.nil?
|
|
41
|
+
|
|
42
|
+
header_time_match = header_value.to_s.match(HEADER_VALUE_MATCHER)
|
|
43
|
+
return unless header_time_match
|
|
44
|
+
|
|
45
|
+
header_time_match[:timestamp].to_f
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Promenade
|
|
2
|
+
module Client
|
|
3
|
+
module Rack
|
|
4
|
+
class RequestLabeler
|
|
5
|
+
require_relative "singleton_caller"
|
|
6
|
+
extend SingletonCaller
|
|
7
|
+
|
|
8
|
+
REQUEST_METHOD = "REQUEST_METHOD".freeze
|
|
9
|
+
|
|
10
|
+
HTTP_HOST = "HTTP_HOST".freeze
|
|
11
|
+
|
|
12
|
+
PARAMS_KEY = "action_dispatch.request.parameters".freeze
|
|
13
|
+
|
|
14
|
+
PATH_PARAMS_KEY = "action_dispatch.request.path_parameters".freeze
|
|
15
|
+
|
|
16
|
+
CONTROLLER = "controller".freeze
|
|
17
|
+
|
|
18
|
+
ACTION = "action".freeze
|
|
19
|
+
|
|
20
|
+
UNKNOWN = "unknown".freeze
|
|
21
|
+
|
|
22
|
+
SEPARATOR = "#".freeze
|
|
23
|
+
|
|
24
|
+
private_constant :REQUEST_METHOD, :HTTP_HOST, :PARAMS_KEY, :CONTROLLER, :ACTION, :UNKNOWN, :SEPARATOR
|
|
25
|
+
|
|
26
|
+
def call(env)
|
|
27
|
+
{
|
|
28
|
+
method: env[REQUEST_METHOD].to_s.downcase,
|
|
29
|
+
host: env[HTTP_HOST].to_s,
|
|
30
|
+
controller_action: controller_action_from_env(env),
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def controller_action_from_env(env)
|
|
37
|
+
controller = env.dig(PARAMS_KEY, CONTROLLER) ||
|
|
38
|
+
env.dig(PATH_PARAMS_KEY, CONTROLLER.to_sym) ||
|
|
39
|
+
UNKNOWN
|
|
40
|
+
|
|
41
|
+
action = env.dig(PARAMS_KEY, ACTION) ||
|
|
42
|
+
env.dig(PATH_PARAMS_KEY, ACTION.to_sym) ||
|
|
43
|
+
UNKNOWN
|
|
44
|
+
|
|
45
|
+
[controller, action].join(SEPARATOR)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Promenade
|
|
2
|
+
module Client
|
|
3
|
+
module Rack
|
|
4
|
+
module SingletonCaller
|
|
5
|
+
def initialize_singleton(...)
|
|
6
|
+
@singleton = new(...)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def call(...)
|
|
10
|
+
singleton.call(...)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def singleton
|
|
14
|
+
@singleton || initialize_singleton
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Promenade
|
|
2
|
+
class Configuration
|
|
3
|
+
attr_accessor :queue_time_buckets, :rack_latency_buckets
|
|
4
|
+
|
|
5
|
+
DEFAULT_RACK_LATENCY_BUCKETS = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10].freeze
|
|
6
|
+
|
|
7
|
+
DEFAULT_QUEUE_TIME_BUCKETS = [0.01, 0.5, 1.0, 10.0, 30.0].freeze
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@rack_latency_buckets = DEFAULT_RACK_LATENCY_BUCKETS
|
|
11
|
+
@queue_time_buckets = DEFAULT_QUEUE_TIME_BUCKETS
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/lib/promenade/prometheus.rb
CHANGED
data/lib/promenade/railtie.rb
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
require "promenade/setup"
|
|
2
|
+
require "promenade/engine"
|
|
3
|
+
require "promenade/client/rack/http_request_duration_collector"
|
|
4
|
+
require "promenade/client/rack/http_request_queue_time_collector"
|
|
2
5
|
|
|
3
6
|
module Promenade
|
|
4
7
|
class Railtie < ::Rails::Railtie
|
|
5
8
|
initializer "promenade.configure_rails_initialization" do
|
|
6
9
|
Promenade.setup
|
|
10
|
+
Rails.application.config.middleware.insert_after ActionDispatch::ShowExceptions,
|
|
11
|
+
Promenade::Client::Rack::HTTPRequestDurationCollector
|
|
12
|
+
Rails.application.config.middleware.insert 0,
|
|
13
|
+
Promenade::Client::Rack::HTTPRequestQueueTimeCollector
|
|
7
14
|
end
|
|
8
15
|
end
|
|
9
16
|
end
|
data/lib/promenade/setup.rb
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
require "pathname"
|
|
2
2
|
|
|
3
3
|
module Promenade
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
module_function
|
|
5
|
+
|
|
6
|
+
def root_dir
|
|
7
|
+
if rails_defined?
|
|
8
|
+
Rails.root
|
|
9
|
+
else
|
|
10
|
+
Pathname.new(ENV.fetch("RAILS_ROOT", Dir.pwd))
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def rails_defined?
|
|
15
|
+
defined?(Rails)
|
|
7
16
|
end
|
|
8
17
|
|
|
9
|
-
def
|
|
18
|
+
def multiprocess_files_dir
|
|
10
19
|
ENV.fetch("PROMETHEUS_MULTIPROC_DIR", root_dir.join("tmp", "promenade"))
|
|
11
20
|
end
|
|
12
21
|
|
|
13
|
-
def
|
|
22
|
+
def setup
|
|
14
23
|
unless File.directory? multiprocess_files_dir
|
|
15
24
|
FileUtils.mkdir_p multiprocess_files_dir
|
|
16
25
|
end
|
data/lib/promenade/version.rb
CHANGED
data/lib/promenade.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require "promenade/version"
|
|
2
2
|
require "promenade/setup"
|
|
3
|
+
require "promenade/configuration"
|
|
3
4
|
require "promenade/railtie" if defined? ::Rails::Railtie
|
|
4
5
|
require "promenade/prometheus"
|
|
5
6
|
|
|
@@ -14,5 +15,13 @@ module Promenade
|
|
|
14
15
|
def metric(name)
|
|
15
16
|
Promenade::Prometheus.metric(name)
|
|
16
17
|
end
|
|
18
|
+
|
|
19
|
+
def configuration
|
|
20
|
+
@_configuration ||= Configuration.new
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def configure
|
|
24
|
+
yield(configuration)
|
|
25
|
+
end
|
|
17
26
|
end
|
|
18
27
|
end
|
data/promenade.gemspec
CHANGED
|
@@ -22,19 +22,23 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
|
|
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
23
23
|
spec.require_paths = ["lib"]
|
|
24
24
|
|
|
25
|
-
spec.required_ruby_version = ">= 2.
|
|
25
|
+
spec.required_ruby_version = ">= 2.7", "< 3.2"
|
|
26
26
|
|
|
27
|
-
spec.add_dependency "
|
|
28
|
-
spec.add_dependency "
|
|
27
|
+
spec.add_dependency "actionpack"
|
|
28
|
+
spec.add_dependency "activesupport", "> 6.0", "< 8.0"
|
|
29
|
+
spec.add_dependency "prometheus-client-mmap", "~> 0.16.0"
|
|
29
30
|
spec.add_dependency "rack"
|
|
30
|
-
|
|
31
31
|
spec.add_development_dependency "bundler", "~> 2.0"
|
|
32
|
+
spec.add_development_dependency "byebug"
|
|
32
33
|
spec.add_development_dependency "climate_control"
|
|
33
34
|
spec.add_development_dependency "deep-cover"
|
|
34
|
-
spec.add_development_dependency "
|
|
35
|
-
spec.add_development_dependency "
|
|
35
|
+
spec.add_development_dependency "rails", "> 3.0", "< 8.0"
|
|
36
|
+
spec.add_development_dependency "rake"
|
|
37
|
+
spec.add_development_dependency "rspec", "~> 3.11"
|
|
38
|
+
spec.add_development_dependency "rspec-rails", "~> 5.1"
|
|
36
39
|
spec.add_development_dependency "rubocop"
|
|
37
40
|
spec.add_development_dependency "rubocop-performance"
|
|
38
41
|
spec.add_development_dependency "rubocop-rails"
|
|
39
42
|
spec.add_development_dependency "simplecov"
|
|
43
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
40
44
|
end
|
metadata
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: promenade
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ed Robinson
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-08-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: actionpack
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
@@ -24,20 +24,40 @@ dependencies:
|
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: activesupport
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '6.0'
|
|
34
|
+
- - "<"
|
|
35
|
+
- !ruby/object:Gem::Version
|
|
36
|
+
version: '8.0'
|
|
37
|
+
type: :runtime
|
|
38
|
+
prerelease: false
|
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - ">"
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '6.0'
|
|
44
|
+
- - "<"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '8.0'
|
|
27
47
|
- !ruby/object:Gem::Dependency
|
|
28
48
|
name: prometheus-client-mmap
|
|
29
49
|
requirement: !ruby/object:Gem::Requirement
|
|
30
50
|
requirements:
|
|
31
51
|
- - "~>"
|
|
32
52
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: 0.
|
|
53
|
+
version: 0.16.0
|
|
34
54
|
type: :runtime
|
|
35
55
|
prerelease: false
|
|
36
56
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
57
|
requirements:
|
|
38
58
|
- - "~>"
|
|
39
59
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: 0.
|
|
60
|
+
version: 0.16.0
|
|
41
61
|
- !ruby/object:Gem::Dependency
|
|
42
62
|
name: rack
|
|
43
63
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -66,6 +86,20 @@ dependencies:
|
|
|
66
86
|
- - "~>"
|
|
67
87
|
- !ruby/object:Gem::Version
|
|
68
88
|
version: '2.0'
|
|
89
|
+
- !ruby/object:Gem::Dependency
|
|
90
|
+
name: byebug
|
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0'
|
|
96
|
+
type: :development
|
|
97
|
+
prerelease: false
|
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0'
|
|
69
103
|
- !ruby/object:Gem::Dependency
|
|
70
104
|
name: climate_control
|
|
71
105
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -94,34 +128,68 @@ dependencies:
|
|
|
94
128
|
- - ">="
|
|
95
129
|
- !ruby/object:Gem::Version
|
|
96
130
|
version: '0'
|
|
131
|
+
- !ruby/object:Gem::Dependency
|
|
132
|
+
name: rails
|
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - ">"
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '3.0'
|
|
138
|
+
- - "<"
|
|
139
|
+
- !ruby/object:Gem::Version
|
|
140
|
+
version: '8.0'
|
|
141
|
+
type: :development
|
|
142
|
+
prerelease: false
|
|
143
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
144
|
+
requirements:
|
|
145
|
+
- - ">"
|
|
146
|
+
- !ruby/object:Gem::Version
|
|
147
|
+
version: '3.0'
|
|
148
|
+
- - "<"
|
|
149
|
+
- !ruby/object:Gem::Version
|
|
150
|
+
version: '8.0'
|
|
97
151
|
- !ruby/object:Gem::Dependency
|
|
98
152
|
name: rake
|
|
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'
|
|
165
|
+
- !ruby/object:Gem::Dependency
|
|
166
|
+
name: rspec
|
|
99
167
|
requirement: !ruby/object:Gem::Requirement
|
|
100
168
|
requirements:
|
|
101
169
|
- - "~>"
|
|
102
170
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '
|
|
171
|
+
version: '3.11'
|
|
104
172
|
type: :development
|
|
105
173
|
prerelease: false
|
|
106
174
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
175
|
requirements:
|
|
108
176
|
- - "~>"
|
|
109
177
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '
|
|
178
|
+
version: '3.11'
|
|
111
179
|
- !ruby/object:Gem::Dependency
|
|
112
|
-
name: rspec
|
|
180
|
+
name: rspec-rails
|
|
113
181
|
requirement: !ruby/object:Gem::Requirement
|
|
114
182
|
requirements:
|
|
115
183
|
- - "~>"
|
|
116
184
|
- !ruby/object:Gem::Version
|
|
117
|
-
version: '
|
|
185
|
+
version: '5.1'
|
|
118
186
|
type: :development
|
|
119
187
|
prerelease: false
|
|
120
188
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
189
|
requirements:
|
|
122
190
|
- - "~>"
|
|
123
191
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: '
|
|
192
|
+
version: '5.1'
|
|
125
193
|
- !ruby/object:Gem::Dependency
|
|
126
194
|
name: rubocop
|
|
127
195
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -199,9 +267,19 @@ files:
|
|
|
199
267
|
- Rakefile
|
|
200
268
|
- bin/console
|
|
201
269
|
- bin/integration_test
|
|
270
|
+
- bin/rails
|
|
202
271
|
- bin/setup
|
|
203
272
|
- exe/promenade
|
|
204
273
|
- lib/promenade.rb
|
|
274
|
+
- lib/promenade/client/rack/exception_handler.rb
|
|
275
|
+
- lib/promenade/client/rack/http_request_duration_collector.rb
|
|
276
|
+
- lib/promenade/client/rack/http_request_queue_time_collector.rb
|
|
277
|
+
- lib/promenade/client/rack/middleware_base.rb
|
|
278
|
+
- lib/promenade/client/rack/queue_time_duration.rb
|
|
279
|
+
- lib/promenade/client/rack/request_labeler.rb
|
|
280
|
+
- lib/promenade/client/rack/singleton_caller.rb
|
|
281
|
+
- lib/promenade/configuration.rb
|
|
282
|
+
- lib/promenade/engine.rb
|
|
205
283
|
- lib/promenade/kafka.rb
|
|
206
284
|
- lib/promenade/kafka/async_producer_subscriber.rb
|
|
207
285
|
- lib/promenade/kafka/connection_subscriber.rb
|
|
@@ -217,7 +295,8 @@ files:
|
|
|
217
295
|
homepage: https://github.com/errm/promenade
|
|
218
296
|
licenses:
|
|
219
297
|
- MIT
|
|
220
|
-
metadata:
|
|
298
|
+
metadata:
|
|
299
|
+
rubygems_mfa_required: 'true'
|
|
221
300
|
post_install_message:
|
|
222
301
|
rdoc_options: []
|
|
223
302
|
require_paths:
|
|
@@ -226,17 +305,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
226
305
|
requirements:
|
|
227
306
|
- - ">="
|
|
228
307
|
- !ruby/object:Gem::Version
|
|
229
|
-
version: '2.
|
|
308
|
+
version: '2.7'
|
|
230
309
|
- - "<"
|
|
231
310
|
- !ruby/object:Gem::Version
|
|
232
|
-
version: '
|
|
311
|
+
version: '3.2'
|
|
233
312
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
234
313
|
requirements:
|
|
235
314
|
- - ">="
|
|
236
315
|
- !ruby/object:Gem::Version
|
|
237
316
|
version: '0'
|
|
238
317
|
requirements: []
|
|
239
|
-
rubygems_version: 3.
|
|
318
|
+
rubygems_version: 3.3.18
|
|
240
319
|
signing_key:
|
|
241
320
|
specification_version: 4
|
|
242
321
|
summary: Promenade makes it simple to instrument Ruby apps for prometheus scraping
|