prometheus_exporter 0.5.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +36 -0
- data/CHANGELOG +4 -0
- data/README.md +71 -14
- data/bin/prometheus_exporter +17 -0
- data/lib/prometheus_exporter.rb +1 -0
- data/lib/prometheus_exporter/client.rb +23 -2
- data/lib/prometheus_exporter/instrumentation/active_record.rb +1 -1
- data/lib/prometheus_exporter/instrumentation/sidekiq.rb +44 -3
- data/lib/prometheus_exporter/instrumentation/sidekiq_queue.rb +12 -1
- data/lib/prometheus_exporter/middleware.rb +13 -2
- data/lib/prometheus_exporter/server/runner.rb +12 -2
- data/lib/prometheus_exporter/server/sidekiq_collector.rb +2 -2
- data/lib/prometheus_exporter/server/web_server.rb +29 -17
- data/lib/prometheus_exporter/version.rb +1 -1
- metadata +3 -3
- data/.travis.yml +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f516c39448418a2216851149f0479f3f9e0f5feadae5a5468e7953fc0551d318
|
4
|
+
data.tar.gz: dcc937b79e05d4cd74a64ab2135425c75c4bba1be053bec99e8db0695a3ac998
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5664f24c1c4a1520bafe789e5df8a9f1c40b118933cab9b73baa953f633ec6e81c3a11bbc9fc63097a2a2acdd2390daeade9449e6451cc83207fc2162575b359
|
7
|
+
data.tar.gz: ca4aeedbc6e211818569257e8a3e9fde93be363a2da246abae45749bc9cc232052ac52f0850cd54d0f600904bed193a10db1f76e4fc9567b837b20a78264158b
|
@@ -0,0 +1,36 @@
|
|
1
|
+
name: Test Exporter
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
pull_request:
|
6
|
+
schedule:
|
7
|
+
- cron: '0 0 * * 0' # weekly
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
build:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
name: Ruby ${{ matrix.ruby }}
|
13
|
+
strategy:
|
14
|
+
matrix:
|
15
|
+
ruby: ["2.7", "2.6", "2.5", "2.4"]
|
16
|
+
steps:
|
17
|
+
- uses: actions/checkout@master
|
18
|
+
with:
|
19
|
+
fetch-depth: 1
|
20
|
+
- uses: actions/setup-ruby@v1
|
21
|
+
with:
|
22
|
+
ruby-version: ${{ matrix.ruby }}
|
23
|
+
- uses: actions/cache@v2
|
24
|
+
with:
|
25
|
+
path: vendor/bundle
|
26
|
+
key: ${{ runner.os }}-${{ matrix.ruby }}-gems-${{ hashFiles('**/Gemfile.lock') }}
|
27
|
+
restore-keys: |
|
28
|
+
${{ runner.os }}-${{ matrix.ruby }}-gems-
|
29
|
+
- name: Setup gems
|
30
|
+
run: |
|
31
|
+
bundle config path vendor/bundle
|
32
|
+
bundle install --jobs 4
|
33
|
+
- name: Rubocop
|
34
|
+
run: bundle exec rubocop
|
35
|
+
- name: Run tests
|
36
|
+
run: bundle exec rake
|
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -200,12 +200,27 @@ $ bundle exec prometheus_exporter
|
|
200
200
|
| Summary | `http_sql_duration_seconds`² | Time spent in HTTP reqs in SQL in seconds |
|
201
201
|
| Summary | `http_queue_duration_seconds`³ | Time spent queueing the request in load balancer in seconds |
|
202
202
|
|
203
|
-
All metrics have a `controller` and an `action` label.
|
204
|
-
`http_requests_total` additionally has a (HTTP response) `status` label.
|
203
|
+
All metrics have a `controller` and an `action` label.
|
204
|
+
`http_requests_total` additionally has a (HTTP response) `status` label.
|
205
205
|
|
206
|
-
|
207
|
-
|
208
|
-
|
206
|
+
To add your own labels to the default metrics, create a subclass of `PrometheusExporter::Middleware`, override `custom_labels`, and use it in your initializer.
|
207
|
+
```ruby
|
208
|
+
class MyMiddleware < PrometheusExporter::Middleware
|
209
|
+
def custom_labels(env)
|
210
|
+
labels = {}
|
211
|
+
|
212
|
+
if env['HTTP_X_PLATFORM']
|
213
|
+
labels['platform'] = env['HTTP_X_PLATFORM']
|
214
|
+
end
|
215
|
+
|
216
|
+
labels
|
217
|
+
end
|
218
|
+
end
|
219
|
+
```
|
220
|
+
|
221
|
+
¹) Only available when Redis is used.
|
222
|
+
²) Only available when Mysql or PostgreSQL are used.
|
223
|
+
³) Only available when [Instrumenting Request Queueing Time](#instrumenting-request-queueing-time) is set up.
|
209
224
|
|
210
225
|
#### Activerecord Connection Pool Metrics
|
211
226
|
|
@@ -365,19 +380,19 @@ Sometimes the Sidekiq server shuts down before it can send metrics, that were ge
|
|
365
380
|
**PrometheusExporter::Instrumentation::Sidekiq**
|
366
381
|
| Type | Name | Description |
|
367
382
|
| --- | --- | --- |
|
368
|
-
|
|
383
|
+
| Summary | `sidekiq_job_duration_seconds` | Time spent in sidekiq jobs |
|
369
384
|
| Counter | `sidekiq_jobs_total` | Total number of sidekiq jobs executed |
|
370
385
|
| Counter | `sidekiq_restarted_jobs_total` | Total number of sidekiq jobs that we restarted because of a sidekiq shutdown |
|
371
386
|
| Counter | `sidekiq_failed_jobs_total` | Total number of failed sidekiq jobs |
|
372
387
|
|
373
|
-
All metrics have a `job_name` label.
|
388
|
+
All metrics have a `job_name` label and a `queue` label.
|
374
389
|
|
375
390
|
**PrometheusExporter::Instrumentation::Sidekiq.death_handler**
|
376
391
|
| Type | Name | Description |
|
377
392
|
| --- | --- | --- |
|
378
393
|
| Counter | `sidekiq_dead_jobs_total` | Total number of dead sidekiq jobs |
|
379
394
|
|
380
|
-
This metric
|
395
|
+
This metric has a `job_name` label and a `queue` label.
|
381
396
|
|
382
397
|
**PrometheusExporter::Instrumentation::SidekiqQueue**
|
383
398
|
| Type | Name | Description |
|
@@ -387,7 +402,7 @@ This metric also has a `job_name` label.
|
|
387
402
|
|
388
403
|
Both metrics will have a `queue` label with the name of the queue.
|
389
404
|
|
390
|
-
_See [Metrics collected by Process Instrumentation](#metrics-collected-by-process-instrumentation) for a list of metrics the Process instrumentation will produce._
|
405
|
+
_See [Metrics collected by Process Instrumentation](#metrics-collected-by-process-instrumentation) for a list of metrics the Process instrumentation will produce._
|
391
406
|
|
392
407
|
#### Shoryuken metrics
|
393
408
|
|
@@ -411,7 +426,7 @@ end
|
|
411
426
|
| Counter | `shoryuken_restarted_jobs_total` | Total number of shoryuken jobs that we restarted because of a shoryuken shutdown |
|
412
427
|
| Counter | `shoryuken_failed_jobs_total` | Total number of failed shoryuken jobs |
|
413
428
|
|
414
|
-
All metrics have labels for `job_name` and `queue_name`.
|
429
|
+
All metrics have labels for `job_name` and `queue_name`.
|
415
430
|
|
416
431
|
#### Delayed Job plugin
|
417
432
|
|
@@ -456,7 +471,7 @@ end
|
|
456
471
|
| Counter | `hutch_jobs_total` | Total number of hutch jobs executed |
|
457
472
|
| Counter | `hutch_failed_jobs_total` | Total number failed hutch jobs executed |
|
458
473
|
|
459
|
-
All metrics have a `job_name` label.
|
474
|
+
All metrics have a `job_name` label.
|
460
475
|
|
461
476
|
#### Instrumenting Request Queueing Time
|
462
477
|
|
@@ -494,7 +509,7 @@ end
|
|
494
509
|
| Gauge | `puma_thread_pool_capacity_total` | Number of puma threads available at current scale |
|
495
510
|
| Gauge | `puma_max_threads_total` | Number of puma threads at available at max scale |
|
496
511
|
|
497
|
-
All metrics may have a `phase` label.
|
512
|
+
All metrics may have a `phase` label.
|
498
513
|
|
499
514
|
### Unicorn process metrics
|
500
515
|
|
@@ -577,8 +592,8 @@ Then you can collect the metrics you need on demand:
|
|
577
592
|
|
578
593
|
```ruby
|
579
594
|
def metrics
|
580
|
-
|
581
|
-
|
595
|
+
user_count_gauge = PrometheusExporter::Metric::Gauge.new('user_count', 'number of users in the app')
|
596
|
+
user_count_gauge.observe User.count
|
582
597
|
[user_count_gauge]
|
583
598
|
end
|
584
599
|
```
|
@@ -692,6 +707,25 @@ ruby_web_requests{hostname="app-server-01"} 1
|
|
692
707
|
When running the process for `prometheus_exporter` using `bin/prometheus_exporter`, there are several configurations that
|
693
708
|
can be passed in:
|
694
709
|
|
710
|
+
```
|
711
|
+
Usage: prometheus_exporter [options]
|
712
|
+
-p, --port INTEGER Port exporter should listen on (default: 9394)
|
713
|
+
-b, --bind STRING IP address exporter should listen on (default: localhost)
|
714
|
+
-t, --timeout INTEGER Timeout in seconds for metrics endpoint (default: 2)
|
715
|
+
--prefix METRIC_PREFIX Prefix to apply to all metrics (default: ruby_)
|
716
|
+
--label METRIC_LABEL Label to apply to all metrics (default: {})
|
717
|
+
-c, --collector FILE (optional) Custom collector to run
|
718
|
+
-a, --type-collector FILE (optional) Custom type collectors to run in main collector
|
719
|
+
-v, --verbose
|
720
|
+
--auth FILE (optional) enable basic authentication using a htpasswd FILE
|
721
|
+
--realm REALM (optional) Use REALM for basic authentication (default: "Prometheus Exporter")
|
722
|
+
--unicorn-listen-address ADDRESS
|
723
|
+
(optional) Address where unicorn listens on (unix or TCP address)
|
724
|
+
--unicorn-master PID_FILE (optional) PID file of unicorn master process to monitor unicorn
|
725
|
+
```
|
726
|
+
|
727
|
+
#### Example
|
728
|
+
|
695
729
|
The following will run the process at
|
696
730
|
- Port `8080` (default `9394`)
|
697
731
|
- Bind to `0.0.0.0` (default `localhost`)
|
@@ -707,6 +741,29 @@ prometheus_exporter -p 8080 \
|
|
707
741
|
--prefix 'foo_'
|
708
742
|
```
|
709
743
|
|
744
|
+
#### Enabling Basic Authentication
|
745
|
+
|
746
|
+
If you desire authentication on your `/metrics` route, you can enable basic authentication with the `--auth` option.
|
747
|
+
|
748
|
+
```
|
749
|
+
$ prometheus_exporter --auth my-htpasswd-file
|
750
|
+
```
|
751
|
+
|
752
|
+
Additionally, the `--realm` option may be used to provide a customized realm for the challenge request.
|
753
|
+
|
754
|
+
Notes:
|
755
|
+
|
756
|
+
* You will need to create a `htpasswd` formatted file before hand which contains one or more user:password entries
|
757
|
+
* Only the basic `crypt` encryption is currently supported
|
758
|
+
|
759
|
+
A simple `htpasswd` file can be created with the Apache `htpasswd` utility; e.g:
|
760
|
+
|
761
|
+
```
|
762
|
+
$ htpasswd -cdb my-htpasswd-file my-user my-unencrypted-password
|
763
|
+
```
|
764
|
+
|
765
|
+
This will create a file named `my-htpasswd-file` which is suitable for use the `--auth` option.
|
766
|
+
|
710
767
|
### Client default labels
|
711
768
|
|
712
769
|
You can specify a default label for instrumentation metrics sent by a specific client. For example:
|
data/bin/prometheus_exporter
CHANGED
@@ -47,6 +47,12 @@ def run
|
|
47
47
|
opt.on('-v', '--verbose') do |o|
|
48
48
|
options[:verbose] = true
|
49
49
|
end
|
50
|
+
opt.on('--auth FILE', String, "(optional) enable basic authentication using a htpasswd FILE") do |o|
|
51
|
+
options[:auth] = o
|
52
|
+
end
|
53
|
+
opt.on('--realm REALM', String, "(optional) Use REALM for basic authentication (default: \"#{PrometheusExporter::DEFAULT_REALM}\")") do |o|
|
54
|
+
options[:realm] = o
|
55
|
+
end
|
50
56
|
|
51
57
|
opt.on('--unicorn-listen-address ADDRESS', String, '(optional) Address where unicorn listens on (unix or TCP address)') do |o|
|
52
58
|
options[:unicorn_listen_address] = o
|
@@ -57,6 +63,17 @@ def run
|
|
57
63
|
end
|
58
64
|
end.parse!
|
59
65
|
|
66
|
+
if options.has_key?(:realm) && !options.has_key?(:auth)
|
67
|
+
STDERR.puts "[Warn] Providing REALM without AUTH has no effect"
|
68
|
+
end
|
69
|
+
|
70
|
+
if options.has_key?(:auth)
|
71
|
+
unless File.exist?(options[:auth]) && File.readable?(options[:auth])
|
72
|
+
STDERR.puts "[Error] The AUTH file either doesn't exist or we don't have access to it"
|
73
|
+
exit 1
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
60
77
|
if custom_collector_filename
|
61
78
|
eval File.read(custom_collector_filename), nil, File.expand_path(custom_collector_filename)
|
62
79
|
found = false
|
data/lib/prometheus_exporter.rb
CHANGED
@@ -64,8 +64,10 @@ module PrometheusExporter
|
|
64
64
|
@metrics = []
|
65
65
|
|
66
66
|
@queue = Queue.new
|
67
|
+
|
67
68
|
@socket = nil
|
68
69
|
@socket_started = nil
|
70
|
+
@socket_pid = nil
|
69
71
|
|
70
72
|
max_queue_size ||= MAX_QUEUE_SIZE
|
71
73
|
max_queue_size = max_queue_size.to_i
|
@@ -107,7 +109,16 @@ module PrometheusExporter
|
|
107
109
|
end
|
108
110
|
|
109
111
|
def send_json(obj)
|
110
|
-
payload =
|
112
|
+
payload =
|
113
|
+
if @custom_labels
|
114
|
+
if obj[:custom_labels]
|
115
|
+
obj.merge(custom_labels: @custom_labels.merge(obj[:custom_labels]))
|
116
|
+
else
|
117
|
+
obj.merge(custom_labels: @custom_labels)
|
118
|
+
end
|
119
|
+
else
|
120
|
+
obj
|
121
|
+
end
|
111
122
|
send(@json_serializer.dump(payload))
|
112
123
|
end
|
113
124
|
|
@@ -191,12 +202,20 @@ module PrometheusExporter
|
|
191
202
|
end
|
192
203
|
|
193
204
|
def close_socket_if_old!
|
194
|
-
if @socket && ((@socket_started + MAX_SOCKET_AGE) < Time.now.to_f)
|
205
|
+
if @socket_pid == Process.pid && @socket && @socket_started && ((@socket_started + MAX_SOCKET_AGE) < Time.now.to_f)
|
195
206
|
close_socket!
|
196
207
|
end
|
197
208
|
end
|
198
209
|
|
199
210
|
def ensure_socket!
|
211
|
+
# if process was forked socket may be owned by parent
|
212
|
+
# leave it alone and reset
|
213
|
+
if @socket_pid != Process.pid
|
214
|
+
@socket = nil
|
215
|
+
@socket_started = nil
|
216
|
+
@socket_pid = nil
|
217
|
+
end
|
218
|
+
|
200
219
|
close_socket_if_old!
|
201
220
|
if !@socket
|
202
221
|
@socket = TCPSocket.new @host, @port
|
@@ -207,12 +226,14 @@ module PrometheusExporter
|
|
207
226
|
@socket.write("Content-Type: application/octet-stream\r\n")
|
208
227
|
@socket.write("\r\n")
|
209
228
|
@socket_started = Time.now.to_f
|
229
|
+
@socket_pid = Process.pid
|
210
230
|
end
|
211
231
|
|
212
232
|
nil
|
213
233
|
rescue
|
214
234
|
@socket = nil
|
215
235
|
@socket_started = nil
|
236
|
+
@socket_pid = nil
|
216
237
|
raise
|
217
238
|
end
|
218
239
|
|
@@ -69,7 +69,7 @@ module PrometheusExporter::Instrumentation
|
|
69
69
|
|
70
70
|
labels_from_config = pool.spec.config
|
71
71
|
.select { |k, v| @config_labels.include? k }
|
72
|
-
.map { |k, v| [k.to_s.prepend("dbconfig_"), v] }
|
72
|
+
.map { |k, v| [k.to_s.dup.prepend("dbconfig_"), v] }
|
73
73
|
|
74
74
|
labels = @metric_labels.merge(pool_name: pool.spec.name).merge(Hash[labels_from_config])
|
75
75
|
|
@@ -1,6 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'yaml'
|
4
|
+
|
3
5
|
module PrometheusExporter::Instrumentation
|
6
|
+
JOB_WRAPPER_CLASS_NAME = 'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper'
|
7
|
+
DELAYED_CLASS_NAMES = [
|
8
|
+
'Sidekiq::Extensions::DelayedClass',
|
9
|
+
'Sidekiq::Extensions::DelayedModel',
|
10
|
+
'Sidekiq::Extensions::DelayedMailer',
|
11
|
+
]
|
12
|
+
|
4
13
|
class Sidekiq
|
5
14
|
def self.death_handler
|
6
15
|
-> (job, ex) do
|
@@ -32,15 +41,47 @@ module PrometheusExporter::Instrumentation
|
|
32
41
|
raise e
|
33
42
|
ensure
|
34
43
|
duration = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start
|
35
|
-
class_name = worker.class.to_s == 'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper' ?
|
36
|
-
msg['wrapped'] : worker.class.to_s
|
37
44
|
@client.send_json(
|
38
45
|
type: "sidekiq",
|
39
|
-
name:
|
46
|
+
name: get_name(worker, msg),
|
47
|
+
queue: queue,
|
40
48
|
success: success,
|
41
49
|
shutdown: shutdown,
|
42
50
|
duration: duration
|
43
51
|
)
|
44
52
|
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def get_name(worker, msg)
|
57
|
+
class_name = worker.class.to_s
|
58
|
+
if class_name == JOB_WRAPPER_CLASS_NAME
|
59
|
+
get_job_wrapper_name(msg)
|
60
|
+
elsif DELAYED_CLASS_NAMES.include?(class_name)
|
61
|
+
get_delayed_name(msg, class_name)
|
62
|
+
else
|
63
|
+
class_name
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_job_wrapper_name(msg)
|
68
|
+
msg['wrapped']
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_delayed_name(msg, class_name)
|
72
|
+
# fallback to class_name since we're relying on the internal implementation
|
73
|
+
# of the delayed extensions
|
74
|
+
# https://github.com/mperham/sidekiq/blob/master/lib/sidekiq/extensions/class_methods.rb
|
75
|
+
begin
|
76
|
+
(target, method_name, _args) = YAML.load(msg['args'].first)
|
77
|
+
if target.class == Class
|
78
|
+
"#{target.name}##{method_name}"
|
79
|
+
else
|
80
|
+
"#{target.class.name}##{method_name}"
|
81
|
+
end
|
82
|
+
rescue
|
83
|
+
class_name
|
84
|
+
end
|
85
|
+
end
|
45
86
|
end
|
46
87
|
end
|
@@ -27,13 +27,24 @@ module PrometheusExporter::Instrumentation
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def collect_queue_stats
|
30
|
+
hostname = Socket.gethostname
|
31
|
+
pid = ::Process.pid
|
32
|
+
ps = ::Sidekiq::ProcessSet.new
|
33
|
+
|
34
|
+
process = ps.find do |sp|
|
35
|
+
sp['hostname'] == hostname && sp['pid'] == pid
|
36
|
+
end
|
37
|
+
|
38
|
+
queues = process.nil? ? [] : process['queues']
|
39
|
+
|
30
40
|
::Sidekiq::Queue.all.map do |queue|
|
41
|
+
next unless queues.include? queue.name
|
31
42
|
{
|
32
43
|
backlog_total: queue.size,
|
33
44
|
latency_seconds: queue.latency.to_i,
|
34
45
|
labels: { queue: queue.name }
|
35
46
|
}
|
36
|
-
end
|
47
|
+
end.compact
|
37
48
|
end
|
38
49
|
end
|
39
50
|
end
|
@@ -44,14 +44,25 @@ class PrometheusExporter::Middleware
|
|
44
44
|
controller = params["controller"]
|
45
45
|
end
|
46
46
|
|
47
|
-
|
47
|
+
obj = {
|
48
48
|
type: "web",
|
49
49
|
timings: info,
|
50
50
|
queue_time: queue_time,
|
51
51
|
action: action,
|
52
52
|
controller: controller,
|
53
53
|
status: status
|
54
|
-
|
54
|
+
}
|
55
|
+
labels = custom_labels(env)
|
56
|
+
if labels
|
57
|
+
obj = obj.merge(custom_labels: labels)
|
58
|
+
end
|
59
|
+
|
60
|
+
@client.send_json(obj)
|
61
|
+
end
|
62
|
+
|
63
|
+
# allows subclasses to add custom labels based on env
|
64
|
+
def custom_labels(env)
|
65
|
+
nil
|
55
66
|
end
|
56
67
|
|
57
68
|
private
|
@@ -15,6 +15,8 @@ module PrometheusExporter::Server
|
|
15
15
|
@collector_class = nil
|
16
16
|
@type_collectors = nil
|
17
17
|
@prefix = nil
|
18
|
+
@auth = nil
|
19
|
+
@realm = nil
|
18
20
|
|
19
21
|
options.each do |k, v|
|
20
22
|
send("#{k}=", v) if self.class.method_defined?("#{k}=")
|
@@ -40,12 +42,20 @@ module PrometheusExporter::Server
|
|
40
42
|
)
|
41
43
|
end
|
42
44
|
|
43
|
-
server = server_class.new
|
45
|
+
server = server_class.new(port: port, bind: bind, collector: collector, timeout: timeout, verbose: verbose, auth: auth, realm: realm)
|
44
46
|
server.start
|
45
47
|
end
|
46
48
|
|
47
49
|
attr_accessor :unicorn_listen_address, :unicorn_pid_file
|
48
|
-
attr_writer :prefix, :port, :bind, :collector_class, :type_collectors, :timeout, :verbose, :server_class, :label
|
50
|
+
attr_writer :prefix, :port, :bind, :collector_class, :type_collectors, :timeout, :verbose, :server_class, :label, :auth, :realm
|
51
|
+
|
52
|
+
def auth
|
53
|
+
@auth || nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def realm
|
57
|
+
@realm || PrometheusExporter::DEFAULT_REALM
|
58
|
+
end
|
49
59
|
|
50
60
|
def prefix
|
51
61
|
@prefix || PrometheusExporter::DEFAULT_PREFIX
|
@@ -17,7 +17,7 @@ module PrometheusExporter::Server
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def collect(obj)
|
20
|
-
default_labels = { job_name: obj['name'] }
|
20
|
+
default_labels = { job_name: obj['name'], queue: obj['queue'] }
|
21
21
|
custom_labels = obj['custom_labels']
|
22
22
|
labels = custom_labels.nil? ? default_labels : default_labels.merge(custom_labels)
|
23
23
|
|
@@ -52,7 +52,7 @@ module PrometheusExporter::Server
|
|
52
52
|
if !@sidekiq_jobs_total
|
53
53
|
|
54
54
|
@sidekiq_job_duration_seconds =
|
55
|
-
PrometheusExporter::Metric::
|
55
|
+
PrometheusExporter::Metric::Summary.new(
|
56
56
|
"sidekiq_job_duration_seconds", "Total time spent in sidekiq jobs.")
|
57
57
|
|
58
58
|
@sidekiq_jobs_total =
|
@@ -9,9 +9,14 @@ module PrometheusExporter::Server
|
|
9
9
|
class WebServer
|
10
10
|
attr_reader :collector
|
11
11
|
|
12
|
-
def initialize(
|
13
|
-
|
14
|
-
@
|
12
|
+
def initialize(opts)
|
13
|
+
@port = opts[:port] || PrometheusExporter::DEFAULT_PORT
|
14
|
+
@bind = opts[:bind] || PrometheusExporter::DEFAULT_BIND_ADDRESS
|
15
|
+
@collector = opts[:collector] || Collector.new
|
16
|
+
@timeout = opts[:timeout] || PrometheusExporter::DEFAULT_TIMEOUT
|
17
|
+
@verbose = opts[:verbose] || false
|
18
|
+
@auth = opts[:auth]
|
19
|
+
@realm = opts[:realm] || PrometheusExporter::DEFAULT_REALM
|
15
20
|
|
16
21
|
@metrics_total = PrometheusExporter::Metric::Counter.new("collector_metrics_total", "Total metrics processed by exporter web.")
|
17
22
|
|
@@ -23,33 +28,33 @@ module PrometheusExporter::Server
|
|
23
28
|
@sessions_total.observe(0)
|
24
29
|
@bad_metrics_total.observe(0)
|
25
30
|
|
26
|
-
access_log, logger = nil
|
31
|
+
@access_log, @logger = nil
|
27
32
|
|
28
|
-
if verbose
|
29
|
-
access_log = [
|
33
|
+
if @verbose
|
34
|
+
@access_log = [
|
30
35
|
[$stderr, WEBrick::AccessLog::COMMON_LOG_FORMAT],
|
31
36
|
[$stderr, WEBrick::AccessLog::REFERER_LOG_FORMAT],
|
32
37
|
]
|
33
|
-
logger = WEBrick::Log.new($stderr)
|
38
|
+
@logger = WEBrick::Log.new($stderr)
|
34
39
|
else
|
35
|
-
access_log = []
|
36
|
-
logger = WEBrick::Log.new("/dev/null")
|
40
|
+
@access_log = []
|
41
|
+
@logger = WEBrick::Log.new("/dev/null")
|
37
42
|
end
|
38
43
|
|
44
|
+
@logger.info "Using Basic Authentication via #{@auth}" if @verbose && @auth
|
45
|
+
|
39
46
|
@server = WEBrick::HTTPServer.new(
|
40
|
-
Port: port,
|
41
|
-
BindAddress: bind,
|
42
|
-
Logger: logger,
|
43
|
-
AccessLog: access_log,
|
47
|
+
Port: @port,
|
48
|
+
BindAddress: @bind,
|
49
|
+
Logger: @logger,
|
50
|
+
AccessLog: @access_log,
|
44
51
|
)
|
45
52
|
|
46
|
-
@collector = collector || Collector.new
|
47
|
-
@port = port
|
48
|
-
@timeout = timeout
|
49
|
-
|
50
53
|
@server.mount_proc '/' do |req, res|
|
51
54
|
res['Content-Type'] = 'text/plain; charset=utf-8'
|
52
55
|
if req.path == '/metrics'
|
56
|
+
authenticate(req, res) if @auth
|
57
|
+
|
53
58
|
res.status = 200
|
54
59
|
if req.header["accept-encoding"].to_s.include?("gzip")
|
55
60
|
sio = StringIO.new
|
@@ -159,5 +164,12 @@ module PrometheusExporter::Server
|
|
159
164
|
gauge
|
160
165
|
end
|
161
166
|
|
167
|
+
def authenticate(req, res)
|
168
|
+
htpasswd = WEBrick::HTTPAuth::Htpasswd.new(@auth)
|
169
|
+
basic_auth = WEBrick::HTTPAuth::BasicAuth.new({ Realm: @realm, UserDB: htpasswd, Logger: @logger })
|
170
|
+
|
171
|
+
basic_auth.authenticate(req, res)
|
172
|
+
end
|
173
|
+
|
162
174
|
end
|
163
175
|
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.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Saffron
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -172,9 +172,9 @@ executables:
|
|
172
172
|
extensions: []
|
173
173
|
extra_rdoc_files: []
|
174
174
|
files:
|
175
|
+
- ".github/workflows/ci.yml"
|
175
176
|
- ".gitignore"
|
176
177
|
- ".rubocop.yml"
|
177
|
-
- ".travis.yml"
|
178
178
|
- CHANGELOG
|
179
179
|
- CODE_OF_CONDUCT.md
|
180
180
|
- Gemfile
|
data/.travis.yml
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
sudo: required
|
2
|
-
language: ruby
|
3
|
-
dist: trusty
|
4
|
-
rvm:
|
5
|
-
- 2.3
|
6
|
-
- 2.4
|
7
|
-
- 2.5
|
8
|
-
- 2.6
|
9
|
-
before_install: gem install bundler -v 1.16.1
|
10
|
-
before_script: sudo sh -c 'echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6'
|
11
|
-
|
12
|
-
script: bundle exec rubocop && bundle exec rake
|