prometheus_client_addons 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +273 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/prometheus_client_addons.rb +9 -0
- data/lib/prometheus_client_addons/prometheus/client/active_record.rb +34 -0
- data/lib/prometheus_client_addons/prometheus/client/custom_collector.rb +26 -0
- data/lib/prometheus_client_addons/prometheus/client/fake_gauge.rb +17 -0
- data/lib/prometheus_client_addons/prometheus/client/formats/text_extended.rb +48 -0
- data/lib/prometheus_client_addons/prometheus/client/gc.rb +54 -0
- data/lib/prometheus_client_addons/prometheus/client/multi_metric.rb +38 -0
- data/lib/prometheus_client_addons/prometheus/client/puma.rb +97 -0
- data/lib/prometheus_client_addons/puma/plugin/prometheus_client_addons.rb +19 -0
- data/lib/prometheus_client_addons/version.rb +3 -0
- data/prometheus_client_addons.gemspec +38 -0
- metadata +136 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e92df93c0d837d7a85176aaf94e7c954f4eb1de51e0f0f7f87341414514e614b
|
4
|
+
data.tar.gz: 80329fa945177a4acabfca5be1caacfc4f57b6dcbc6d567a8a92bd6f14391d57
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fb58dc08009041432e37ff55b1e3a14cbbb36ee9545154671ad1ea1dae62bfece3544c016601c49348984c7da12878e10e9d6adfefa04179446e7b5849981eb0
|
7
|
+
data.tar.gz: df185a4b8b278471a3c4e49d9e96e17daca4050e5eb3a34548589b96721425507b03ee227eeea2c2fd0a9173178e66e8b62e903353b65ece62308b8e333c4f9f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 kraaaken
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,273 @@
|
|
1
|
+
# Prometheus Ruby Client Addons
|
2
|
+
|
3
|
+
## Usage (with Rails)
|
4
|
+
|
5
|
+
### Puma server
|
6
|
+
|
7
|
+
config/initializers/prometheus.rb
|
8
|
+
```ruby
|
9
|
+
require 'prometheus/client'
|
10
|
+
require 'prometheus_client_addons'
|
11
|
+
|
12
|
+
prometheus = Prometheus::Client.registry
|
13
|
+
puma = PrometheusClientAddons::Prometheus::Client::Puma.new(
|
14
|
+
prefix: 'puma',
|
15
|
+
base_labels: { my_label: 'baz' }
|
16
|
+
)
|
17
|
+
prometheus.register(puma)
|
18
|
+
```
|
19
|
+
|
20
|
+
config/puma.rb
|
21
|
+
```ruby
|
22
|
+
activate_control_app('auto')
|
23
|
+
plugin :prometheus_client_addons
|
24
|
+
```
|
25
|
+
|
26
|
+
Example response in non-clustered mode
|
27
|
+
```
|
28
|
+
# TYPE puma_backlog gauge
|
29
|
+
# HELP puma_backlog How many requests are waiting
|
30
|
+
puma_backlog{my_label="baz"} 0
|
31
|
+
# TYPE puma_running gauge
|
32
|
+
# HELP puma_running Number of running threads
|
33
|
+
puma_running{my_label="baz"} 5
|
34
|
+
# TYPE puma_pool_capacity gauge
|
35
|
+
# HELP puma_pool_capacity Number of requests that can be processed right now
|
36
|
+
puma_pool_capacity{my_label="baz"} 4
|
37
|
+
# TYPE puma_max_threads gauge
|
38
|
+
# HELP puma_max_threads Maximum number of worker threads
|
39
|
+
puma_max_threads{my_label="baz"} 5
|
40
|
+
```
|
41
|
+
|
42
|
+
Example response in clustered mode
|
43
|
+
```
|
44
|
+
# TYPE puma_workers gauge
|
45
|
+
# HELP puma_workers Number of workers
|
46
|
+
puma_workers{my_label="baz"} 2
|
47
|
+
# TYPE puma_phase gauge
|
48
|
+
# HELP puma_phase Phase of worker
|
49
|
+
puma_phase{my_label="baz"} 0
|
50
|
+
# TYPE puma_booted_workers gauge
|
51
|
+
# HELP puma_booted_workers Number of booted workers
|
52
|
+
puma_booted_workers{my_label="baz"} 2
|
53
|
+
# TYPE puma_old_workers gauge
|
54
|
+
# HELP puma_old_workers Number of old workers
|
55
|
+
puma_old_workers{my_label="baz"} 0
|
56
|
+
# TYPE puma_worker_status_phase gauge
|
57
|
+
# HELP puma_worker_status_phase Phase of worker
|
58
|
+
puma_worker_status_phase{my_label="baz",worker_index="0"} 0
|
59
|
+
puma_worker_status_phase{my_label="baz",worker_index="1"} 0
|
60
|
+
# TYPE puma_worker_status_booted gauge
|
61
|
+
# HELP puma_worker_status_booted Booted or not
|
62
|
+
puma_worker_status_booted{my_label="baz",worker_index="0"} true
|
63
|
+
puma_worker_status_booted{my_label="baz",worker_index="1"} true
|
64
|
+
# TYPE puma_worker_status_last_checkin gauge
|
65
|
+
# HELP puma_worker_status_last_checkin Last update
|
66
|
+
puma_worker_status_last_checkin{my_label="baz",worker_index="0"} 2019-09-04T15:01:33Z
|
67
|
+
puma_worker_status_last_checkin{my_label="baz",worker_index="1"} 2019-09-04T15:01:33Z
|
68
|
+
# TYPE puma_worker_status_last_status_backlog gauge
|
69
|
+
# HELP puma_worker_status_last_status_backlog How many objects have yet to be processed by the pool
|
70
|
+
puma_worker_status_last_status_backlog{my_label="baz",worker_index="0"} 0
|
71
|
+
puma_worker_status_last_status_backlog{my_label="baz",worker_index="1"} 0
|
72
|
+
# TYPE puma_worker_status_last_status_running gauge
|
73
|
+
# HELP puma_worker_status_last_status_running Number of running threads
|
74
|
+
puma_worker_status_last_status_running{my_label="baz",worker_index="0"} 5
|
75
|
+
puma_worker_status_last_status_running{my_label="baz",worker_index="1"} 5
|
76
|
+
# TYPE puma_worker_status_last_status_pool_capacity gauge
|
77
|
+
# HELP puma_worker_status_last_status_pool_capacity Number of requests that can be processed right now
|
78
|
+
puma_worker_status_last_status_pool_capacity{my_label="baz",worker_index="0"} 5
|
79
|
+
puma_worker_status_last_status_pool_capacity{my_label="baz",worker_index="1"} 5
|
80
|
+
# TYPE puma_worker_status_last_status_max_threads gauge
|
81
|
+
# HELP puma_worker_status_last_status_max_threads Maximum number of worker threads
|
82
|
+
puma_worker_status_last_status_max_threads{my_label="baz",worker_index="0"} 5
|
83
|
+
puma_worker_status_last_status_max_threads{my_label="baz",worker_index="1"} 5
|
84
|
+
```
|
85
|
+
|
86
|
+
### ActiveRecord::Base.connection_pool.stat
|
87
|
+
|
88
|
+
*Now it's not working with pre-forked/clustered-mode web servers. Sorry.*
|
89
|
+
|
90
|
+
config/initializers/prometheus.rb
|
91
|
+
```ruby
|
92
|
+
require 'prometheus/client'
|
93
|
+
require 'prometheus_client_addons'
|
94
|
+
|
95
|
+
prometheus = Prometheus::Client.registry
|
96
|
+
pool = PrometheusClientAddons::Prometheus::Client::ActiveRecord.new(
|
97
|
+
prefix: 'activerecord',
|
98
|
+
base_labels: { my_label: 'foo' }
|
99
|
+
)
|
100
|
+
prometheus.register(pool)
|
101
|
+
```
|
102
|
+
|
103
|
+
Example response
|
104
|
+
```
|
105
|
+
# TYPE activerecord_size gauge
|
106
|
+
# HELP activerecord_size Size of pool
|
107
|
+
activerecord_size{my_label="foo"} 5
|
108
|
+
# TYPE activerecord_connections gauge
|
109
|
+
# HELP activerecord_connections Connections count
|
110
|
+
activerecord_connections{my_label="foo"} 0
|
111
|
+
# TYPE activerecord_busy gauge
|
112
|
+
# HELP activerecord_busy Busy count
|
113
|
+
activerecord_busy{my_label="foo"} 0
|
114
|
+
# TYPE activerecord_dead gauge
|
115
|
+
# HELP activerecord_dead Dead count
|
116
|
+
activerecord_dead{my_label="foo"} 0
|
117
|
+
# TYPE activerecord_idle gauge
|
118
|
+
# HELP activerecord_idle Idle count
|
119
|
+
activerecord_idle{my_label="foo"} 0
|
120
|
+
# TYPE activerecord_waiting gauge
|
121
|
+
# HELP activerecord_waiting Num waiting in queue
|
122
|
+
activerecord_waiting{my_label="foo"} 0
|
123
|
+
# TYPE activerecord_checkout_timeout gauge
|
124
|
+
# HELP activerecord_checkout_timeout Checkout timeout
|
125
|
+
activerecord_checkout_timeout{my_label="foo"} 5
|
126
|
+
```
|
127
|
+
|
128
|
+
### GC.stat
|
129
|
+
|
130
|
+
config/initializers/prometheus.rb
|
131
|
+
```ruby
|
132
|
+
require 'prometheus/client'
|
133
|
+
require 'prometheus_client_addons'
|
134
|
+
|
135
|
+
prometheus = Prometheus::Client.registry
|
136
|
+
gc = PrometheusClientAddons::Prometheus::Client::GC.new(
|
137
|
+
prefix: 'gc',
|
138
|
+
base_labels: { my_label: 'foo' }
|
139
|
+
)
|
140
|
+
prometheus.register(gc)
|
141
|
+
```
|
142
|
+
|
143
|
+
Example response
|
144
|
+
```
|
145
|
+
# TYPE gc_count gauge
|
146
|
+
# HELP gc_count count
|
147
|
+
gc_count{my_label="foo"} 62
|
148
|
+
# TYPE gc_heap_allocated_pages gauge
|
149
|
+
# HELP gc_heap_allocated_pages heap_allocated_pages
|
150
|
+
gc_heap_allocated_pages{my_label="foo"} 3593
|
151
|
+
# TYPE gc_heap_sorted_length gauge
|
152
|
+
# HELP gc_heap_sorted_length heap_sorted_length
|
153
|
+
gc_heap_sorted_length{my_label="foo"} 3593
|
154
|
+
# TYPE gc_heap_allocatable_pages gauge
|
155
|
+
# HELP gc_heap_allocatable_pages heap_allocatable_pages
|
156
|
+
gc_heap_allocatable_pages{my_label="foo"} 0
|
157
|
+
# TYPE gc_heap_available_slots gauge
|
158
|
+
# HELP gc_heap_available_slots heap_available_slots
|
159
|
+
gc_heap_available_slots{my_label="foo"} 1464501
|
160
|
+
# TYPE gc_heap_live_slots gauge
|
161
|
+
# HELP gc_heap_live_slots heap_live_slots
|
162
|
+
gc_heap_live_slots{my_label="foo"} 1464445
|
163
|
+
# TYPE gc_heap_free_slots gauge
|
164
|
+
# HELP gc_heap_free_slots heap_free_slots
|
165
|
+
gc_heap_free_slots{my_label="foo"} 56
|
166
|
+
# TYPE gc_heap_final_slots gauge
|
167
|
+
# HELP gc_heap_final_slots heap_final_slots
|
168
|
+
gc_heap_final_slots{my_label="foo"} 0
|
169
|
+
# TYPE gc_heap_marked_slots gauge
|
170
|
+
# HELP gc_heap_marked_slots heap_marked_slots
|
171
|
+
gc_heap_marked_slots{my_label="foo"} 999525
|
172
|
+
# TYPE gc_heap_eden_pages gauge
|
173
|
+
# HELP gc_heap_eden_pages heap_eden_pages
|
174
|
+
gc_heap_eden_pages{my_label="foo"} 3593
|
175
|
+
# TYPE gc_heap_tomb_pages gauge
|
176
|
+
# HELP gc_heap_tomb_pages heap_tomb_pages
|
177
|
+
gc_heap_tomb_pages{my_label="foo"} 0
|
178
|
+
# TYPE gc_total_allocated_pages gauge
|
179
|
+
# HELP gc_total_allocated_pages total_allocated_pages
|
180
|
+
gc_total_allocated_pages{my_label="foo"} 3593
|
181
|
+
# TYPE gc_total_freed_pages gauge
|
182
|
+
# HELP gc_total_freed_pages total_freed_pages
|
183
|
+
gc_total_freed_pages{my_label="foo"} 0
|
184
|
+
# TYPE gc_total_allocated_objects gauge
|
185
|
+
# HELP gc_total_allocated_objects total_allocated_objects
|
186
|
+
gc_total_allocated_objects{my_label="foo"} 4665284
|
187
|
+
# TYPE gc_total_freed_objects gauge
|
188
|
+
# HELP gc_total_freed_objects total_freed_objects
|
189
|
+
gc_total_freed_objects{my_label="foo"} 3200839
|
190
|
+
# TYPE gc_malloc_increase_bytes gauge
|
191
|
+
# HELP gc_malloc_increase_bytes malloc_increase_bytes
|
192
|
+
gc_malloc_increase_bytes{my_label="foo"} 16693664
|
193
|
+
# TYPE gc_malloc_increase_bytes_limit gauge
|
194
|
+
# HELP gc_malloc_increase_bytes_limit malloc_increase_bytes_limit
|
195
|
+
gc_malloc_increase_bytes_limit{my_label="foo"} 30330547
|
196
|
+
# TYPE gc_minor_gc_count gauge
|
197
|
+
# HELP gc_minor_gc_count minor_gc_count
|
198
|
+
gc_minor_gc_count{my_label="foo"} 48
|
199
|
+
# TYPE gc_major_gc_count gauge
|
200
|
+
# HELP gc_major_gc_count major_gc_count
|
201
|
+
gc_major_gc_count{my_label="foo"} 14
|
202
|
+
# TYPE gc_remembered_wb_unprotected_objects gauge
|
203
|
+
# HELP gc_remembered_wb_unprotected_objects remembered_wb_unprotected_objects
|
204
|
+
gc_remembered_wb_unprotected_objects{my_label="foo"} 4357
|
205
|
+
# TYPE gc_remembered_wb_unprotected_objects_limit gauge
|
206
|
+
# HELP gc_remembered_wb_unprotected_objects_limit remembered_wb_unprotected_objects_limit
|
207
|
+
gc_remembered_wb_unprotected_objects_limit{my_label="foo"} 8690
|
208
|
+
# TYPE gc_old_objects gauge
|
209
|
+
# HELP gc_old_objects old_objects
|
210
|
+
gc_old_objects{my_label="foo"} 992074
|
211
|
+
# TYPE gc_old_objects_limit gauge
|
212
|
+
# HELP gc_old_objects_limit old_objects_limit
|
213
|
+
gc_old_objects_limit{my_label="foo"} 1743172
|
214
|
+
# TYPE gc_oldmalloc_increase_bytes gauge
|
215
|
+
# HELP gc_oldmalloc_increase_bytes oldmalloc_increase_bytes
|
216
|
+
gc_oldmalloc_increase_bytes{my_label="foo"} 37700816
|
217
|
+
# TYPE gc_oldmalloc_increase_bytes_limit gauge
|
218
|
+
# HELP gc_oldmalloc_increase_bytes_limit oldmalloc_increase_bytes_limit
|
219
|
+
gc_oldmalloc_increase_bytes_limit{my_label="foo"} 33438324
|
220
|
+
```
|
221
|
+
|
222
|
+
### CustomCollector
|
223
|
+
|
224
|
+
config/initializers/prometheus.rb
|
225
|
+
```ruby
|
226
|
+
require 'prometheus/client'
|
227
|
+
require 'prometheus_client_addons'
|
228
|
+
|
229
|
+
prometheus = Prometheus::Client.registry
|
230
|
+
custom_collector = PrometheusClientAddons::Prometheus::Client::CustomCollector.new(
|
231
|
+
name: 'custom_metric',
|
232
|
+
docstring: 'This is a custom metric',
|
233
|
+
base_labels: { my_label: 'foo' },
|
234
|
+
&Proc.new {
|
235
|
+
# return custom value from block
|
236
|
+
Time.now.to_i
|
237
|
+
}
|
238
|
+
)
|
239
|
+
prometheus.register(custom_collector)
|
240
|
+
```
|
241
|
+
|
242
|
+
Example response
|
243
|
+
```
|
244
|
+
# TYPE custom_metric gauge
|
245
|
+
# HELP custom_metric This is a custom metric
|
246
|
+
custom_metric{my_label="foo"} 1567612321
|
247
|
+
```
|
248
|
+
|
249
|
+
## Installation
|
250
|
+
|
251
|
+
```ruby
|
252
|
+
gem 'prometheus_client_addons'
|
253
|
+
```
|
254
|
+
|
255
|
+
```bash
|
256
|
+
bundle install
|
257
|
+
# or
|
258
|
+
gem install prometheus_client_addons
|
259
|
+
```
|
260
|
+
|
261
|
+
## Development
|
262
|
+
|
263
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
264
|
+
|
265
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
266
|
+
|
267
|
+
## Contributing
|
268
|
+
|
269
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/prometheus_client_addons.
|
270
|
+
|
271
|
+
## License
|
272
|
+
|
273
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "prometheus_client_addons"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require "prometheus_client_addons/version"
|
2
|
+
|
3
|
+
module PrometheusClientAddons
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'prometheus_client_addons/prometheus/client/puma'
|
7
|
+
require 'prometheus_client_addons/prometheus/client/active_record'
|
8
|
+
require 'prometheus_client_addons/prometheus/client/custom_collector'
|
9
|
+
require 'prometheus_client_addons/prometheus/client/gc'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'prometheus_client_addons/prometheus/client/formats/text_extended'
|
2
|
+
require 'prometheus_client_addons/prometheus/client/multi_metric'
|
3
|
+
|
4
|
+
module PrometheusClientAddons
|
5
|
+
module Prometheus
|
6
|
+
module Client
|
7
|
+
class ActiveRecord < MultiMetric
|
8
|
+
HANDLES = {
|
9
|
+
size: 'Size of pool',
|
10
|
+
connections: 'Connections count',
|
11
|
+
busy: 'Busy count',
|
12
|
+
dead: 'Dead count',
|
13
|
+
idle: 'Idle count',
|
14
|
+
waiting: 'Num waiting in queue',
|
15
|
+
checkout_timeout: 'Checkout timeout'
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
def multi_name_type
|
19
|
+
full_handles = HANDLES.keys.map { |key| "#{prefix}#{key}" }.map(&:to_sym)
|
20
|
+
Hash[full_handles.zip([:gauge] * HANDLES.size)]
|
21
|
+
end
|
22
|
+
|
23
|
+
def multi_name_docstring
|
24
|
+
Hash[HANDLES.map { |key, value| ["#{prefix}#{key}".to_sym, value] }]
|
25
|
+
end
|
26
|
+
|
27
|
+
def multi_values
|
28
|
+
stat = ::ActiveRecord::Base.connection_pool.stat
|
29
|
+
Hash[stat.map { |key, value| ["#{prefix}#{key}".to_sym, { {} => value }] }]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'prometheus/client/metric'
|
2
|
+
|
3
|
+
module PrometheusClientAddons
|
4
|
+
module Prometheus
|
5
|
+
module Client
|
6
|
+
class CustomCollector < ::Prometheus::Client::Metric
|
7
|
+
def initialize(name:, docstring:, base_labels: {}, &block)
|
8
|
+
@custom_collector = block
|
9
|
+
super(name.to_sym, docstring, base_labels)
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(labels = {})
|
13
|
+
@custom_collector.call
|
14
|
+
end
|
15
|
+
|
16
|
+
def values
|
17
|
+
{ {} => @custom_collector.call }
|
18
|
+
end
|
19
|
+
|
20
|
+
def type
|
21
|
+
:gauge
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module PrometheusClientAddons
|
2
|
+
module Prometheus
|
3
|
+
module Client
|
4
|
+
FakeGauge = Struct.new(:name, :docstring, :base_labels) do
|
5
|
+
def initialize(*)
|
6
|
+
self.base_labels ||= {}
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def type
|
11
|
+
:gauge
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'prometheus/middleware/exporter'
|
2
|
+
require 'prometheus/client/formats/text'
|
3
|
+
require 'prometheus_client_addons/prometheus/client/multi_metric'
|
4
|
+
require 'prometheus_client_addons/prometheus/client/fake_gauge'
|
5
|
+
|
6
|
+
module PrometheusClientAddons
|
7
|
+
module Prometheus
|
8
|
+
module Client
|
9
|
+
module Formats
|
10
|
+
TextExtended = ::Prometheus::Client::Formats::Text.dup
|
11
|
+
|
12
|
+
module TextExtended
|
13
|
+
def self.marshal(registry)
|
14
|
+
lines = []
|
15
|
+
|
16
|
+
registry.metrics.each do |metric|
|
17
|
+
if metric.is_a?(MultiMetric)
|
18
|
+
metric.multi_values.each do |name, values|
|
19
|
+
lines << format(self::TYPE_LINE, name, metric.multi_name_type[name])
|
20
|
+
lines << format(self::HELP_LINE, name, escape(metric.multi_name_docstring[name]))
|
21
|
+
|
22
|
+
values.each do |label_set, value|
|
23
|
+
_metric = FakeGauge.new(name, metric.multi_name_docstring[name], metric.base_labels)
|
24
|
+
representation(_metric, label_set, value) { |l| lines << l }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
else
|
28
|
+
lines << format(self::TYPE_LINE, metric.name, metric.type)
|
29
|
+
lines << format(self::HELP_LINE, metric.name, escape(metric.docstring))
|
30
|
+
|
31
|
+
metric.values.each do |label_set, value|
|
32
|
+
representation(metric, label_set, value) { |l| lines << l }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
(lines << nil).join(self::DELIMITER)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
Prometheus::Middleware::Exporter.send(:remove_const, 'FORMATS')
|
46
|
+
Prometheus::Middleware::Exporter.send(:remove_const, 'FALLBACK')
|
47
|
+
Prometheus::Middleware::Exporter.send(:const_set, 'FORMATS', [PrometheusClientAddons::Prometheus::Client::Formats::TextExtended].freeze)
|
48
|
+
Prometheus::Middleware::Exporter.send(:const_set, 'FALLBACK', PrometheusClientAddons::Prometheus::Client::Formats::TextExtended)
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'prometheus_client_addons/prometheus/client/formats/text_extended'
|
2
|
+
require 'prometheus_client_addons/prometheus/client/multi_metric'
|
3
|
+
|
4
|
+
module PrometheusClientAddons
|
5
|
+
module Prometheus
|
6
|
+
module Client
|
7
|
+
class GC < MultiMetric
|
8
|
+
KEYS = [
|
9
|
+
:count,
|
10
|
+
:heap_allocated_pages,
|
11
|
+
:heap_sorted_length,
|
12
|
+
:heap_allocatable_pages,
|
13
|
+
:heap_available_slots,
|
14
|
+
:heap_live_slots,
|
15
|
+
:heap_free_slots,
|
16
|
+
:heap_final_slots,
|
17
|
+
:heap_marked_slots,
|
18
|
+
:heap_eden_pages,
|
19
|
+
:heap_tomb_pages,
|
20
|
+
:total_allocated_pages,
|
21
|
+
:total_freed_pages,
|
22
|
+
:total_allocated_objects,
|
23
|
+
:total_freed_objects,
|
24
|
+
:malloc_increase_bytes,
|
25
|
+
:malloc_increase_bytes_limit,
|
26
|
+
:minor_gc_count,
|
27
|
+
:major_gc_count,
|
28
|
+
:remembered_wb_unprotected_objects,
|
29
|
+
:remembered_wb_unprotected_objects_limit,
|
30
|
+
:old_objects,
|
31
|
+
:old_objects_limit,
|
32
|
+
:oldmalloc_increase_bytes,
|
33
|
+
:oldmalloc_increase_bytes_limit
|
34
|
+
].freeze
|
35
|
+
|
36
|
+
HANDLES = Hash[KEYS.zip(KEYS)].freeze
|
37
|
+
|
38
|
+
def multi_name_type
|
39
|
+
full_handles = HANDLES.keys.map { |key| "#{prefix}#{key}" }.map(&:to_sym)
|
40
|
+
Hash[full_handles.zip([:gauge] * HANDLES.size)]
|
41
|
+
end
|
42
|
+
|
43
|
+
def multi_name_docstring
|
44
|
+
Hash[HANDLES.map { |key, value| ["#{prefix}#{key}".to_sym, value] }]
|
45
|
+
end
|
46
|
+
|
47
|
+
def multi_values
|
48
|
+
stat = ::GC.stat
|
49
|
+
Hash[stat.map { |key, value| ["#{prefix}#{key}".to_sym, { {} => value }] }]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'prometheus/client/metric'
|
2
|
+
require 'prometheus/client/label_set_validator'
|
3
|
+
|
4
|
+
module PrometheusClientAddons
|
5
|
+
module Prometheus
|
6
|
+
module Client
|
7
|
+
class MultiMetric < ::Prometheus::Client::Metric
|
8
|
+
attr_reader :name, :prefix, :base_labels
|
9
|
+
|
10
|
+
def initialize(prefix: '', base_labels: {})
|
11
|
+
prefix = "#{prefix}_" unless prefix == ''
|
12
|
+
|
13
|
+
@prefix = prefix
|
14
|
+
@name = prefix
|
15
|
+
@base_labels = base_labels
|
16
|
+
|
17
|
+
multi_name_type.keys.each { |name| validate_name("#{prefix}#{name}".to_sym) }
|
18
|
+
multi_name_docstring.keys.each { |name| validate_name("#{prefix}#{name}".to_sym) }
|
19
|
+
multi_name_docstring.values.each(&method(:validate_docstring))
|
20
|
+
@validator = ::Prometheus::Client::LabelSetValidator.new
|
21
|
+
@validator.valid?(base_labels)
|
22
|
+
end
|
23
|
+
|
24
|
+
def multi_name_type
|
25
|
+
fail('Should return hash {name => type}')
|
26
|
+
end
|
27
|
+
|
28
|
+
def multi_name_docstring
|
29
|
+
fail('Should return hash {name => docstrings}')
|
30
|
+
end
|
31
|
+
|
32
|
+
def multi_values
|
33
|
+
fail('Should return hash {name => {label_set => value, label_set => value, }}')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'prometheus_client_addons/prometheus/client/formats/text_extended'
|
3
|
+
require 'prometheus_client_addons/prometheus/client/multi_metric'
|
4
|
+
require 'prometheus_client_addons/puma/plugin/prometheus_client_addons'
|
5
|
+
|
6
|
+
module PrometheusClientAddons
|
7
|
+
module Prometheus
|
8
|
+
module Client
|
9
|
+
class Puma < MultiMetric
|
10
|
+
class << self
|
11
|
+
attr_accessor :control_url, :control_auth_token
|
12
|
+
end
|
13
|
+
|
14
|
+
HANDLES = {
|
15
|
+
backlog: 'How many requests are waiting',
|
16
|
+
running: 'Number of running threads',
|
17
|
+
pool_capacity: 'Number of requests that can be processed right now',
|
18
|
+
max_threads: 'Maximum number of worker threads',
|
19
|
+
|
20
|
+
workers: 'Number of workers',
|
21
|
+
phase: 'Phase of worker',
|
22
|
+
booted_workers: 'Number of booted workers',
|
23
|
+
old_workers: 'Number of old workers',
|
24
|
+
|
25
|
+
worker_status_phase: 'Phase of worker',
|
26
|
+
worker_status_booted: 'Booted or not',
|
27
|
+
worker_status_last_checkin: 'Last update',
|
28
|
+
|
29
|
+
worker_status_last_status_backlog: 'How many objects have yet to be processed by the pool',
|
30
|
+
worker_status_last_status_running: 'Number of running threads',
|
31
|
+
worker_status_last_status_pool_capacity: 'Number of requests that can be processed right now',
|
32
|
+
worker_status_last_status_max_threads: 'Maximum number of worker threads'
|
33
|
+
}.freeze
|
34
|
+
|
35
|
+
def multi_name_type
|
36
|
+
full_handles = HANDLES.keys.map { |key| "#{prefix}#{key}" }.map(&:to_sym)
|
37
|
+
Hash[full_handles.zip([:gauge] * HANDLES.size)]
|
38
|
+
end
|
39
|
+
|
40
|
+
def multi_name_docstring
|
41
|
+
Hash[HANDLES.map { |key, value| ["#{prefix}#{key}".to_sym, value] }]
|
42
|
+
end
|
43
|
+
|
44
|
+
def extract(input, output, nested, label_set = {})
|
45
|
+
key = if input.key?(nested.last.to_s)
|
46
|
+
nested.last.to_s
|
47
|
+
elsif input.key?(nested.last.to_sym)
|
48
|
+
nested.last.to_sym
|
49
|
+
end
|
50
|
+
return unless key
|
51
|
+
|
52
|
+
output["#{prefix}#{nested.join('_')}".to_sym] ||= {}
|
53
|
+
output["#{prefix}#{nested.join('_')}".to_sym][label_set] = input[key]
|
54
|
+
end
|
55
|
+
|
56
|
+
def multi_values
|
57
|
+
body = Socket.unix(self.class.control_url.gsub("unix://", '')) do |socket|
|
58
|
+
socket << "GET /stats?token=#{self.class.control_auth_token} HTTP/1.0\r\n\r\n"
|
59
|
+
socket.read
|
60
|
+
end
|
61
|
+
|
62
|
+
data = JSON.parse(body.split("\n").last, symbolize_names: true)
|
63
|
+
|
64
|
+
result = {}
|
65
|
+
|
66
|
+
extract(data, result, [:backlog])
|
67
|
+
extract(data, result, [:running])
|
68
|
+
extract(data, result, [:pool_capacity])
|
69
|
+
extract(data, result, [:max_threads])
|
70
|
+
|
71
|
+
extract(data, result, [:workers])
|
72
|
+
extract(data, result, [:phase])
|
73
|
+
extract(data, result, [:booted_workers])
|
74
|
+
extract(data, result, [:old_workers])
|
75
|
+
|
76
|
+
if data.key?(:worker_status) && !data[:worker_status].empty?
|
77
|
+
data[:worker_status].each do |worker_status|
|
78
|
+
worker_index = worker_status[:index]
|
79
|
+
|
80
|
+
extract(worker_status, result, [:worker_status, :phase], { worker_index: worker_index })
|
81
|
+
extract(worker_status, result, [:worker_status, :booted], { worker_index: worker_index })
|
82
|
+
extract(worker_status, result, [:worker_status, :last_checkin], { worker_index: worker_index })
|
83
|
+
|
84
|
+
last_status = worker_status[:last_status]
|
85
|
+
extract(last_status, result, [:worker_status, :last_status, :backlog], { worker_index: worker_index })
|
86
|
+
extract(last_status, result, [:worker_status, :last_status, :running], { worker_index: worker_index })
|
87
|
+
extract(last_status, result, [:worker_status, :last_status, :pool_capacity], { worker_index: worker_index })
|
88
|
+
extract(last_status, result, [:worker_status, :last_status, :max_threads], { worker_index: worker_index })
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
result
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'puma/plugin'
|
2
|
+
|
3
|
+
module PrometheusClientAddons
|
4
|
+
module Puma
|
5
|
+
module Plugin
|
6
|
+
::Puma::Plugin.create do
|
7
|
+
def start(launcher)
|
8
|
+
control_url = launcher.options[:control_url]
|
9
|
+
raise StandardError, "Need Puma's activate_control_app" if control_url == nil
|
10
|
+
|
11
|
+
Prometheus::Client::Puma.tap do |puma|
|
12
|
+
puma.control_url = control_url
|
13
|
+
puma.control_auth_token = launcher.options[:control_auth_token]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "prometheus_client_addons/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "prometheus_client_addons"
|
7
|
+
spec.version = PrometheusClientAddons::VERSION
|
8
|
+
spec.authors = ["Anton Osenenko"]
|
9
|
+
spec.email = ["anton.osenenko@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = 'The missed parts of prometheus/client_ruby'
|
12
|
+
spec.description = 'The missed parts of prometheus/client_ruby'
|
13
|
+
spec.homepage = "https://github.com/a0s/prometheus_client_addons"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
if spec.respond_to?(:metadata)
|
17
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
19
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
20
|
+
else
|
21
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
22
|
+
"public gem pushes."
|
23
|
+
end
|
24
|
+
|
25
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
26
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
27
|
+
end
|
28
|
+
spec.bindir = "exe"
|
29
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
30
|
+
spec.require_paths = ["lib"]
|
31
|
+
|
32
|
+
spec.add_dependency "prometheus-client", "~> 0.9.0"
|
33
|
+
|
34
|
+
spec.add_development_dependency "bundler", "~> 1.17"
|
35
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
36
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
37
|
+
spec.add_development_dependency "puma"
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: prometheus_client_addons
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Anton Osenenko
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-09-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: prometheus-client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.9.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.9.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.17'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.17'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: puma
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: The missed parts of prometheus/client_ruby
|
84
|
+
email:
|
85
|
+
- anton.osenenko@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".travis.yml"
|
93
|
+
- Gemfile
|
94
|
+
- LICENSE.txt
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- bin/console
|
98
|
+
- bin/setup
|
99
|
+
- lib/prometheus_client_addons.rb
|
100
|
+
- lib/prometheus_client_addons/prometheus/client/active_record.rb
|
101
|
+
- lib/prometheus_client_addons/prometheus/client/custom_collector.rb
|
102
|
+
- lib/prometheus_client_addons/prometheus/client/fake_gauge.rb
|
103
|
+
- lib/prometheus_client_addons/prometheus/client/formats/text_extended.rb
|
104
|
+
- lib/prometheus_client_addons/prometheus/client/gc.rb
|
105
|
+
- lib/prometheus_client_addons/prometheus/client/multi_metric.rb
|
106
|
+
- lib/prometheus_client_addons/prometheus/client/puma.rb
|
107
|
+
- lib/prometheus_client_addons/puma/plugin/prometheus_client_addons.rb
|
108
|
+
- lib/prometheus_client_addons/version.rb
|
109
|
+
- prometheus_client_addons.gemspec
|
110
|
+
homepage: https://github.com/a0s/prometheus_client_addons
|
111
|
+
licenses:
|
112
|
+
- MIT
|
113
|
+
metadata:
|
114
|
+
allowed_push_host: https://rubygems.org
|
115
|
+
homepage_uri: https://github.com/a0s/prometheus_client_addons
|
116
|
+
source_code_uri: https://github.com/a0s/prometheus_client_addons
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
requirements: []
|
132
|
+
rubygems_version: 3.0.3
|
133
|
+
signing_key:
|
134
|
+
specification_version: 4
|
135
|
+
summary: The missed parts of prometheus/client_ruby
|
136
|
+
test_files: []
|