prometheus_exporter 0.8.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.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: []
|