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 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
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .ruby-*
10
+ Gemfile.lock
11
+
12
+ # rspec failure tracking
13
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.3
7
+ before_install: gem install bundler -v 1.17.2
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in prometheus_client_addons.gemspec
6
+ gemspec
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
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
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,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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,3 @@
1
+ module PrometheusClientAddons
2
+ VERSION = "0.1.0"
3
+ 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: []