prometheus_exporter 0.4.16 → 0.5.3
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/.rubocop.yml +2 -1
- data/CHANGELOG +22 -0
- data/README.md +189 -5
- data/bin/prometheus_exporter +11 -1
- data/lib/prometheus_exporter.rb +13 -0
- data/lib/prometheus_exporter/client.rb +8 -1
- data/lib/prometheus_exporter/instrumentation.rb +2 -0
- data/lib/prometheus_exporter/instrumentation/active_record.rb +1 -12
- data/lib/prometheus_exporter/instrumentation/process.rb +3 -12
- data/lib/prometheus_exporter/instrumentation/shoryuken.rb +31 -0
- data/lib/prometheus_exporter/instrumentation/sidekiq_queue.rb +39 -0
- data/lib/prometheus_exporter/metric/base.rb +8 -0
- data/lib/prometheus_exporter/metric/counter.rb +8 -0
- data/lib/prometheus_exporter/metric/gauge.rb +8 -0
- data/lib/prometheus_exporter/metric/histogram.rb +16 -0
- data/lib/prometheus_exporter/metric/summary.rb +17 -0
- data/lib/prometheus_exporter/server.rb +2 -0
- data/lib/prometheus_exporter/server/active_record_collector.rb +1 -0
- data/lib/prometheus_exporter/server/collector.rb +2 -0
- data/lib/prometheus_exporter/server/delayed_job_collector.rb +11 -0
- data/lib/prometheus_exporter/server/hutch_collector.rb +6 -0
- data/lib/prometheus_exporter/server/runner.rb +17 -28
- data/lib/prometheus_exporter/server/shoryuken_collector.rb +67 -0
- data/lib/prometheus_exporter/server/sidekiq_collector.rb +9 -0
- data/lib/prometheus_exporter/server/sidekiq_queue_collector.rb +46 -0
- data/lib/prometheus_exporter/server/web_collector.rb +5 -0
- data/lib/prometheus_exporter/server/web_server.rb +2 -1
- data/lib/prometheus_exporter/version.rb +1 -1
- data/prometheus_exporter.gemspec +16 -13
- metadata +26 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a284b77cbd17e80457e94520d18976dc3dd6fb8c238d8a90cda6513e291f01ad
|
4
|
+
data.tar.gz: 4464419fc9c67d387edd9d6d5bdfac1411d0864d29c0cd3a6f10d2f02b3d7e24
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84c2e2af95a8839cd9deecca9fbc26bacff590ae5cb3677862f1eb1d476401114406130cc78d2248cec0380e70c1b74b306e1265b3343bbac9c09d8400e692a3
|
7
|
+
data.tar.gz: 41898546588ef7eafa772252ef5ed1a8c222e4009e64ccec35d463217336597a94f1c844f3e2174e030c19a7c1b90d1028e5729cc393cf797654362f5d66b7f2
|
data/.rubocop.yml
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
inherit_gem:
|
2
|
+
rubocop-discourse: default.yml
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
0.5.3 - 29-07-2020
|
2
|
+
|
3
|
+
- FEATURE: added #remove to all metric types so users can remove specific labels if needed
|
4
|
+
|
5
|
+
0.5.2 - 01-07-2020
|
6
|
+
|
7
|
+
- FEATURE: expanded instrumentation for sidekiq
|
8
|
+
- FEATURE: configurable default labels
|
9
|
+
|
10
|
+
0.5.1 - 25-02-2020
|
11
|
+
|
12
|
+
- FEATURE: Allow configuring the default client's host and port via environment variables
|
13
|
+
|
14
|
+
0.5.0 - 14-02-2020
|
15
|
+
|
16
|
+
- Breaking change: listen only to localhost by default to prevent unintended insecure configuration
|
17
|
+
- FIX: Avoid calling `hostname` aggressively, instead cache it on the exporter instance
|
18
|
+
|
19
|
+
0.4.17 - 13-01-2020
|
20
|
+
|
21
|
+
- FEATURE: add support for `to_h` on all metrics which can be used to query existing key/values
|
22
|
+
|
1
23
|
0.4.16 - 04-11-2019
|
2
24
|
|
3
25
|
- FEATURE: Support #reset! on all metric types to reset a metric to default
|
data/README.md
CHANGED
@@ -13,6 +13,7 @@ To learn more see [Instrumenting Rails with Prometheus](https://samsaffron.com/a
|
|
13
13
|
* [Rails integration](#rails-integration)
|
14
14
|
* [Per-process stats](#per-process-stats)
|
15
15
|
* [Sidekiq metrics](#sidekiq-metrics)
|
16
|
+
* [Shoryuken metrics](#shoryuken-metrics)
|
16
17
|
* [ActiveRecord Connection Pool Metrics](#activerecord-connection-pool-metrics)
|
17
18
|
* [Delayed Job plugin](#delayed-job-plugin)
|
18
19
|
* [Hutch metrics](#hutch-message-processing-tracer)
|
@@ -23,6 +24,7 @@ To learn more see [Instrumenting Rails with Prometheus](https://samsaffron.com/a
|
|
23
24
|
* [GraphQL support](#graphql-support)
|
24
25
|
* [Metrics default prefix / labels](#metrics-default-prefix--labels)
|
25
26
|
* [Client default labels](#client-default-labels)
|
27
|
+
* [Client default host](#client-default-host)
|
26
28
|
* [Transport concerns](#transport-concerns)
|
27
29
|
* [JSON generation and parsing](#json-generation-and-parsing)
|
28
30
|
* [Contributing](#contributing)
|
@@ -62,8 +64,9 @@ require 'prometheus_exporter/server'
|
|
62
64
|
require 'prometheus_exporter/client'
|
63
65
|
require 'prometheus_exporter/instrumentation'
|
64
66
|
|
67
|
+
# bind is the address, on which the webserver will listen
|
65
68
|
# port is the port that will provide the /metrics route
|
66
|
-
server = PrometheusExporter::Server::WebServer.new port: 12345
|
69
|
+
server = PrometheusExporter::Server::WebServer.new bind: 'localhost', port: 12345
|
67
70
|
server.start
|
68
71
|
|
69
72
|
# wire up a default local client
|
@@ -115,7 +118,7 @@ In some cases (for example, unicorn or puma clusters) you may want to aggregate
|
|
115
118
|
|
116
119
|
Simplest way to achieve this is to use the built-in collector.
|
117
120
|
|
118
|
-
First, run an exporter on your desired port (we use the default port of 9394):
|
121
|
+
First, run an exporter on your desired port (we use the default bind to localhost and port of 9394):
|
119
122
|
|
120
123
|
```
|
121
124
|
$ prometheus_exporter
|
@@ -187,13 +190,30 @@ Ensure you run the exporter in a monitored background process:
|
|
187
190
|
$ bundle exec prometheus_exporter
|
188
191
|
```
|
189
192
|
|
193
|
+
#### Metrics collected by Rails integration middleware
|
194
|
+
|
195
|
+
| Type | Name | Description |
|
196
|
+
| --- | --- | --- |
|
197
|
+
| Counter | `http_requests_total` | Total HTTP requests from web app |
|
198
|
+
| Summary | `http_duration_seconds` | Time spent in HTTP reqs in seconds |
|
199
|
+
| Summary | `http_redis_duration_seconds`¹ | Time spent in HTTP reqs in Redis, in seconds |
|
200
|
+
| Summary | `http_sql_duration_seconds`² | Time spent in HTTP reqs in SQL in seconds |
|
201
|
+
| Summary | `http_queue_duration_seconds`³ | Time spent queueing the request in load balancer in seconds |
|
202
|
+
|
203
|
+
All metrics have a `controller` and an `action` label.
|
204
|
+
`http_requests_total` additionally has a (HTTP response) `status` label.
|
205
|
+
|
206
|
+
¹) Only available when Redis is used.
|
207
|
+
²) Only available when Mysql or PostgreSQL are used.
|
208
|
+
³) Only available when [Instrumenting Request Queueing Time](#instrumenting-request-queueing-time) is set up.
|
209
|
+
|
190
210
|
#### Activerecord Connection Pool Metrics
|
191
211
|
|
192
212
|
This collects activerecord connection pool metrics.
|
193
213
|
|
194
214
|
It supports injection of custom labels and the connection config options (`username`, `database`, `host`, `port`) as labels.
|
195
215
|
|
196
|
-
For Puma single mode
|
216
|
+
For Puma single mode
|
197
217
|
```ruby
|
198
218
|
#in puma.rb
|
199
219
|
require 'prometheus_exporter/instrumentation'
|
@@ -219,7 +239,7 @@ end
|
|
219
239
|
For Unicorn / Passenger
|
220
240
|
|
221
241
|
```ruby
|
222
|
-
after_fork do
|
242
|
+
after_fork do |_server, _worker|
|
223
243
|
require 'prometheus_exporter/instrumentation'
|
224
244
|
PrometheusExporter::Instrumentation::ActiveRecord.start(
|
225
245
|
custom_labels: { type: "unicorn_worker" }, #optional params
|
@@ -241,6 +261,19 @@ Sidekiq.configure_server do |config|
|
|
241
261
|
end
|
242
262
|
```
|
243
263
|
|
264
|
+
##### Metrics collected by ActiveRecord Instrumentation
|
265
|
+
|
266
|
+
| Type | Name | Description |
|
267
|
+
| --- | --- | --- |
|
268
|
+
| Gauge | `active_record_connection_pool_connections` | Total connections in pool |
|
269
|
+
| Gauge | `active_record_connection_pool_busy` | Connections in use in pool |
|
270
|
+
| Gauge | `active_record_connection_pool_dead` | Dead connections in pool |
|
271
|
+
| Gauge | `active_record_connection_pool_idle` | Idle connections in pool |
|
272
|
+
| Gauge | `active_record_connection_pool_waiting` | Connection requests waiting |
|
273
|
+
| Gauge | `active_record_connection_pool_size` | Maximum allowed connection pool size |
|
274
|
+
|
275
|
+
All metrics collected by the ActiveRecord integration include at least the following labels: `pid` (of the process the stats where collected in), `pool_name`, any labels included in the `config_labels` option (prefixed with `dbconfig_`, example: `dbconfig_host`), and all custom labels provided with the `custom_labels` option.
|
276
|
+
|
244
277
|
#### Per-process stats
|
245
278
|
|
246
279
|
You may also be interested in per-process stats. This collects memory and GC stats:
|
@@ -257,11 +290,30 @@ end
|
|
257
290
|
# in unicorn/puma/passenger be sure to run a new process instrumenter after fork
|
258
291
|
after_fork do
|
259
292
|
require 'prometheus_exporter/instrumentation'
|
260
|
-
PrometheusExporter::Instrumentation::Process.start(type:"web")
|
293
|
+
PrometheusExporter::Instrumentation::Process.start(type: "web")
|
261
294
|
end
|
262
295
|
|
263
296
|
```
|
264
297
|
|
298
|
+
##### Metrics collected by Process Instrumentation
|
299
|
+
|
300
|
+
| Type | Name | Description |
|
301
|
+
| --- | --- | --- |
|
302
|
+
| Gauge | `heap_free_slots` | Free ruby heap slots |
|
303
|
+
| Gauge | `heap_live_slots` | Used ruby heap slots |
|
304
|
+
| Gauge | `v8_heap_size`* | Total JavaScript V8 heap size (bytes) |
|
305
|
+
| Gauge | `v8_used_heap_size`* | Total used JavaScript V8 heap size (bytes) |
|
306
|
+
| Gauge | `v8_physical_size`* | Physical size consumed by V8 heaps |
|
307
|
+
| Gauge | `v8_heap_count`* | Number of V8 contexts running |
|
308
|
+
| Gauge | `rss` | Total RSS used by process |
|
309
|
+
| Counter | `major_gc_ops_total` | Major GC operations by process |
|
310
|
+
| Counter | `minor_gc_ops_total` | Minor GC operations by process |
|
311
|
+
| Counter | `allocated_objects_total` | Total number of allocated objects by process |
|
312
|
+
|
313
|
+
_Metrics marked with * are only collected when `MiniRacer` is defined._
|
314
|
+
|
315
|
+
Metrics collected by Process instrumentation include labels `type` (as given with the `type` option), `pid` (of the process the stats where collected in), and any custom labels given to `Process.start` with the `labels` option.
|
316
|
+
|
265
317
|
#### Sidekiq metrics
|
266
318
|
|
267
319
|
Including Sidekiq metrics (how many jobs ran? how many failed? how long did they take? how many are dead? how many were restarted?)
|
@@ -276,6 +328,17 @@ Sidekiq.configure_server do |config|
|
|
276
328
|
end
|
277
329
|
```
|
278
330
|
|
331
|
+
To monitor Queue size and latency:
|
332
|
+
|
333
|
+
```ruby
|
334
|
+
Sidekiq.configure_server do |config|
|
335
|
+
config.on :startup do
|
336
|
+
require 'prometheus_exporter/instrumentation'
|
337
|
+
PrometheusExporter::Instrumentation::SidekiqQueue.start
|
338
|
+
end
|
339
|
+
end
|
340
|
+
```
|
341
|
+
|
279
342
|
To monitor Sidekiq process info:
|
280
343
|
|
281
344
|
```ruby
|
@@ -297,6 +360,59 @@ Sometimes the Sidekiq server shuts down before it can send metrics, that were ge
|
|
297
360
|
end
|
298
361
|
```
|
299
362
|
|
363
|
+
##### Metrics collected by Sidekiq Instrumentation
|
364
|
+
|
365
|
+
**PrometheusExporter::Instrumentation::Sidekiq**
|
366
|
+
| Type | Name | Description |
|
367
|
+
| --- | --- | --- |
|
368
|
+
| Counter | `sidekiq_job_duration_seconds` | Total time spent in sidekiq jobs |
|
369
|
+
| Counter | `sidekiq_jobs_total` | Total number of sidekiq jobs executed |
|
370
|
+
| Counter | `sidekiq_restarted_jobs_total` | Total number of sidekiq jobs that we restarted because of a sidekiq shutdown |
|
371
|
+
| Counter | `sidekiq_failed_jobs_total` | Total number of failed sidekiq jobs |
|
372
|
+
|
373
|
+
All metrics have a `job_name` label.
|
374
|
+
|
375
|
+
**PrometheusExporter::Instrumentation::Sidekiq.death_handler**
|
376
|
+
| Type | Name | Description |
|
377
|
+
| --- | --- | --- |
|
378
|
+
| Counter | `sidekiq_dead_jobs_total` | Total number of dead sidekiq jobs |
|
379
|
+
|
380
|
+
This metric also has a `job_name` label.
|
381
|
+
|
382
|
+
**PrometheusExporter::Instrumentation::SidekiqQueue**
|
383
|
+
| Type | Name | Description |
|
384
|
+
| --- | --- | --- |
|
385
|
+
| Gauge | `sidekiq_queue_backlog_total` | Size of the sidekiq queue |
|
386
|
+
| Gauge | `sidekiq_queue_latency_seconds` | Latency of the sidekiq queue |
|
387
|
+
|
388
|
+
Both metrics will have a `queue` label with the name of the queue.
|
389
|
+
|
390
|
+
_See [Metrics collected by Process Instrumentation](#metrics-collected-by-process-instrumentation) for a list of metrics the Process instrumentation will produce._
|
391
|
+
|
392
|
+
#### Shoryuken metrics
|
393
|
+
|
394
|
+
For Shoryuken metrics (how many jobs ran? how many failed? how long did they take? how many were restarted?)
|
395
|
+
|
396
|
+
```ruby
|
397
|
+
Shoryuken.configure_server do |config|
|
398
|
+
config.server_middleware do |chain|
|
399
|
+
require 'prometheus_exporter/instrumentation'
|
400
|
+
chain.add PrometheusExporter::Instrumentation::Shoryuken
|
401
|
+
end
|
402
|
+
end
|
403
|
+
```
|
404
|
+
|
405
|
+
##### Metrics collected by Shoryuken Instrumentation
|
406
|
+
|
407
|
+
| Type | Name | Description |
|
408
|
+
| --- | --- | --- |
|
409
|
+
| Counter | `shoryuken_job_duration_seconds` | Total time spent in shoryuken jobs |
|
410
|
+
| Counter | `shoryuken_jobs_total` | Total number of shoryuken jobs executed |
|
411
|
+
| Counter | `shoryuken_restarted_jobs_total` | Total number of shoryuken jobs that we restarted because of a shoryuken shutdown |
|
412
|
+
| Counter | `shoryuken_failed_jobs_total` | Total number of failed shoryuken jobs |
|
413
|
+
|
414
|
+
All metrics have labels for `job_name` and `queue_name`.
|
415
|
+
|
300
416
|
#### Delayed Job plugin
|
301
417
|
|
302
418
|
In an initializer:
|
@@ -308,6 +424,19 @@ unless Rails.env == "test"
|
|
308
424
|
end
|
309
425
|
```
|
310
426
|
|
427
|
+
##### Metrics collected by Delayed Job Instrumentation
|
428
|
+
|
429
|
+
| Type | Name | Description | Labels |
|
430
|
+
| --- | --- | --- | --- |
|
431
|
+
| Counter | `delayed_job_duration_seconds` | Total time spent in delayed jobs | `job_name` |
|
432
|
+
| Counter | `delayed_jobs_total` | Total number of delayed jobs executed | `job_name` |
|
433
|
+
| Gauge | `delayed_jobs_enqueued` | Number of enqueued delayed jobs | - |
|
434
|
+
| Gauge | `delayed_jobs_pending` | Number of pending delayed jobs | - |
|
435
|
+
| Counter | `delayed_failed_jobs_total` | Total number failed delayed jobs executed | `job_name` |
|
436
|
+
| Counter | `delayed_jobs_max_attempts_reached_total` | Total number of delayed jobs that reached max attempts | - |
|
437
|
+
| Summary | `delayed_job_duration_seconds_summary` | Summary of the time it takes jobs to execute | `status` |
|
438
|
+
| Summary | `delayed_job_attempts_summary` | Summary of the amount of attempts it takes delayed jobs to succeed | - |
|
439
|
+
|
311
440
|
#### Hutch Message Processing Tracer
|
312
441
|
|
313
442
|
Capture [Hutch](https://github.com/gocardless/hutch) metrics (how many jobs ran? how many failed? how long did they take?)
|
@@ -319,6 +448,16 @@ unless Rails.env == "test"
|
|
319
448
|
end
|
320
449
|
```
|
321
450
|
|
451
|
+
##### Metrics collected by Hutch Instrumentation
|
452
|
+
|
453
|
+
| Type | Name | Description |
|
454
|
+
| --- | --- | --- |
|
455
|
+
| Counter | `hutch_job_duration_seconds` | Total time spent in hutch jobs |
|
456
|
+
| Counter | `hutch_jobs_total` | Total number of hutch jobs executed |
|
457
|
+
| Counter | `hutch_failed_jobs_total` | Total number failed hutch jobs executed |
|
458
|
+
|
459
|
+
All metrics have a `job_name` label.
|
460
|
+
|
322
461
|
#### Instrumenting Request Queueing Time
|
323
462
|
|
324
463
|
Request Queueing is defined as the time it takes for a request to reach your application (instrumented by this `prometheus_exporter`) from farther upstream (as your load balancer). A high queueing time usually means that your backend cannot handle all the incoming requests in time, so they queue up (= you should see if you need to add more capacity).
|
@@ -343,6 +482,20 @@ after_worker_boot do
|
|
343
482
|
end
|
344
483
|
```
|
345
484
|
|
485
|
+
#### Metrics collected by Puma Instrumentation
|
486
|
+
|
487
|
+
| Type | Name | Description |
|
488
|
+
| --- | --- | --- |
|
489
|
+
| Gauge | `puma_workers_total` | Number of puma workers |
|
490
|
+
| Gauge | `puma_booted_workers_total` | Number of puma workers booted |
|
491
|
+
| Gauge | `puma_old_workers_total` | Number of old puma workers |
|
492
|
+
| Gauge | `puma_running_threads_total` | Number of puma threads currently running |
|
493
|
+
| Gauge | `puma_request_backlog_total` | Number of requests waiting to be processed by a puma thread |
|
494
|
+
| Gauge | `puma_thread_pool_capacity_total` | Number of puma threads available at current scale |
|
495
|
+
| Gauge | `puma_max_threads_total` | Number of puma threads at available at max scale |
|
496
|
+
|
497
|
+
All metrics may have a `phase` label.
|
498
|
+
|
346
499
|
### Unicorn process metrics
|
347
500
|
|
348
501
|
In order to gather metrics from unicorn processes, we use `rainbows`, which exposes `Rainbows::Linux.tcp_listener_stats` to gather information about active workers and queued requests. To start monitoring your unicorn processes, you'll need to know both the path to unicorn PID file and the listen address (`pid_file` and `listen` in your unicorn config file)
|
@@ -358,6 +511,14 @@ prometheus_exporter --unicorn-master /var/run/unicorn.pid --unicorn-listen-addre
|
|
358
511
|
|
359
512
|
Note: You must install the `raindrops` gem in your `Gemfile` or locally.
|
360
513
|
|
514
|
+
#### Metrics collected by Unicorn Instrumentation
|
515
|
+
|
516
|
+
| Type | Name | Description |
|
517
|
+
| --- | --- | --- |
|
518
|
+
| Gauge | `unicorn_workers_total` | Number of unicorn workers |
|
519
|
+
| Gauge | `unicorn_active_workers_total` | Number of active unicorn workers |
|
520
|
+
| Gauge | `unicorn_request_backlog_total` | Number of requests waiting to be processed by a unicorn worker |
|
521
|
+
|
361
522
|
### Custom type collectors
|
362
523
|
|
363
524
|
In some cases you may have custom metrics you want to ship the collector in a batch. In this case you may still be interested in the base collector behavior, but would like to add your own special messages.
|
@@ -526,6 +687,26 @@ ruby_web_requests{hostname="app-server-01",route="test/route"} 1
|
|
526
687
|
ruby_web_requests{hostname="app-server-01"} 1
|
527
688
|
```
|
528
689
|
|
690
|
+
### Exporter Process Configuration
|
691
|
+
|
692
|
+
When running the process for `prometheus_exporter` using `bin/prometheus_exporter`, there are several configurations that
|
693
|
+
can be passed in:
|
694
|
+
|
695
|
+
The following will run the process at
|
696
|
+
- Port `8080` (default `9394`)
|
697
|
+
- Bind to `0.0.0.0` (default `localhost`)
|
698
|
+
- Timeout in `1 second` for metrics endpoint (default `2 seconds`)
|
699
|
+
- Metric prefix as `foo_` (default `ruby_`)
|
700
|
+
- Default labels as `{environment: "integration", foo: "bar"}`
|
701
|
+
|
702
|
+
```bash
|
703
|
+
prometheus_exporter -p 8080 \
|
704
|
+
-b 0.0.0.0 \
|
705
|
+
-t 1 \
|
706
|
+
--label '{"environment": "integration", "foo": "bar"}' \
|
707
|
+
--prefix 'foo_'
|
708
|
+
```
|
709
|
+
|
529
710
|
### Client default labels
|
530
711
|
|
531
712
|
You can specify a default label for instrumentation metrics sent by a specific client. For example:
|
@@ -545,6 +726,9 @@ Will result in:
|
|
545
726
|
http_requests_total{controller="home","action"="index",service="app-server-01",app_name="app-01"} 2
|
546
727
|
http_requests_total{service="app-server-01",app_name="app-01"} 1
|
547
728
|
```
|
729
|
+
### Client default host
|
730
|
+
|
731
|
+
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`.
|
548
732
|
|
549
733
|
## Transport concerns
|
550
734
|
|
data/bin/prometheus_exporter
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'optparse'
|
5
|
+
require 'json'
|
5
6
|
|
6
7
|
require_relative "./../lib/prometheus_exporter"
|
7
8
|
require_relative "./../lib/prometheus_exporter/server"
|
@@ -19,6 +20,12 @@ def run
|
|
19
20
|
"Port exporter should listen on (default: #{PrometheusExporter::DEFAULT_PORT})") do |o|
|
20
21
|
options[:port] = o.to_i
|
21
22
|
end
|
23
|
+
opt.on('-b',
|
24
|
+
'--bind STRING',
|
25
|
+
String,
|
26
|
+
"IP address exporter should listen on (default: #{PrometheusExporter::DEFAULT_BIND_ADDRESS})") do |o|
|
27
|
+
options[:bind] = o.to_s
|
28
|
+
end
|
22
29
|
opt.on('-t',
|
23
30
|
'--timeout INTEGER',
|
24
31
|
Integer,
|
@@ -28,6 +35,9 @@ def run
|
|
28
35
|
opt.on('--prefix METRIC_PREFIX', "Prefix to apply to all metrics (default: #{PrometheusExporter::DEFAULT_PREFIX})") do |o|
|
29
36
|
options[:prefix] = o.to_s
|
30
37
|
end
|
38
|
+
opt.on('--label METRIC_LABEL', "Label to apply to all metrics (default: #{PrometheusExporter::DEFAULT_LABEL})") do |o|
|
39
|
+
options[:label] = JSON.parse(o.to_s)
|
40
|
+
end
|
31
41
|
opt.on('-c', '--collector FILE', String, "(optional) Custom collector to run") do |o|
|
32
42
|
custom_collector_filename = o.to_s
|
33
43
|
end
|
@@ -81,7 +91,7 @@ def run
|
|
81
91
|
|
82
92
|
runner = PrometheusExporter::Server::Runner.new(options)
|
83
93
|
|
84
|
-
puts "#{Time.now} Starting prometheus exporter on
|
94
|
+
puts "#{Time.now} Starting prometheus exporter on #{runner.bind}:#{runner.port}"
|
85
95
|
runner.start
|
86
96
|
sleep
|
87
97
|
end
|
data/lib/prometheus_exporter.rb
CHANGED
@@ -7,7 +7,9 @@ require "thread"
|
|
7
7
|
module PrometheusExporter
|
8
8
|
# per: https://github.com/prometheus/prometheus/wiki/Default-port-allocations
|
9
9
|
DEFAULT_PORT = 9394
|
10
|
+
DEFAULT_BIND_ADDRESS = 'localhost'
|
10
11
|
DEFAULT_PREFIX = 'ruby_'
|
12
|
+
DEFAULT_LABEL = {}
|
11
13
|
DEFAULT_TIMEOUT = 2
|
12
14
|
|
13
15
|
class OjCompat
|
@@ -19,6 +21,17 @@ module PrometheusExporter
|
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
24
|
+
def self.hostname
|
25
|
+
@hostname ||=
|
26
|
+
begin
|
27
|
+
require 'socket'
|
28
|
+
Socket.gethostname
|
29
|
+
rescue => e
|
30
|
+
STDERR.puts "Unable to lookup hostname #{e}"
|
31
|
+
"unknown-host"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
22
35
|
def self.detect_json_serializer(preferred)
|
23
36
|
if preferred.nil?
|
24
37
|
preferred = :oj if has_oj?
|
@@ -53,7 +53,14 @@ module PrometheusExporter
|
|
53
53
|
MAX_SOCKET_AGE = 25
|
54
54
|
MAX_QUEUE_SIZE = 10_000
|
55
55
|
|
56
|
-
def initialize(
|
56
|
+
def initialize(
|
57
|
+
host: ENV.fetch('PROMETHEUS_EXPORTER_HOST', 'localhost'),
|
58
|
+
port: ENV.fetch('PROMETHEUS_EXPORTER_PORT', PrometheusExporter::DEFAULT_PORT),
|
59
|
+
max_queue_size: nil,
|
60
|
+
thread_sleep: 0.5,
|
61
|
+
json_serializer: nil,
|
62
|
+
custom_labels: nil
|
63
|
+
)
|
57
64
|
@metrics = []
|
58
65
|
|
59
66
|
@queue = Queue.new
|
@@ -4,8 +4,10 @@ require_relative "client"
|
|
4
4
|
require_relative "instrumentation/process"
|
5
5
|
require_relative "instrumentation/method_profiler"
|
6
6
|
require_relative "instrumentation/sidekiq"
|
7
|
+
require_relative "instrumentation/sidekiq_queue"
|
7
8
|
require_relative "instrumentation/delayed_job"
|
8
9
|
require_relative "instrumentation/puma"
|
9
10
|
require_relative "instrumentation/hutch"
|
10
11
|
require_relative "instrumentation/unicorn"
|
11
12
|
require_relative "instrumentation/active_record"
|
13
|
+
require_relative "instrumentation/shoryuken"
|
@@ -51,17 +51,6 @@ module PrometheusExporter::Instrumentation
|
|
51
51
|
def initialize(metric_labels, config_labels)
|
52
52
|
@metric_labels = metric_labels
|
53
53
|
@config_labels = config_labels
|
54
|
-
@hostname = nil
|
55
|
-
end
|
56
|
-
|
57
|
-
def hostname
|
58
|
-
@hostname ||=
|
59
|
-
begin
|
60
|
-
`hostname`.strip
|
61
|
-
rescue => e
|
62
|
-
STDERR.puts "Unable to lookup hostname #{e}"
|
63
|
-
"unknown-host"
|
64
|
-
end
|
65
54
|
end
|
66
55
|
|
67
56
|
def collect
|
@@ -87,7 +76,7 @@ module PrometheusExporter::Instrumentation
|
|
87
76
|
metric = {
|
88
77
|
pid: pid,
|
89
78
|
type: "active_record",
|
90
|
-
hostname: hostname,
|
79
|
+
hostname: ::PrometheusExporter.hostname,
|
91
80
|
metric_labels: labels
|
92
81
|
}
|
93
82
|
metric.merge!(pool.stat)
|
@@ -3,6 +3,8 @@
|
|
3
3
|
# collects stats from currently running process
|
4
4
|
module PrometheusExporter::Instrumentation
|
5
5
|
class Process
|
6
|
+
@thread = nil if !defined?(@thread)
|
7
|
+
|
6
8
|
def self.start(client: nil, type: "ruby", frequency: 30, labels: nil)
|
7
9
|
|
8
10
|
metric_labels =
|
@@ -42,24 +44,13 @@ module PrometheusExporter::Instrumentation
|
|
42
44
|
|
43
45
|
def initialize(metric_labels)
|
44
46
|
@metric_labels = metric_labels
|
45
|
-
@hostname = nil
|
46
|
-
end
|
47
|
-
|
48
|
-
def hostname
|
49
|
-
@hostname ||=
|
50
|
-
begin
|
51
|
-
`hostname`.strip
|
52
|
-
rescue => e
|
53
|
-
STDERR.puts "Unable to lookup hostname #{e}"
|
54
|
-
"unknown-host"
|
55
|
-
end
|
56
47
|
end
|
57
48
|
|
58
49
|
def collect
|
59
50
|
metric = {}
|
60
51
|
metric[:type] = "process"
|
61
52
|
metric[:metric_labels] = @metric_labels
|
62
|
-
metric[:hostname] = hostname
|
53
|
+
metric[:hostname] = ::PrometheusExporter.hostname
|
63
54
|
collect_gc_stats(metric)
|
64
55
|
collect_v8_stats(metric)
|
65
56
|
collect_process_stats(metric)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PrometheusExporter::Instrumentation
|
4
|
+
class Shoryuken
|
5
|
+
|
6
|
+
def initialize(client: nil)
|
7
|
+
@client = client || PrometheusExporter::Client.default
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(worker, queue, msg, body)
|
11
|
+
success = false
|
12
|
+
start = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
13
|
+
result = yield
|
14
|
+
success = true
|
15
|
+
result
|
16
|
+
rescue ::Shoryuken::Shutdown => e
|
17
|
+
shutdown = true
|
18
|
+
raise e
|
19
|
+
ensure
|
20
|
+
duration = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start
|
21
|
+
@client.send_json(
|
22
|
+
type: "shoryuken",
|
23
|
+
queue: queue,
|
24
|
+
name: worker.class.name,
|
25
|
+
success: success,
|
26
|
+
shutdown: shutdown,
|
27
|
+
duration: duration
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PrometheusExporter::Instrumentation
|
4
|
+
class SidekiqQueue
|
5
|
+
def self.start(client: nil, frequency: 30)
|
6
|
+
client ||= PrometheusExporter::Client.default
|
7
|
+
sidekiq_queue_collector = new
|
8
|
+
|
9
|
+
Thread.new do
|
10
|
+
loop do
|
11
|
+
begin
|
12
|
+
client.send_json(sidekiq_queue_collector.collect)
|
13
|
+
rescue StandardError => e
|
14
|
+
STDERR.puts("Prometheus Exporter Failed To Collect Sidekiq Queue metrics #{e}")
|
15
|
+
ensure
|
16
|
+
sleep frequency
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def collect
|
23
|
+
{
|
24
|
+
type: 'sidekiq_queue',
|
25
|
+
queues: collect_queue_stats
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def collect_queue_stats
|
30
|
+
::Sidekiq::Queue.all.map do |queue|
|
31
|
+
{
|
32
|
+
backlog_total: queue.size,
|
33
|
+
latency_seconds: queue.latency.to_i,
|
34
|
+
labels: { queue: queue.name }
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
module PrometheusExporter::Metric
|
4
4
|
class Base
|
5
|
+
|
6
|
+
@default_prefix = nil if !defined?(@default_prefix)
|
7
|
+
@default_labels = nil if !defined?(@default_labels)
|
8
|
+
|
5
9
|
# prefix applied to all metrics
|
6
10
|
def self.default_prefix=(name)
|
7
11
|
@default_prefix = name
|
@@ -38,6 +42,10 @@ module PrometheusExporter::Metric
|
|
38
42
|
raise "Not implemented"
|
39
43
|
end
|
40
44
|
|
45
|
+
def to_h
|
46
|
+
raise "Not implemented"
|
47
|
+
end
|
48
|
+
|
41
49
|
def from_json(json)
|
42
50
|
json = JSON.parse(json) if String === json
|
43
51
|
@name = json["name"]
|
@@ -23,6 +23,14 @@ module PrometheusExporter::Metric
|
|
23
23
|
end.join("\n")
|
24
24
|
end
|
25
25
|
|
26
|
+
def to_h
|
27
|
+
@data.dup
|
28
|
+
end
|
29
|
+
|
30
|
+
def remove(labels)
|
31
|
+
@data.delete(labels)
|
32
|
+
end
|
33
|
+
|
26
34
|
def observe(increment = 1, labels = {})
|
27
35
|
@data[labels] ||= 0
|
28
36
|
@data[labels] += increment
|
@@ -17,6 +17,22 @@ module PrometheusExporter::Metric
|
|
17
17
|
@observations = {}
|
18
18
|
end
|
19
19
|
|
20
|
+
def to_h
|
21
|
+
data = {}
|
22
|
+
@observations.each do |labels, buckets|
|
23
|
+
count = @counts[labels]
|
24
|
+
sum = @sums[labels]
|
25
|
+
data[labels] = { "count" => count, "sum" => sum }
|
26
|
+
end
|
27
|
+
data
|
28
|
+
end
|
29
|
+
|
30
|
+
def remove(labels)
|
31
|
+
@observations.delete(labels)
|
32
|
+
@counts.delete(labels)
|
33
|
+
@sums.delete(labels)
|
34
|
+
end
|
35
|
+
|
20
36
|
def type
|
21
37
|
"histogram"
|
22
38
|
end
|
@@ -22,6 +22,23 @@ module PrometheusExporter::Metric
|
|
22
22
|
@sums = {}
|
23
23
|
end
|
24
24
|
|
25
|
+
def to_h
|
26
|
+
data = {}
|
27
|
+
calculate_all_quantiles.each do |labels, quantiles|
|
28
|
+
count = @counts[labels]
|
29
|
+
sum = @sums[labels]
|
30
|
+
data[labels] = { "count" => count, "sum" => sum }
|
31
|
+
end
|
32
|
+
data
|
33
|
+
end
|
34
|
+
|
35
|
+
def remove(labels)
|
36
|
+
@counts.delete(labels)
|
37
|
+
@sums.delete(labels)
|
38
|
+
@buffers[0].delete(labels)
|
39
|
+
@buffers[1].delete(labels)
|
40
|
+
end
|
41
|
+
|
25
42
|
def type
|
26
43
|
"summary"
|
27
44
|
end
|
@@ -5,6 +5,7 @@ require_relative "server/type_collector"
|
|
5
5
|
require_relative "server/web_collector"
|
6
6
|
require_relative "server/process_collector"
|
7
7
|
require_relative "server/sidekiq_collector"
|
8
|
+
require_relative "server/sidekiq_queue_collector"
|
8
9
|
require_relative "server/delayed_job_collector"
|
9
10
|
require_relative "server/collector_base"
|
10
11
|
require_relative "server/collector"
|
@@ -14,3 +15,4 @@ require_relative "server/puma_collector"
|
|
14
15
|
require_relative "server/hutch_collector"
|
15
16
|
require_relative "server/unicorn_collector"
|
16
17
|
require_relative "server/active_record_collector"
|
18
|
+
require_relative "server/shoryuken_collector"
|
@@ -27,6 +27,7 @@ module PrometheusExporter::Server
|
|
27
27
|
|
28
28
|
@active_record_metrics.map do |m|
|
29
29
|
metric_key = (m["metric_labels"] || {}).merge("pid" => m["pid"])
|
30
|
+
metric_key.merge!(m["custom_labels"]) if m["custom_labels"]
|
30
31
|
|
31
32
|
ACTIVE_RECORD_GAUGES.map do |k, help|
|
32
33
|
k = k.to_s
|
@@ -13,11 +13,13 @@ module PrometheusExporter::Server
|
|
13
13
|
register_collector(WebCollector.new)
|
14
14
|
register_collector(ProcessCollector.new)
|
15
15
|
register_collector(SidekiqCollector.new)
|
16
|
+
register_collector(SidekiqQueueCollector.new)
|
16
17
|
register_collector(DelayedJobCollector.new)
|
17
18
|
register_collector(PumaCollector.new)
|
18
19
|
register_collector(HutchCollector.new)
|
19
20
|
register_collector(UnicornCollector.new)
|
20
21
|
register_collector(ActiveRecordCollector.new)
|
22
|
+
register_collector(ShoryukenCollector.new)
|
21
23
|
end
|
22
24
|
|
23
25
|
def register_collector(collector)
|
@@ -2,6 +2,17 @@
|
|
2
2
|
|
3
3
|
module PrometheusExporter::Server
|
4
4
|
class DelayedJobCollector < TypeCollector
|
5
|
+
def initialize
|
6
|
+
@delayed_jobs_total = nil
|
7
|
+
@delayed_job_duration_seconds = nil
|
8
|
+
@delayed_jobs_total = nil
|
9
|
+
@delayed_failed_jobs_total = nil
|
10
|
+
@delayed_jobs_max_attempts_reached_total = nil
|
11
|
+
@delayed_job_duration_seconds_summary = nil
|
12
|
+
@delayed_job_attempts_summary = nil
|
13
|
+
@delayed_jobs_enqueued = nil
|
14
|
+
@delayed_jobs_pending = nil
|
15
|
+
end
|
5
16
|
|
6
17
|
def type
|
7
18
|
"delayed_job"
|
@@ -9,6 +9,13 @@ module PrometheusExporter::Server
|
|
9
9
|
|
10
10
|
class Runner
|
11
11
|
def initialize(options = {})
|
12
|
+
@timeout = nil
|
13
|
+
@port = nil
|
14
|
+
@bind = nil
|
15
|
+
@collector_class = nil
|
16
|
+
@type_collectors = nil
|
17
|
+
@prefix = nil
|
18
|
+
|
12
19
|
options.each do |k, v|
|
13
20
|
send("#{k}=", v) if self.class.method_defined?("#{k}=")
|
14
21
|
end
|
@@ -16,6 +23,7 @@ module PrometheusExporter::Server
|
|
16
23
|
|
17
24
|
def start
|
18
25
|
PrometheusExporter::Metric::Base.default_prefix = prefix
|
26
|
+
PrometheusExporter::Metric::Base.default_labels = label
|
19
27
|
|
20
28
|
register_type_collectors
|
21
29
|
|
@@ -32,73 +40,54 @@ module PrometheusExporter::Server
|
|
32
40
|
)
|
33
41
|
end
|
34
42
|
|
35
|
-
server = server_class.new port: port, collector: collector, timeout: timeout, verbose: verbose
|
43
|
+
server = server_class.new port: port, bind: bind, collector: collector, timeout: timeout, verbose: verbose
|
36
44
|
server.start
|
37
45
|
end
|
38
46
|
|
39
|
-
|
40
|
-
|
41
|
-
end
|
47
|
+
attr_accessor :unicorn_listen_address, :unicorn_pid_file
|
48
|
+
attr_writer :prefix, :port, :bind, :collector_class, :type_collectors, :timeout, :verbose, :server_class, :label
|
42
49
|
|
43
50
|
def prefix
|
44
51
|
@prefix || PrometheusExporter::DEFAULT_PREFIX
|
45
52
|
end
|
46
53
|
|
47
|
-
def port=(port)
|
48
|
-
@port = port
|
49
|
-
end
|
50
|
-
|
51
54
|
def port
|
52
55
|
@port || PrometheusExporter::DEFAULT_PORT
|
53
56
|
end
|
54
57
|
|
55
|
-
def
|
56
|
-
@
|
58
|
+
def bind
|
59
|
+
@bind || PrometheusExporter::DEFAULT_BIND_ADDRESS
|
57
60
|
end
|
58
61
|
|
59
62
|
def collector_class
|
60
63
|
@collector_class || PrometheusExporter::Server::Collector
|
61
64
|
end
|
62
65
|
|
63
|
-
def type_collectors=(type_collectors)
|
64
|
-
@type_collectors = type_collectors
|
65
|
-
end
|
66
|
-
|
67
66
|
def type_collectors
|
68
67
|
@type_collectors || []
|
69
68
|
end
|
70
69
|
|
71
|
-
def timeout=(timeout)
|
72
|
-
@timeout = timeout
|
73
|
-
end
|
74
|
-
|
75
70
|
def timeout
|
76
71
|
@timeout || PrometheusExporter::DEFAULT_TIMEOUT
|
77
72
|
end
|
78
73
|
|
79
|
-
def verbose=(verbose)
|
80
|
-
@verbose = verbose
|
81
|
-
end
|
82
|
-
|
83
74
|
def verbose
|
84
75
|
return @verbose if defined? @verbose
|
85
76
|
false
|
86
77
|
end
|
87
78
|
|
88
|
-
def server_class=(server_class)
|
89
|
-
@server_class = server_class
|
90
|
-
end
|
91
|
-
|
92
79
|
def server_class
|
93
80
|
@server_class || PrometheusExporter::Server::WebServer
|
94
81
|
end
|
95
82
|
|
96
|
-
attr_accessor :unicorn_listen_address, :unicorn_pid_file
|
97
|
-
|
98
83
|
def collector
|
99
84
|
@_collector ||= collector_class.new
|
100
85
|
end
|
101
86
|
|
87
|
+
def label
|
88
|
+
@label ||= PrometheusExporter::DEFAULT_LABEL
|
89
|
+
end
|
90
|
+
|
102
91
|
private
|
103
92
|
|
104
93
|
def register_type_collectors
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PrometheusExporter::Server
|
4
|
+
class ShoryukenCollector < TypeCollector
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@shoryuken_jobs_total = nil
|
8
|
+
@shoryuken_job_duration_seconds = nil
|
9
|
+
@shoryuken_jobs_total = nil
|
10
|
+
@shoryuken_restarted_jobs_total = nil
|
11
|
+
@shoryuken_failed_jobs_total = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def type
|
15
|
+
"shoryuken"
|
16
|
+
end
|
17
|
+
|
18
|
+
def collect(obj)
|
19
|
+
default_labels = { job_name: obj['name'] , queue_name: obj['queue'] }
|
20
|
+
custom_labels = obj['custom_labels']
|
21
|
+
labels = custom_labels.nil? ? default_labels : default_labels.merge(custom_labels)
|
22
|
+
|
23
|
+
ensure_shoryuken_metrics
|
24
|
+
@shoryuken_job_duration_seconds.observe(obj["duration"], labels)
|
25
|
+
@shoryuken_jobs_total.observe(1, labels)
|
26
|
+
@shoryuken_restarted_jobs_total.observe(1, labels) if obj["shutdown"]
|
27
|
+
@shoryuken_failed_jobs_total.observe(1, labels) if !obj["success"] && !obj["shutdown"]
|
28
|
+
end
|
29
|
+
|
30
|
+
def metrics
|
31
|
+
if @shoryuken_jobs_total
|
32
|
+
[
|
33
|
+
@shoryuken_job_duration_seconds,
|
34
|
+
@shoryuken_jobs_total,
|
35
|
+
@shoryuken_restarted_jobs_total,
|
36
|
+
@shoryuken_failed_jobs_total,
|
37
|
+
]
|
38
|
+
else
|
39
|
+
[]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
def ensure_shoryuken_metrics
|
46
|
+
if !@shoryuken_jobs_total
|
47
|
+
|
48
|
+
@shoryuken_job_duration_seconds =
|
49
|
+
PrometheusExporter::Metric::Counter.new(
|
50
|
+
"shoryuken_job_duration_seconds", "Total time spent in shoryuken jobs.")
|
51
|
+
|
52
|
+
@shoryuken_jobs_total =
|
53
|
+
PrometheusExporter::Metric::Counter.new(
|
54
|
+
"shoryuken_jobs_total", "Total number of shoryuken jobs executed.")
|
55
|
+
|
56
|
+
@shoryuken_restarted_jobs_total =
|
57
|
+
PrometheusExporter::Metric::Counter.new(
|
58
|
+
"shoryuken_restarted_jobs_total", "Total number of shoryuken jobs that we restarted because of a shoryuken shutdown.")
|
59
|
+
|
60
|
+
@shoryuken_failed_jobs_total =
|
61
|
+
PrometheusExporter::Metric::Counter.new(
|
62
|
+
"shoryuken_failed_jobs_total", "Total number of failed shoryuken jobs.")
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -3,6 +3,15 @@
|
|
3
3
|
module PrometheusExporter::Server
|
4
4
|
class SidekiqCollector < TypeCollector
|
5
5
|
|
6
|
+
def initialize
|
7
|
+
@sidekiq_jobs_total = nil
|
8
|
+
@sidekiq_job_duration_seconds = nil
|
9
|
+
@sidekiq_jobs_total = nil
|
10
|
+
@sidekiq_restarted_jobs_total = nil
|
11
|
+
@sidekiq_failed_jobs_total = nil
|
12
|
+
@sidekiq_dead_jobs_total = nil
|
13
|
+
end
|
14
|
+
|
6
15
|
def type
|
7
16
|
"sidekiq"
|
8
17
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module PrometheusExporter::Server
|
3
|
+
class SidekiqQueueCollector < TypeCollector
|
4
|
+
MAX_SIDEKIQ_METRIC_AGE = 60
|
5
|
+
|
6
|
+
SIDEKIQ_QUEUE_GAUGES = {
|
7
|
+
'backlog_total' => 'Size of the sidekiq queue.',
|
8
|
+
'latency_seconds' => 'Latency of the sidekiq queue.',
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
attr_reader :sidekiq_metrics, :gauges
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@sidekiq_metrics = []
|
15
|
+
@gauges = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def type
|
19
|
+
'sidekiq_queue'
|
20
|
+
end
|
21
|
+
|
22
|
+
def metrics
|
23
|
+
sidekiq_metrics.map do |metric|
|
24
|
+
labels = metric.fetch("labels", {})
|
25
|
+
SIDEKIQ_QUEUE_GAUGES.map do |name, help|
|
26
|
+
if (value = metric[name])
|
27
|
+
gauge = gauges[name] ||= PrometheusExporter::Metric::Gauge.new("sidekiq_queue_#{name}", help)
|
28
|
+
gauge.observe(value, labels)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
gauges.values
|
34
|
+
end
|
35
|
+
|
36
|
+
def collect(object)
|
37
|
+
now = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
38
|
+
object['queues'].each do |queue|
|
39
|
+
queue["created_at"] = now
|
40
|
+
queue["labels"].merge!(object['custom_labels']) if object['custom_labels']
|
41
|
+
sidekiq_metrics.delete_if { |metric| metric['created_at'] + MAX_SIDEKIQ_METRIC_AGE < now }
|
42
|
+
sidekiq_metrics << queue
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -4,6 +4,11 @@ module PrometheusExporter::Server
|
|
4
4
|
class WebCollector < TypeCollector
|
5
5
|
def initialize
|
6
6
|
@metrics = {}
|
7
|
+
@http_requests_total = nil
|
8
|
+
@http_duration_seconds = nil
|
9
|
+
@http_redis_duration_seconds = nil
|
10
|
+
@http_sql_duration_seconds = nil
|
11
|
+
@http_queue_duration_seconds = nil
|
7
12
|
end
|
8
13
|
|
9
14
|
def type
|
@@ -9,7 +9,7 @@ module PrometheusExporter::Server
|
|
9
9
|
class WebServer
|
10
10
|
attr_reader :collector
|
11
11
|
|
12
|
-
def initialize(port: , collector: nil, timeout: PrometheusExporter::DEFAULT_TIMEOUT, verbose: false)
|
12
|
+
def initialize(port: , bind: nil, collector: nil, timeout: PrometheusExporter::DEFAULT_TIMEOUT, verbose: false)
|
13
13
|
|
14
14
|
@verbose = verbose
|
15
15
|
|
@@ -38,6 +38,7 @@ module PrometheusExporter::Server
|
|
38
38
|
|
39
39
|
@server = WEBrick::HTTPServer.new(
|
40
40
|
Port: port,
|
41
|
+
BindAddress: bind,
|
41
42
|
Logger: logger,
|
42
43
|
AccessLog: access_log,
|
43
44
|
)
|
data/prometheus_exporter.gemspec
CHANGED
@@ -5,26 +5,28 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
5
|
require "prometheus_exporter/version"
|
6
6
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
|
-
spec.name
|
9
|
-
spec.version
|
10
|
-
spec.authors
|
11
|
-
spec.email
|
8
|
+
spec.name = "prometheus_exporter"
|
9
|
+
spec.version = PrometheusExporter::VERSION
|
10
|
+
spec.authors = ["Sam Saffron"]
|
11
|
+
spec.email = ["sam.saffron@gmail.com"]
|
12
12
|
|
13
|
-
spec.summary
|
14
|
-
spec.description
|
15
|
-
spec.homepage
|
16
|
-
spec.license
|
13
|
+
spec.summary = %q{Prometheus Exporter}
|
14
|
+
spec.description = %q{Prometheus metric collector and exporter for Ruby}
|
15
|
+
spec.homepage = "https://github.com/discourse/prometheus_exporter"
|
16
|
+
spec.license = "MIT"
|
17
17
|
|
18
|
-
spec.
|
18
|
+
spec.post_install_message = "prometheus_exporter will only bind to localhost by default as of v0.5"
|
19
|
+
|
20
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
21
|
f.match(%r{^(test|spec|features|bin)/})
|
20
22
|
end
|
21
|
-
spec.bindir
|
22
|
-
spec.executables
|
23
|
-
spec.require_paths
|
23
|
+
spec.bindir = "bin"
|
24
|
+
spec.executables = ["prometheus_exporter"]
|
25
|
+
spec.require_paths = ["lib"]
|
24
26
|
|
25
27
|
spec.add_development_dependency "rubocop", ">= 0.69"
|
26
28
|
spec.add_development_dependency "bundler", "> 1.16"
|
27
|
-
spec.add_development_dependency "rake", "~>
|
29
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
28
30
|
spec.add_development_dependency "minitest", "~> 5.0"
|
29
31
|
spec.add_development_dependency "guard", "~> 2.0"
|
30
32
|
spec.add_development_dependency "mini_racer", "~> 0.1"
|
@@ -32,6 +34,7 @@ Gem::Specification.new do |spec|
|
|
32
34
|
spec.add_development_dependency "oj", "~> 3.0"
|
33
35
|
spec.add_development_dependency "rack-test", "~> 0.8.3"
|
34
36
|
spec.add_development_dependency "minitest-stub-const", "~> 0.6"
|
37
|
+
spec.add_development_dependency "rubocop-discourse", ">2"
|
35
38
|
if !RUBY_ENGINE == 'jruby'
|
36
39
|
spec.add_development_dependency "raindrops", "~> 0.19"
|
37
40
|
end
|
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: 0.5.3
|
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:
|
11
|
+
date: 2020-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '13.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '13.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: minitest
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,6 +150,20 @@ dependencies:
|
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0.6'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rubocop-discourse
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '2'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '2'
|
153
167
|
description: Prometheus metric collector and exporter for Ruby
|
154
168
|
email:
|
155
169
|
- sam.saffron@gmail.com
|
@@ -180,7 +194,9 @@ files:
|
|
180
194
|
- lib/prometheus_exporter/instrumentation/method_profiler.rb
|
181
195
|
- lib/prometheus_exporter/instrumentation/process.rb
|
182
196
|
- lib/prometheus_exporter/instrumentation/puma.rb
|
197
|
+
- lib/prometheus_exporter/instrumentation/shoryuken.rb
|
183
198
|
- lib/prometheus_exporter/instrumentation/sidekiq.rb
|
199
|
+
- lib/prometheus_exporter/instrumentation/sidekiq_queue.rb
|
184
200
|
- lib/prometheus_exporter/instrumentation/unicorn.rb
|
185
201
|
- lib/prometheus_exporter/metric.rb
|
186
202
|
- lib/prometheus_exporter/metric/base.rb
|
@@ -198,7 +214,9 @@ files:
|
|
198
214
|
- lib/prometheus_exporter/server/process_collector.rb
|
199
215
|
- lib/prometheus_exporter/server/puma_collector.rb
|
200
216
|
- lib/prometheus_exporter/server/runner.rb
|
217
|
+
- lib/prometheus_exporter/server/shoryuken_collector.rb
|
201
218
|
- lib/prometheus_exporter/server/sidekiq_collector.rb
|
219
|
+
- lib/prometheus_exporter/server/sidekiq_queue_collector.rb
|
202
220
|
- lib/prometheus_exporter/server/type_collector.rb
|
203
221
|
- lib/prometheus_exporter/server/unicorn_collector.rb
|
204
222
|
- lib/prometheus_exporter/server/web_collector.rb
|
@@ -209,7 +227,8 @@ homepage: https://github.com/discourse/prometheus_exporter
|
|
209
227
|
licenses:
|
210
228
|
- MIT
|
211
229
|
metadata: {}
|
212
|
-
post_install_message:
|
230
|
+
post_install_message: prometheus_exporter will only bind to localhost by default as
|
231
|
+
of v0.5
|
213
232
|
rdoc_options: []
|
214
233
|
require_paths:
|
215
234
|
- lib
|
@@ -225,7 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
225
244
|
version: '0'
|
226
245
|
requirements: []
|
227
246
|
rubygems_version: 3.0.3
|
228
|
-
signing_key:
|
247
|
+
signing_key:
|
229
248
|
specification_version: 4
|
230
249
|
summary: Prometheus Exporter
|
231
250
|
test_files: []
|