prometheus_exporter 0.4.16 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|