prometheus_exporter 0.8.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +10 -3
- data/CHANGELOG +8 -0
- data/README.md +56 -24
- data/bin/prometheus_exporter +3 -0
- data/lib/prometheus_exporter/instrumentation/puma.rb +11 -11
- data/lib/prometheus_exporter/instrumentation/resque.rb +6 -6
- data/lib/prometheus_exporter/instrumentation/sidekiq_process.rb +58 -0
- data/lib/prometheus_exporter/instrumentation/sidekiq_queue.rb +26 -12
- data/lib/prometheus_exporter/instrumentation/unicorn.rb +3 -3
- data/lib/prometheus_exporter/instrumentation.rb +1 -0
- data/lib/prometheus_exporter/metric/base.rb +9 -0
- data/lib/prometheus_exporter/metric/gauge.rb +4 -0
- data/lib/prometheus_exporter/server/collector.rb +1 -0
- data/lib/prometheus_exporter/server/delayed_job_collector.rb +17 -18
- data/lib/prometheus_exporter/server/puma_collector.rb +7 -7
- data/lib/prometheus_exporter/server/resque_collector.rb +6 -6
- data/lib/prometheus_exporter/server/runner.rb +10 -1
- data/lib/prometheus_exporter/server/sidekiq_collector.rb +1 -1
- data/lib/prometheus_exporter/server/sidekiq_process_collector.rb +46 -0
- data/lib/prometheus_exporter/server/sidekiq_queue_collector.rb +1 -1
- data/lib/prometheus_exporter/server/unicorn_collector.rb +3 -3
- data/lib/prometheus_exporter/server/web_collector.rb +4 -4
- data/lib/prometheus_exporter/server/web_server.rb +3 -3
- data/lib/prometheus_exporter/server.rb +1 -0
- data/lib/prometheus_exporter/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b9fae4f661a2154e78754266e14a491a3d4271a7f2bf308586d1d5c16975452
|
4
|
+
data.tar.gz: 3c12e51359809b26963be8d148ebf0775f83ad588ca6b7f352b855e73f553598
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 866d3593b9d575451efec2a87dac5d0e4b03b9ed265b776c9ae3f65ce417e7cb04c8ee29769ba38d3fc5ad1abb5824c56c10f5ee7b8461d62629c95145f8c58d
|
7
|
+
data.tar.gz: 6dd42a1d78443807ca0b026617e55e23089e772620d0dfd88ccc3c2871a6096fb081ca0065060e943680158f7b78c88035bb8d64327f95e4756f3902add36fe3
|
data/.github/workflows/ci.yml
CHANGED
@@ -12,7 +12,7 @@ jobs:
|
|
12
12
|
name: Ruby ${{ matrix.ruby }}
|
13
13
|
strategy:
|
14
14
|
matrix:
|
15
|
-
ruby: ["3.0","2.7", "2.6"]
|
15
|
+
ruby: ["3.0", "2.7", "2.6"]
|
16
16
|
steps:
|
17
17
|
- uses: actions/checkout@master
|
18
18
|
with:
|
@@ -26,11 +26,18 @@ jobs:
|
|
26
26
|
key: ${{ runner.os }}-${{ matrix.ruby }}-gems-v2-${{ hashFiles('**/Gemfile.lock') }}
|
27
27
|
restore-keys: |
|
28
28
|
${{ runner.os }}-${{ matrix.ruby }}-gems-v2-
|
29
|
+
|
30
|
+
- name: Downgrade rubygems
|
31
|
+
run: |
|
32
|
+
# for Ruby <= 2.6 , details https://github.com/rubygems/rubygems/issues/3284
|
33
|
+
gem update --system 3.0.8
|
34
|
+
if: ${{ matrix.ruby == '2.6' || matrix.ruby == '2.7' }}
|
35
|
+
- name: Upgrade rubygems
|
36
|
+
run: |
|
37
|
+
gem update --system
|
29
38
|
- name: Setup gems
|
30
39
|
run: |
|
31
40
|
gem install bundler
|
32
|
-
# for Ruby <= 2.6 , details https://github.com/rubygems/rubygems/issues/3284
|
33
|
-
gem update --system 3.0.8 && gem update --system
|
34
41
|
bundle config path vendor/bundle
|
35
42
|
bundle install --jobs 4
|
36
43
|
bundle exec appraisal install
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
1.0.0 - 23-11-2021
|
2
|
+
|
3
|
+
- BREAKING: rename metrics to match prometheus official naming conventions (See https://prometheus.io/docs/practices/naming/#metric-names)
|
4
|
+
- FEATURE: Sidekiq process metrics
|
5
|
+
- FEATURE: Allow collecting web metrics as histograms
|
6
|
+
- FIX: logger improved for web server
|
7
|
+
- FIX: Remove job labels from DelayedJob queues
|
8
|
+
|
1
9
|
0.8.1 - 04-08-2021
|
2
10
|
|
3
11
|
- FEATURE: swap from hardcoded STDERR to logger pattern (see README for details)
|
data/README.md
CHANGED
@@ -5,6 +5,7 @@ Prometheus Exporter allows you to aggregate custom metrics from multiple process
|
|
5
5
|
To learn more see [Instrumenting Rails with Prometheus](https://samsaffron.com/archive/2018/02/02/instrumenting-rails-with-prometheus) (it has pretty pictures!)
|
6
6
|
|
7
7
|
* [Requirements](#requirements)
|
8
|
+
* [Migrating from v0.x](#migrating-from-v0.x)
|
8
9
|
* [Installation](#installation)
|
9
10
|
* [Usage](#usage)
|
10
11
|
* [Single process mode](#single-process-mode)
|
@@ -26,6 +27,7 @@ To learn more see [Instrumenting Rails with Prometheus](https://samsaffron.com/a
|
|
26
27
|
* [Metrics default prefix / labels](#metrics-default-prefix--labels)
|
27
28
|
* [Client default labels](#client-default-labels)
|
28
29
|
* [Client default host](#client-default-host)
|
30
|
+
* [Histogram mode](#histogram-mode)
|
29
31
|
* [Transport concerns](#transport-concerns)
|
30
32
|
* [JSON generation and parsing](#json-generation-and-parsing)
|
31
33
|
* [Logging](#logging)
|
@@ -35,7 +37,13 @@ To learn more see [Instrumenting Rails with Prometheus](https://samsaffron.com/a
|
|
35
37
|
|
36
38
|
## Requirements
|
37
39
|
|
38
|
-
Minimum Ruby of version 2.
|
40
|
+
Minimum Ruby of version 2.6.0 is required, Ruby 2.5.0 is EOL as of March 31st 2021.
|
41
|
+
|
42
|
+
## Migrating from v0.x
|
43
|
+
|
44
|
+
There are some major changes in v1.x from v0.x.
|
45
|
+
|
46
|
+
- Some of metrics are renamed to match [prometheus official guide for metric names](https://prometheus.io/docs/practices/naming/#metric-names). (#184)
|
39
47
|
|
40
48
|
## Installation
|
41
49
|
|
@@ -382,6 +390,8 @@ Sidekiq.configure_server do |config|
|
|
382
390
|
end
|
383
391
|
```
|
384
392
|
|
393
|
+
This will only monitor the queues that are consumed by the sidekiq process you are on. You can pass an `all_queues` parameter to monitor metrics on all queues.
|
394
|
+
|
385
395
|
To monitor Sidekiq process info:
|
386
396
|
|
387
397
|
```ruby
|
@@ -389,6 +399,7 @@ Sidekiq.configure_server do |config|
|
|
389
399
|
config.on :startup do
|
390
400
|
require 'prometheus_exporter/instrumentation'
|
391
401
|
PrometheusExporter::Instrumentation::Process.start type: 'sidekiq'
|
402
|
+
PrometheusExporter::Instrumentation::SidekiqProcess.start
|
392
403
|
end
|
393
404
|
end
|
394
405
|
```
|
@@ -425,11 +436,19 @@ This metric has a `job_name` label and a `queue` label.
|
|
425
436
|
**PrometheusExporter::Instrumentation::SidekiqQueue**
|
426
437
|
| Type | Name | Description |
|
427
438
|
| --- | --- | --- |
|
428
|
-
| Gauge | `
|
439
|
+
| Gauge | `sidekiq_queue_backlog` | Size of the sidekiq queue |
|
429
440
|
| Gauge | `sidekiq_queue_latency_seconds` | Latency of the sidekiq queue |
|
430
441
|
|
431
442
|
Both metrics will have a `queue` label with the name of the queue.
|
432
443
|
|
444
|
+
**PrometheusExporter::Instrumentation::SidekiqProcess**
|
445
|
+
| Type | Name | Description |
|
446
|
+
| --- | --- | --- |
|
447
|
+
| Gauge | `sidekiq_process_busy` | Number of busy workers for this process |
|
448
|
+
| Gauge | `sidekiq_process_concurrency` | Concurrency for this process |
|
449
|
+
|
450
|
+
Both metrics will include the labels `labels`, `queues`, `quiet`, `tag`, `hostname` and `identity`, as returned by the [Sidekiq API](https://github.com/mperham/sidekiq/wiki/API#processes).
|
451
|
+
|
433
452
|
_See [Metrics collected by Process Instrumentation](#metrics-collected-by-process-instrumentation) for a list of metrics the Process instrumentation will produce._
|
434
453
|
|
435
454
|
#### Shoryuken metrics
|
@@ -529,15 +548,15 @@ end
|
|
529
548
|
|
530
549
|
#### Metrics collected by Puma Instrumentation
|
531
550
|
|
532
|
-
| Type | Name
|
533
|
-
| --- | ---
|
534
|
-
| Gauge | `
|
535
|
-
| Gauge | `
|
536
|
-
| Gauge | `
|
537
|
-
| Gauge | `
|
538
|
-
| Gauge | `
|
539
|
-
| Gauge | `
|
540
|
-
| Gauge | `
|
551
|
+
| Type | Name | Description |
|
552
|
+
| --- | --- | --- |
|
553
|
+
| Gauge | `puma_workers` | Number of puma workers |
|
554
|
+
| Gauge | `puma_booted_workers` | Number of puma workers booted |
|
555
|
+
| Gauge | `puma_old_workers` | Number of old puma workers |
|
556
|
+
| Gauge | `puma_running_threads` | Number of puma threads currently running |
|
557
|
+
| Gauge | `puma_request_backlog` | Number of requests waiting to be processed by a puma thread |
|
558
|
+
| Gauge | `puma_thread_pool_capacity` | Number of puma threads available at current scale |
|
559
|
+
| Gauge | `puma_max_threads` | Number of puma threads at available at max scale |
|
541
560
|
|
542
561
|
All metrics may have a `phase` label and all custom labels provided with the `labels` option.
|
543
562
|
|
@@ -554,14 +573,14 @@ PrometheusExporter::Instrumentation::Resque.start
|
|
554
573
|
|
555
574
|
#### Metrics collected by Resque Instrumentation
|
556
575
|
|
557
|
-
| Type | Name
|
558
|
-
| --- | ---
|
559
|
-
| Gauge | `
|
560
|
-
| Gauge | `
|
561
|
-
| Gauge | `
|
562
|
-
| Gauge | `
|
563
|
-
| Gauge | `
|
564
|
-
| Gauge | `
|
576
|
+
| Type | Name | Description |
|
577
|
+
| --- | --- | --- |
|
578
|
+
| Gauge | `resque_processed_jobs` | Total number of processed Resque jobs |
|
579
|
+
| Gauge | `resque_failed_jobs` | Total number of failed Resque jobs |
|
580
|
+
| Gauge | `resque_pending_jobs` | Total number of pending Resque jobs |
|
581
|
+
| Gauge | `resque_queues` | Total number of Resque queues |
|
582
|
+
| Gauge | `resque_workers` | Total number of Resque workers running |
|
583
|
+
| Gauge | `resque_working` | Total number of Resque workers working |
|
565
584
|
|
566
585
|
### Unicorn process metrics
|
567
586
|
|
@@ -580,11 +599,11 @@ Note: You must install the `raindrops` gem in your `Gemfile` or locally.
|
|
580
599
|
|
581
600
|
#### Metrics collected by Unicorn Instrumentation
|
582
601
|
|
583
|
-
| Type | Name
|
584
|
-
| --- | ---
|
585
|
-
| Gauge | `
|
586
|
-
| Gauge | `
|
587
|
-
| Gauge | `
|
602
|
+
| Type | Name | Description |
|
603
|
+
| --- | --- | --- |
|
604
|
+
| Gauge | `unicorn_workers` | Number of unicorn workers |
|
605
|
+
| Gauge | `unicorn_active_workers` | Number of active unicorn workers |
|
606
|
+
| Gauge | `unicorn_request_backlog` | Number of requests waiting to be processed by a unicorn worker |
|
588
607
|
|
589
608
|
### Custom type collectors
|
590
609
|
|
@@ -769,6 +788,7 @@ Usage: prometheus_exporter [options]
|
|
769
788
|
-c, --collector FILE (optional) Custom collector to run
|
770
789
|
-a, --type-collector FILE (optional) Custom type collectors to run in main collector
|
771
790
|
-v, --verbose
|
791
|
+
-g, --histogram Use histogram instead of summary for aggregations
|
772
792
|
--auth FILE (optional) enable basic authentication using a htpasswd FILE
|
773
793
|
--realm REALM (optional) Use REALM for basic authentication (default: "Prometheus Exporter")
|
774
794
|
--unicorn-listen-address ADDRESS
|
@@ -839,6 +859,18 @@ http_requests_total{service="app-server-01",app_name="app-01"} 1
|
|
839
859
|
|
840
860
|
By default, `PrometheusExporter::Client.default` connects to `localhost:9394`. If your setup requires this (e.g. when using `docker-compose`), you can change the default host and port by setting the environment variables `PROMETHEUS_EXPORTER_HOST` and `PROMETHEUS_EXPORTER_PORT`.
|
841
861
|
|
862
|
+
### Histogram mode
|
863
|
+
|
864
|
+
By default, the built-in collectors will report aggregations as summaries. If you need to aggregate metrics across labels, you can switch from summaries to histograms:
|
865
|
+
|
866
|
+
```
|
867
|
+
$ prometheus_exporter --histogram
|
868
|
+
```
|
869
|
+
|
870
|
+
In histogram mode, the same metrics will be collected but will be reported as histograms rather than summaries. This sacrifices some precision but allows aggregating metrics across actions and nodes using [`histogram_quantile`].
|
871
|
+
|
872
|
+
[`histogram_quantile`]: https://prometheus.io/docs/prometheus/latest/querying/functions/#histogram_quantile
|
873
|
+
|
842
874
|
## Transport concerns
|
843
875
|
|
844
876
|
Prometheus Exporter handles transport using a simple HTTP protocol. In multi process mode we avoid needing a large number of HTTP request by using chunked encoding to send metrics. This means that a single HTTP channel can deliver 100s or even 1000s of metrics over a single HTTP session to the `/send-metrics` endpoint. All calls to `send` and `send_json` on the `PrometheusExporter::Client` class are **non-blocking** and batched.
|
data/bin/prometheus_exporter
CHANGED
@@ -50,6 +50,9 @@ def run
|
|
50
50
|
opt.on('-v', '--verbose') do |o|
|
51
51
|
options[:verbose] = true
|
52
52
|
end
|
53
|
+
opt.on('-g', '--histogram', "Use histogram instead of summary for aggregations") do |o|
|
54
|
+
options[:histogram] = true
|
55
|
+
end
|
53
56
|
opt.on('--auth FILE', String, "(optional) enable basic authentication using a htpasswd FILE") do |o|
|
54
57
|
options[:auth] = o
|
55
58
|
end
|
@@ -46,9 +46,9 @@ module PrometheusExporter::Instrumentation
|
|
46
46
|
|
47
47
|
if stats.key?("workers")
|
48
48
|
metric[:phase] = stats["phase"]
|
49
|
-
metric[:
|
50
|
-
metric[:
|
51
|
-
metric[:
|
49
|
+
metric[:workers] = stats["workers"]
|
50
|
+
metric[:booted_workers] = stats["booted_workers"]
|
51
|
+
metric[:old_workers] = stats["old_workers"]
|
52
52
|
|
53
53
|
stats["worker_status"].each do |worker|
|
54
54
|
next if worker["last_status"].empty?
|
@@ -62,15 +62,15 @@ module PrometheusExporter::Instrumentation
|
|
62
62
|
private
|
63
63
|
|
64
64
|
def collect_worker_status(metric, status)
|
65
|
-
metric[:
|
66
|
-
metric[:
|
67
|
-
metric[:
|
68
|
-
metric[:
|
65
|
+
metric[:request_backlog] ||= 0
|
66
|
+
metric[:running_threads] ||= 0
|
67
|
+
metric[:thread_pool_capacity] ||= 0
|
68
|
+
metric[:max_threads] ||= 0
|
69
69
|
|
70
|
-
metric[:
|
71
|
-
metric[:
|
72
|
-
metric[:
|
73
|
-
metric[:
|
70
|
+
metric[:request_backlog] += status["backlog"]
|
71
|
+
metric[:running_threads] += status["running"]
|
72
|
+
metric[:thread_pool_capacity] += status["pool_capacity"]
|
73
|
+
metric[:max_threads] += status["max_threads"]
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|
@@ -29,12 +29,12 @@ module PrometheusExporter::Instrumentation
|
|
29
29
|
def collect_resque_stats(metric)
|
30
30
|
info = ::Resque.info
|
31
31
|
|
32
|
-
metric[:
|
33
|
-
metric[:
|
34
|
-
metric[:
|
35
|
-
metric[:
|
36
|
-
metric[:
|
37
|
-
metric[:
|
32
|
+
metric[:processed_jobs] = info[:processed]
|
33
|
+
metric[:failed_jobs] = info[:failed]
|
34
|
+
metric[:pending_jobs] = info[:pending]
|
35
|
+
metric[:queues] = info[:queues]
|
36
|
+
metric[:worker] = info[:workers]
|
37
|
+
metric[:working] = info[:working]
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PrometheusExporter::Instrumentation
|
4
|
+
class SidekiqProcess
|
5
|
+
def self.start(client: nil, frequency: 30)
|
6
|
+
client ||= PrometheusExporter::Client.default
|
7
|
+
sidekiq_process_collector = new
|
8
|
+
|
9
|
+
Thread.new do
|
10
|
+
loop do
|
11
|
+
begin
|
12
|
+
client.send_json(sidekiq_process_collector.collect)
|
13
|
+
rescue StandardError => e
|
14
|
+
STDERR.puts("Prometheus Exporter Failed To Collect Sidekiq Processes metrics #{e}")
|
15
|
+
ensure
|
16
|
+
sleep frequency
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@pid = ::Process.pid
|
24
|
+
@hostname = Socket.gethostname
|
25
|
+
end
|
26
|
+
|
27
|
+
def collect
|
28
|
+
{
|
29
|
+
type: 'sidekiq_process',
|
30
|
+
process: collect_stats
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def collect_stats
|
35
|
+
process = current_process
|
36
|
+
return {} unless process
|
37
|
+
|
38
|
+
{
|
39
|
+
busy: process['busy'],
|
40
|
+
concurrency: process['concurrency'],
|
41
|
+
labels: {
|
42
|
+
labels: process['labels'].sort.join(','),
|
43
|
+
queues: process['queues'].sort.join(','),
|
44
|
+
quiet: process['quiet'],
|
45
|
+
tag: process['tag'],
|
46
|
+
hostname: process['hostname'],
|
47
|
+
identity: process['identity'],
|
48
|
+
}
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def current_process
|
53
|
+
::Sidekiq::ProcessSet.new.find do |sp|
|
54
|
+
sp['hostname'] == @hostname && sp['pid'] == @pid
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
module PrometheusExporter::Instrumentation
|
4
4
|
class SidekiqQueue
|
5
|
-
def self.start(client: nil, frequency: 30)
|
5
|
+
def self.start(client: nil, frequency: 30, all_queues: false)
|
6
6
|
client ||= PrometheusExporter::Client.default
|
7
|
-
sidekiq_queue_collector = new
|
7
|
+
sidekiq_queue_collector = new(all_queues: all_queues)
|
8
8
|
|
9
9
|
Thread.new do
|
10
10
|
loop do
|
@@ -19,6 +19,12 @@ module PrometheusExporter::Instrumentation
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
def initialize(all_queues: false)
|
23
|
+
@all_queues = all_queues
|
24
|
+
@pid = ::Process.pid
|
25
|
+
@hostname = Socket.gethostname
|
26
|
+
end
|
27
|
+
|
22
28
|
def collect
|
23
29
|
{
|
24
30
|
type: 'sidekiq_queue',
|
@@ -27,24 +33,32 @@ module PrometheusExporter::Instrumentation
|
|
27
33
|
end
|
28
34
|
|
29
35
|
def collect_queue_stats
|
30
|
-
|
31
|
-
pid = ::Process.pid
|
32
|
-
ps = ::Sidekiq::ProcessSet.new
|
36
|
+
sidekiq_queues = ::Sidekiq::Queue.all
|
33
37
|
|
34
|
-
|
35
|
-
|
38
|
+
unless @all_queues
|
39
|
+
queues = collect_current_process_queues
|
40
|
+
sidekiq_queues.select! { |sidekiq_queue| queues.include?(sidekiq_queue.name) }
|
36
41
|
end
|
37
42
|
|
38
|
-
|
39
|
-
|
40
|
-
::Sidekiq::Queue.all.map do |queue|
|
41
|
-
next unless queues.include? queue.name
|
43
|
+
sidekiq_queues.map do |queue|
|
42
44
|
{
|
43
|
-
|
45
|
+
backlog: queue.size,
|
44
46
|
latency_seconds: queue.latency.to_i,
|
45
47
|
labels: { queue: queue.name }
|
46
48
|
}
|
47
49
|
end.compact
|
48
50
|
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def collect_current_process_queues
|
55
|
+
ps = ::Sidekiq::ProcessSet.new
|
56
|
+
|
57
|
+
process = ps.find do |sp|
|
58
|
+
sp['hostname'] == @hostname && sp['pid'] == @pid
|
59
|
+
end
|
60
|
+
|
61
|
+
process.nil? ? [] : process['queues']
|
62
|
+
end
|
49
63
|
end
|
50
64
|
end
|
@@ -42,9 +42,9 @@ module PrometheusExporter::Instrumentation
|
|
42
42
|
def collect_unicorn_stats(metric)
|
43
43
|
stats = listener_address_stats
|
44
44
|
|
45
|
-
metric[:
|
46
|
-
metric[:
|
47
|
-
metric[:
|
45
|
+
metric[:active_workers] = stats.active
|
46
|
+
metric[:request_backlog] = stats.queued
|
47
|
+
metric[:workers] = worker_process_count
|
48
48
|
end
|
49
49
|
|
50
50
|
private
|
@@ -5,6 +5,7 @@ require_relative "instrumentation/process"
|
|
5
5
|
require_relative "instrumentation/method_profiler"
|
6
6
|
require_relative "instrumentation/sidekiq"
|
7
7
|
require_relative "instrumentation/sidekiq_queue"
|
8
|
+
require_relative "instrumentation/sidekiq_process"
|
8
9
|
require_relative "instrumentation/delayed_job"
|
9
10
|
require_relative "instrumentation/puma"
|
10
11
|
require_relative "instrumentation/hutch"
|
@@ -5,6 +5,7 @@ module PrometheusExporter::Metric
|
|
5
5
|
|
6
6
|
@default_prefix = nil if !defined?(@default_prefix)
|
7
7
|
@default_labels = nil if !defined?(@default_labels)
|
8
|
+
@default_aggregation = nil if !defined?(@default_aggregation)
|
8
9
|
|
9
10
|
# prefix applied to all metrics
|
10
11
|
def self.default_prefix=(name)
|
@@ -23,6 +24,14 @@ module PrometheusExporter::Metric
|
|
23
24
|
@default_labels || {}
|
24
25
|
end
|
25
26
|
|
27
|
+
def self.default_aggregation=(aggregation)
|
28
|
+
@default_aggregation = aggregation
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.default_aggregation
|
32
|
+
@default_aggregation ||= Summary
|
33
|
+
end
|
34
|
+
|
26
35
|
attr_accessor :help, :name, :data
|
27
36
|
|
28
37
|
def initialize(name, help)
|
@@ -14,6 +14,7 @@ module PrometheusExporter::Server
|
|
14
14
|
register_collector(ProcessCollector.new)
|
15
15
|
register_collector(SidekiqCollector.new)
|
16
16
|
register_collector(SidekiqQueueCollector.new)
|
17
|
+
register_collector(SidekiqProcessCollector.new)
|
17
18
|
register_collector(DelayedJobCollector.new)
|
18
19
|
register_collector(PumaCollector.new)
|
19
20
|
register_collector(HutchCollector.new)
|
@@ -19,22 +19,21 @@ module PrometheusExporter::Server
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def collect(obj)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
labels = custom_labels.nil? ? default_labels : default_labels.merge(custom_labels)
|
22
|
+
custom_labels = obj['custom_labels'] || {}
|
23
|
+
gauge_labels = { queue_name: obj['queue_name'] }.merge(custom_labels)
|
24
|
+
counter_labels = gauge_labels.merge(job_name: obj['name'])
|
26
25
|
|
27
26
|
ensure_delayed_job_metrics
|
28
|
-
@delayed_job_duration_seconds.observe(obj["duration"],
|
29
|
-
@delayed_jobs_total.observe(1,
|
30
|
-
@delayed_failed_jobs_total.observe(1,
|
31
|
-
@delayed_jobs_max_attempts_reached_total.observe(1,
|
32
|
-
@delayed_job_duration_seconds_summary.observe(obj["duration"],
|
33
|
-
@delayed_job_duration_seconds_summary.observe(obj["duration"],
|
34
|
-
@delayed_job_duration_seconds_summary.observe(obj["duration"],
|
35
|
-
@delayed_job_attempts_summary.observe(obj["attempts"],
|
36
|
-
@delayed_jobs_enqueued.observe(obj["enqueued"],
|
37
|
-
@delayed_jobs_pending.observe(obj["pending"],
|
27
|
+
@delayed_job_duration_seconds.observe(obj["duration"], counter_labels)
|
28
|
+
@delayed_jobs_total.observe(1, counter_labels)
|
29
|
+
@delayed_failed_jobs_total.observe(1, counter_labels) if !obj["success"]
|
30
|
+
@delayed_jobs_max_attempts_reached_total.observe(1, counter_labels) if obj["attempts"] >= obj["max_attempts"]
|
31
|
+
@delayed_job_duration_seconds_summary.observe(obj["duration"], counter_labels)
|
32
|
+
@delayed_job_duration_seconds_summary.observe(obj["duration"], counter_labels.merge(status: "success")) if obj["success"]
|
33
|
+
@delayed_job_duration_seconds_summary.observe(obj["duration"], counter_labels.merge(status: "failed")) if !obj["success"]
|
34
|
+
@delayed_job_attempts_summary.observe(obj["attempts"], counter_labels) if obj["success"]
|
35
|
+
@delayed_jobs_enqueued.observe(obj["enqueued"], gauge_labels)
|
36
|
+
@delayed_jobs_pending.observe(obj["pending"], gauge_labels)
|
38
37
|
end
|
39
38
|
|
40
39
|
def metrics
|
@@ -77,12 +76,12 @@ module PrometheusExporter::Server
|
|
77
76
|
"delayed_jobs_max_attempts_reached_total", "Total number of delayed jobs that reached max attempts.")
|
78
77
|
|
79
78
|
@delayed_job_duration_seconds_summary =
|
80
|
-
PrometheusExporter::Metric::
|
81
|
-
|
79
|
+
PrometheusExporter::Metric::Base.default_aggregation.new("delayed_job_duration_seconds_summary",
|
80
|
+
"Summary of the time it takes jobs to execute.")
|
82
81
|
|
83
82
|
@delayed_job_attempts_summary =
|
84
|
-
PrometheusExporter::Metric::
|
85
|
-
|
83
|
+
PrometheusExporter::Metric::Base.default_aggregation.new("delayed_job_attempts_summary",
|
84
|
+
"Summary of the amount of attempts it takes delayed jobs to succeed.")
|
86
85
|
end
|
87
86
|
end
|
88
87
|
end
|
@@ -4,13 +4,13 @@ module PrometheusExporter::Server
|
|
4
4
|
class PumaCollector < TypeCollector
|
5
5
|
MAX_PUMA_METRIC_AGE = 30
|
6
6
|
PUMA_GAUGES = {
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
workers: "Number of puma workers.",
|
8
|
+
booted_workers: "Number of puma workers booted.",
|
9
|
+
old_workers: "Number of old puma workers.",
|
10
|
+
running_threads: "Number of puma threads currently running.",
|
11
|
+
request_backlog: "Number of requests waiting to be processed by a puma thread.",
|
12
|
+
thread_pool_capacity: "Number of puma threads available at current scale.",
|
13
|
+
max_threads: "Number of puma threads at available at max scale.",
|
14
14
|
}
|
15
15
|
|
16
16
|
def initialize
|
@@ -4,12 +4,12 @@ module PrometheusExporter::Server
|
|
4
4
|
class ResqueCollector < TypeCollector
|
5
5
|
MAX_RESQUE_METRIC_AGE = 30
|
6
6
|
RESQUE_GAUGES = {
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
processed_jobs: "Total number of processed Resque jobs.",
|
8
|
+
failed_jobs: "Total number of failed Resque jobs.",
|
9
|
+
pending_jobs: "Total number of pending Resque jobs.",
|
10
|
+
queues: "Total number of Resque queues.",
|
11
|
+
workers: "Total number of Resque workers running.",
|
12
|
+
working: "Total number of Resque workers working."
|
13
13
|
}
|
14
14
|
|
15
15
|
def initialize
|
@@ -17,6 +17,7 @@ module PrometheusExporter::Server
|
|
17
17
|
@prefix = nil
|
18
18
|
@auth = nil
|
19
19
|
@realm = nil
|
20
|
+
@histogram = nil
|
20
21
|
|
21
22
|
options.each do |k, v|
|
22
23
|
send("#{k}=", v) if self.class.method_defined?("#{k}=")
|
@@ -27,6 +28,10 @@ module PrometheusExporter::Server
|
|
27
28
|
PrometheusExporter::Metric::Base.default_prefix = prefix
|
28
29
|
PrometheusExporter::Metric::Base.default_labels = label
|
29
30
|
|
31
|
+
if histogram
|
32
|
+
PrometheusExporter::Metric::Base.default_aggregation = PrometheusExporter::Metric::Histogram
|
33
|
+
end
|
34
|
+
|
30
35
|
register_type_collectors
|
31
36
|
|
32
37
|
unless collector.is_a?(PrometheusExporter::Server::CollectorBase)
|
@@ -47,7 +52,7 @@ module PrometheusExporter::Server
|
|
47
52
|
end
|
48
53
|
|
49
54
|
attr_accessor :unicorn_listen_address, :unicorn_pid_file
|
50
|
-
attr_writer :prefix, :port, :bind, :collector_class, :type_collectors, :timeout, :verbose, :server_class, :label, :auth, :realm
|
55
|
+
attr_writer :prefix, :port, :bind, :collector_class, :type_collectors, :timeout, :verbose, :server_class, :label, :auth, :realm, :histogram
|
51
56
|
|
52
57
|
def auth
|
53
58
|
@auth || nil
|
@@ -98,6 +103,10 @@ module PrometheusExporter::Server
|
|
98
103
|
@label ||= PrometheusExporter::DEFAULT_LABEL
|
99
104
|
end
|
100
105
|
|
106
|
+
def histogram
|
107
|
+
@histogram || false
|
108
|
+
end
|
109
|
+
|
101
110
|
private
|
102
111
|
|
103
112
|
def register_type_collectors
|
@@ -52,7 +52,7 @@ module PrometheusExporter::Server
|
|
52
52
|
if !@sidekiq_jobs_total
|
53
53
|
|
54
54
|
@sidekiq_job_duration_seconds =
|
55
|
-
PrometheusExporter::Metric::
|
55
|
+
PrometheusExporter::Metric::Base.default_aggregation.new(
|
56
56
|
"sidekiq_job_duration_seconds", "Total time spent in sidekiq jobs.")
|
57
57
|
|
58
58
|
@sidekiq_jobs_total =
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PrometheusExporter::Server
|
4
|
+
class SidekiqProcessCollector < PrometheusExporter::Server::TypeCollector
|
5
|
+
MAX_SIDEKIQ_METRIC_AGE = 60
|
6
|
+
|
7
|
+
SIDEKIQ_PROCESS_GAUGES = {
|
8
|
+
'busy' => 'Number of running jobs',
|
9
|
+
'concurrency' => 'Maximum concurrency',
|
10
|
+
}.freeze
|
11
|
+
|
12
|
+
attr_reader :sidekiq_metrics, :gauges
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@sidekiq_metrics = []
|
16
|
+
@gauges = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def type
|
20
|
+
'sidekiq_process'
|
21
|
+
end
|
22
|
+
|
23
|
+
def metrics
|
24
|
+
sidekiq_metrics.map do |metric|
|
25
|
+
labels = metric.fetch('labels', {})
|
26
|
+
SIDEKIQ_PROCESS_GAUGES.map do |name, help|
|
27
|
+
if (value = metric[name])
|
28
|
+
gauge = gauges[name] ||= PrometheusExporter::Metric::Gauge.new("sidekiq_process_#{name}", help)
|
29
|
+
gauges[name].observe(value, labels)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
gauges.values
|
35
|
+
end
|
36
|
+
|
37
|
+
def collect(object)
|
38
|
+
now = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
39
|
+
process = object['process']
|
40
|
+
|
41
|
+
process["created_at"] = now
|
42
|
+
sidekiq_metrics.delete_if { |metric| metric['created_at'] + MAX_SIDEKIQ_METRIC_AGE < now }
|
43
|
+
sidekiq_metrics << process
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -6,9 +6,9 @@ class PrometheusExporter::Server::UnicornCollector < PrometheusExporter::Server:
|
|
6
6
|
MAX_UNICORN_METRIC_AGE = 60
|
7
7
|
|
8
8
|
UNICORN_GAUGES = {
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
workers: 'Number of unicorn workers.',
|
10
|
+
active_workers: 'Number of active unicorn workers',
|
11
|
+
request_backlog: 'Number of requests waiting to be processed by a unicorn worker.'
|
12
12
|
}.freeze
|
13
13
|
|
14
14
|
def initialize
|
@@ -33,22 +33,22 @@ module PrometheusExporter::Server
|
|
33
33
|
"Total HTTP requests from web app."
|
34
34
|
)
|
35
35
|
|
36
|
-
@metrics["http_duration_seconds"] = @http_duration_seconds = PrometheusExporter::Metric::
|
36
|
+
@metrics["http_duration_seconds"] = @http_duration_seconds = PrometheusExporter::Metric::Base.default_aggregation.new(
|
37
37
|
"http_duration_seconds",
|
38
38
|
"Time spent in HTTP reqs in seconds."
|
39
39
|
)
|
40
40
|
|
41
|
-
@metrics["http_redis_duration_seconds"] = @http_redis_duration_seconds = PrometheusExporter::Metric::
|
41
|
+
@metrics["http_redis_duration_seconds"] = @http_redis_duration_seconds = PrometheusExporter::Metric::Base.default_aggregation.new(
|
42
42
|
"http_redis_duration_seconds",
|
43
43
|
"Time spent in HTTP reqs in Redis, in seconds."
|
44
44
|
)
|
45
45
|
|
46
|
-
@metrics["http_sql_duration_seconds"] = @http_sql_duration_seconds = PrometheusExporter::Metric::
|
46
|
+
@metrics["http_sql_duration_seconds"] = @http_sql_duration_seconds = PrometheusExporter::Metric::Base.default_aggregation.new(
|
47
47
|
"http_sql_duration_seconds",
|
48
48
|
"Time spent in HTTP reqs in SQL in seconds."
|
49
49
|
)
|
50
50
|
|
51
|
-
@metrics["http_queue_duration_seconds"] = @http_queue_duration_seconds = PrometheusExporter::Metric::
|
51
|
+
@metrics["http_queue_duration_seconds"] = @http_queue_duration_seconds = PrometheusExporter::Metric::Base.default_aggregation.new(
|
52
52
|
"http_queue_duration_seconds",
|
53
53
|
"Time spent queueing the request in load balancer in seconds."
|
54
54
|
)
|
@@ -88,7 +88,7 @@ module PrometheusExporter::Server
|
|
88
88
|
@collector.process(block)
|
89
89
|
rescue => e
|
90
90
|
if @verbose
|
91
|
-
logger.error "\n\n#{e.inspect}\n#{e.backtrace}\n\n"
|
91
|
+
@logger.error "\n\n#{e.inspect}\n#{e.backtrace}\n\n"
|
92
92
|
end
|
93
93
|
@bad_metrics_total.observe
|
94
94
|
res.body = "Bad Metrics #{e}"
|
@@ -106,7 +106,7 @@ module PrometheusExporter::Server
|
|
106
106
|
begin
|
107
107
|
@server.start
|
108
108
|
rescue => e
|
109
|
-
logger.error "Failed to start prometheus collector web on port #{@port}: #{e}"
|
109
|
+
@logger.error "Failed to start prometheus collector web on port #{@port}: #{e}"
|
110
110
|
end
|
111
111
|
end
|
112
112
|
end
|
@@ -123,7 +123,7 @@ module PrometheusExporter::Server
|
|
123
123
|
end
|
124
124
|
rescue Timeout::Error
|
125
125
|
# we timed out ... bummer
|
126
|
-
logger.error "Generating Prometheus metrics text timed out"
|
126
|
+
@logger.error "Generating Prometheus metrics text timed out"
|
127
127
|
end
|
128
128
|
|
129
129
|
metrics = []
|
@@ -6,6 +6,7 @@ require_relative "server/web_collector"
|
|
6
6
|
require_relative "server/process_collector"
|
7
7
|
require_relative "server/sidekiq_collector"
|
8
8
|
require_relative "server/sidekiq_queue_collector"
|
9
|
+
require_relative "server/sidekiq_process_collector"
|
9
10
|
require_relative "server/delayed_job_collector"
|
10
11
|
require_relative "server/collector_base"
|
11
12
|
require_relative "server/collector"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prometheus_exporter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Saffron
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-11-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: webrick
|
@@ -243,6 +243,7 @@ files:
|
|
243
243
|
- lib/prometheus_exporter/instrumentation/resque.rb
|
244
244
|
- lib/prometheus_exporter/instrumentation/shoryuken.rb
|
245
245
|
- lib/prometheus_exporter/instrumentation/sidekiq.rb
|
246
|
+
- lib/prometheus_exporter/instrumentation/sidekiq_process.rb
|
246
247
|
- lib/prometheus_exporter/instrumentation/sidekiq_queue.rb
|
247
248
|
- lib/prometheus_exporter/instrumentation/unicorn.rb
|
248
249
|
- lib/prometheus_exporter/metric.rb
|
@@ -264,6 +265,7 @@ files:
|
|
264
265
|
- lib/prometheus_exporter/server/runner.rb
|
265
266
|
- lib/prometheus_exporter/server/shoryuken_collector.rb
|
266
267
|
- lib/prometheus_exporter/server/sidekiq_collector.rb
|
268
|
+
- lib/prometheus_exporter/server/sidekiq_process_collector.rb
|
267
269
|
- lib/prometheus_exporter/server/sidekiq_queue_collector.rb
|
268
270
|
- lib/prometheus_exporter/server/type_collector.rb
|
269
271
|
- lib/prometheus_exporter/server/unicorn_collector.rb
|
@@ -292,7 +294,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
292
294
|
version: '0'
|
293
295
|
requirements: []
|
294
296
|
rubygems_version: 3.1.6
|
295
|
-
signing_key:
|
297
|
+
signing_key:
|
296
298
|
specification_version: 4
|
297
299
|
summary: Prometheus Exporter
|
298
300
|
test_files: []
|