prometheus_exporter 2.1.1 → 2.2.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 +4 -1
- data/.streerc +2 -0
- data/CHANGELOG +5 -0
- data/README.md +9 -7
- data/bench/bench.rb +12 -11
- data/examples/custom_collector.rb +1 -3
- data/lib/prometheus_exporter/client.rb +16 -32
- data/lib/prometheus_exporter/instrumentation/active_record.rb +20 -8
- data/lib/prometheus_exporter/instrumentation/delayed_job.rb +20 -11
- data/lib/prometheus_exporter/instrumentation/good_job.rb +2 -4
- data/lib/prometheus_exporter/instrumentation/hutch.rb +1 -1
- data/lib/prometheus_exporter/instrumentation/method_profiler.rb +12 -12
- data/lib/prometheus_exporter/instrumentation/periodic_stats.rb +13 -21
- data/lib/prometheus_exporter/instrumentation/process.rb +12 -6
- data/lib/prometheus_exporter/instrumentation/puma.rb +1 -1
- data/lib/prometheus_exporter/instrumentation/resque.rb +1 -3
- data/lib/prometheus_exporter/instrumentation/shoryuken.rb +6 -7
- data/lib/prometheus_exporter/instrumentation/sidekiq.rb +4 -6
- data/lib/prometheus_exporter/instrumentation/sidekiq_process.rb +12 -19
- data/lib/prometheus_exporter/instrumentation/sidekiq_queue.rb +15 -18
- data/lib/prometheus_exporter/instrumentation/sidekiq_stats.rb +10 -15
- data/lib/prometheus_exporter/instrumentation/unicorn.rb +2 -2
- data/lib/prometheus_exporter/metric/base.rb +8 -7
- data/lib/prometheus_exporter/metric/counter.rb +1 -3
- data/lib/prometheus_exporter/metric/gauge.rb +2 -6
- data/lib/prometheus_exporter/metric/histogram.rb +0 -2
- data/lib/prometheus_exporter/metric/summary.rb +5 -14
- data/lib/prometheus_exporter/middleware.rb +40 -32
- data/lib/prometheus_exporter/server/active_record_collector.rb +11 -6
- data/lib/prometheus_exporter/server/collector.rb +12 -16
- data/lib/prometheus_exporter/server/collector_base.rb +0 -2
- data/lib/prometheus_exporter/server/delayed_job_collector.rb +65 -28
- data/lib/prometheus_exporter/server/good_job_collector.rb +1 -1
- data/lib/prometheus_exporter/server/hutch_collector.rb +19 -11
- data/lib/prometheus_exporter/server/metrics_container.rb +4 -4
- data/lib/prometheus_exporter/server/process_collector.rb +7 -5
- data/lib/prometheus_exporter/server/puma_collector.rb +4 -10
- data/lib/prometheus_exporter/server/resque_collector.rb +1 -1
- data/lib/prometheus_exporter/server/runner.rb +34 -13
- data/lib/prometheus_exporter/server/shoryuken_collector.rb +22 -17
- data/lib/prometheus_exporter/server/sidekiq_collector.rb +22 -14
- data/lib/prometheus_exporter/server/sidekiq_process_collector.rb +9 -5
- data/lib/prometheus_exporter/server/sidekiq_queue_collector.rb +7 -6
- data/lib/prometheus_exporter/server/sidekiq_stats_collector.rb +12 -11
- data/lib/prometheus_exporter/server/unicorn_collector.rb +4 -4
- data/lib/prometheus_exporter/server/web_collector.rb +39 -22
- data/lib/prometheus_exporter/server/web_server.rb +10 -20
- data/lib/prometheus_exporter/version.rb +1 -1
- data/prometheus_exporter.gemspec +16 -18
- metadata +31 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8f8c9307f755aa00e95f323d2be11cdf6830f7e420c9bf70d90260e9bc81a85
|
4
|
+
data.tar.gz: 216bedbba838f0a84391ef2e85b290aa596cf3c42d27b4cc6bce7a9fae8be01d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ad534e47314779c76eb9e80d5de23619cd0865c2337147188d7f2ddba3bff9a6c9cf630e20720899c4e7ef9c95bf1db317a719d08fc241850f902aceae1b5cf
|
7
|
+
data.tar.gz: 6e71eab8cf6cdb049612c5afc404d6e399a142ee3eb5bbb3ae897e374ac6474d09f1b6c3ad94ab31f8d12fc52fc9e609a8b066051c89e44ea84be0fa0ec2cf0e
|
data/.github/workflows/ci.yml
CHANGED
@@ -27,7 +27,7 @@ jobs:
|
|
27
27
|
strategy:
|
28
28
|
fail-fast: false
|
29
29
|
matrix:
|
30
|
-
ruby: [
|
30
|
+
ruby: ["3.1", "3.2", "3.3"]
|
31
31
|
activerecord: [61, 70, 71]
|
32
32
|
|
33
33
|
steps:
|
@@ -42,6 +42,9 @@ jobs:
|
|
42
42
|
- name: Rubocop
|
43
43
|
run: bundle exec rubocop
|
44
44
|
|
45
|
+
- name: Syntax tree
|
46
|
+
run: bundle exec stree check Gemfile $(git ls-files '*.rb') $(git ls-files '*.rake') $(git ls-files '*.thor')
|
47
|
+
|
45
48
|
- name: Run tests
|
46
49
|
run: bundle exec rake
|
47
50
|
|
data/.streerc
ADDED
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -213,13 +213,14 @@ Rails.application.middleware.unshift PrometheusExporter::Middleware, instrument:
|
|
213
213
|
|
214
214
|
#### Metrics collected by Rails integration middleware
|
215
215
|
|
216
|
-
| Type | Name
|
217
|
-
| --- | ---
|
218
|
-
| Counter | `http_requests_total`
|
219
|
-
| Summary | `http_request_duration_seconds`
|
220
|
-
| Summary | `http_request_redis_duration_seconds`¹
|
221
|
-
| Summary | `http_request_sql_duration_seconds`²
|
222
|
-
| Summary | `http_request_queue_duration_seconds`³
|
216
|
+
| Type | Name | Description |
|
217
|
+
| --- | --- | --- |
|
218
|
+
| Counter | `http_requests_total` | Total HTTP requests from web app |
|
219
|
+
| Summary | `http_request_duration_seconds` | Time spent in HTTP reqs in seconds |
|
220
|
+
| Summary | `http_request_redis_duration_seconds`¹ | Time spent in HTTP reqs in Redis, in seconds |
|
221
|
+
| Summary | `http_request_sql_duration_seconds`² | Time spent in HTTP reqs in SQL in seconds |
|
222
|
+
| Summary | `http_request_queue_duration_seconds`³ | Time spent queueing the request in load balancer in seconds |
|
223
|
+
| Summary | `http_request_memcache_duration_seconds`⁴ | Time spent in HTTP reqs in Memcache in seconds |
|
223
224
|
|
224
225
|
All metrics have a `controller` and an `action` label.
|
225
226
|
`http_requests_total` additionally has a (HTTP response) `status` label.
|
@@ -268,6 +269,7 @@ ruby_http_request_duration_seconds{path="/api/v1/teams/:id",method="GET",status=
|
|
268
269
|
¹) Only available when Redis is used.
|
269
270
|
²) Only available when Mysql or PostgreSQL are used.
|
270
271
|
³) Only available when [Instrumenting Request Queueing Time](#instrumenting-request-queueing-time) is set up.
|
272
|
+
⁴) Only available when Dalli is used.
|
271
273
|
|
272
274
|
#### Activerecord Connection Pool Metrics
|
273
275
|
|
data/bench/bench.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative
|
3
|
+
require_relative "../lib/prometheus_exporter"
|
4
|
+
require_relative "../lib/prometheus_exporter/client"
|
5
|
+
require_relative "../lib/prometheus_exporter/server"
|
6
6
|
|
7
7
|
# test how long it takes a custom collector to process 10k messages
|
8
8
|
|
@@ -26,18 +26,19 @@ end
|
|
26
26
|
@client = nil
|
27
27
|
@runs = 1000
|
28
28
|
|
29
|
-
done =
|
30
|
-
|
31
|
-
|
32
|
-
@
|
33
|
-
|
29
|
+
done =
|
30
|
+
lambda do
|
31
|
+
puts "Elapsed for 10k messages is #{Time.now - @start}"
|
32
|
+
if (@runs -= 1) > 0
|
33
|
+
@start = Time.now
|
34
|
+
10_000.times { @client.send_json(hello: "world") }
|
35
|
+
end
|
34
36
|
end
|
35
|
-
end
|
36
37
|
|
37
38
|
collector = Collector.new(done)
|
38
|
-
server = PrometheusExporter::Server::WebServer.new port:
|
39
|
+
server = PrometheusExporter::Server::WebServer.new port: 12_349, collector: collector
|
39
40
|
server.start
|
40
|
-
@client = PrometheusExporter::Client.new port:
|
41
|
+
@client = PrometheusExporter::Client.new port: 12_349, max_queue_size: 100_000
|
41
42
|
|
42
43
|
@start = Time.now
|
43
44
|
10_000.times { @client.send_json(hello: "world") }
|
@@ -20,8 +20,6 @@ class MyCustomCollector < PrometheusExporter::Server::BaseCollector
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def prometheus_metrics_text
|
23
|
-
@mutex.synchronize
|
24
|
-
"#{@gauge1.to_prometheus_text}\n#{@gauge2.to_prometheus_text}"
|
25
|
-
end
|
23
|
+
@mutex.synchronize { "#{@gauge1.to_prometheus_text}\n#{@gauge2.to_prometheus_text}" }
|
26
24
|
end
|
27
25
|
end
|
@@ -17,13 +17,7 @@ module PrometheusExporter
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def standard_values(value, keys, prometheus_exporter_action = nil)
|
20
|
-
values = {
|
21
|
-
type: @type,
|
22
|
-
help: @help,
|
23
|
-
name: @name,
|
24
|
-
keys: keys,
|
25
|
-
value: value
|
26
|
-
}
|
20
|
+
values = { type: @type, help: @help, name: @name, keys: keys, value: value }
|
27
21
|
values[
|
28
22
|
:prometheus_exporter_action
|
29
23
|
] = prometheus_exporter_action if prometheus_exporter_action
|
@@ -59,16 +53,14 @@ module PrometheusExporter
|
|
59
53
|
|
60
54
|
def initialize(
|
61
55
|
host: ENV.fetch("PROMETHEUS_EXPORTER_HOST", "localhost"),
|
62
|
-
port: ENV.fetch(
|
63
|
-
"PROMETHEUS_EXPORTER_PORT",
|
64
|
-
PrometheusExporter::DEFAULT_PORT
|
65
|
-
),
|
56
|
+
port: ENV.fetch("PROMETHEUS_EXPORTER_PORT", PrometheusExporter::DEFAULT_PORT),
|
66
57
|
max_queue_size: nil,
|
67
58
|
thread_sleep: 0.5,
|
68
59
|
json_serializer: nil,
|
69
60
|
custom_labels: nil,
|
70
61
|
logger: Logger.new(STDERR),
|
71
|
-
log_level: Logger::WARN
|
62
|
+
log_level: Logger::WARN,
|
63
|
+
process_queue_once_and_stop: false
|
72
64
|
)
|
73
65
|
@logger = logger
|
74
66
|
@logger.level = log_level
|
@@ -83,9 +75,7 @@ module PrometheusExporter
|
|
83
75
|
max_queue_size ||= MAX_QUEUE_SIZE
|
84
76
|
max_queue_size = max_queue_size.to_i
|
85
77
|
|
86
|
-
if max_queue_size <= 0
|
87
|
-
raise ArgumentError, "max_queue_size must be larger than 0"
|
88
|
-
end
|
78
|
+
raise ArgumentError, "max_queue_size must be larger than 0" if max_queue_size <= 0
|
89
79
|
|
90
80
|
@max_queue_size = max_queue_size
|
91
81
|
@host = host
|
@@ -94,10 +84,10 @@ module PrometheusExporter
|
|
94
84
|
@mutex = Mutex.new
|
95
85
|
@thread_sleep = thread_sleep
|
96
86
|
|
97
|
-
@json_serializer =
|
98
|
-
json_serializer == :oj ? PrometheusExporter::OjCompat : JSON
|
87
|
+
@json_serializer = json_serializer == :oj ? PrometheusExporter::OjCompat : JSON
|
99
88
|
|
100
89
|
@custom_labels = custom_labels
|
90
|
+
@process_queue_once_and_stop = process_queue_once_and_stop
|
101
91
|
end
|
102
92
|
|
103
93
|
def custom_labels=(custom_labels)
|
@@ -105,14 +95,7 @@ module PrometheusExporter
|
|
105
95
|
end
|
106
96
|
|
107
97
|
def register(type, name, help, opts = nil)
|
108
|
-
metric =
|
109
|
-
RemoteMetric.new(
|
110
|
-
type: type,
|
111
|
-
name: name,
|
112
|
-
help: help,
|
113
|
-
client: self,
|
114
|
-
opts: opts
|
115
|
-
)
|
98
|
+
metric = RemoteMetric.new(type: type, name: name, help: help, client: self, opts: opts)
|
116
99
|
@metrics << metric
|
117
100
|
metric
|
118
101
|
end
|
@@ -163,7 +146,7 @@ module PrometheusExporter
|
|
163
146
|
@socket.write("\r\n")
|
164
147
|
rescue => e
|
165
148
|
logger.warn "Prometheus Exporter is dropping a message: #{e}"
|
166
|
-
|
149
|
+
close_socket!
|
167
150
|
raise
|
168
151
|
end
|
169
152
|
end
|
@@ -189,6 +172,11 @@ module PrometheusExporter
|
|
189
172
|
end
|
190
173
|
|
191
174
|
def ensure_worker_thread!
|
175
|
+
if @process_queue_once_and_stop
|
176
|
+
worker_loop
|
177
|
+
return
|
178
|
+
end
|
179
|
+
|
192
180
|
unless @worker_thread&.alive?
|
193
181
|
@mutex.synchronize do
|
194
182
|
return if @worker_thread&.alive?
|
@@ -253,8 +241,7 @@ module PrometheusExporter
|
|
253
241
|
|
254
242
|
nil
|
255
243
|
rescue StandardError
|
256
|
-
|
257
|
-
@socket_started = nil
|
244
|
+
close_socket!
|
258
245
|
@socket_pid = nil
|
259
246
|
raise
|
260
247
|
end
|
@@ -262,10 +249,7 @@ module PrometheusExporter
|
|
262
249
|
def wait_for_empty_queue_with_timeout(timeout_seconds)
|
263
250
|
start_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
264
251
|
while @queue.length > 0
|
265
|
-
if start_time + timeout_seconds <
|
266
|
-
::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
267
|
-
break
|
268
|
-
end
|
252
|
+
break if start_time + timeout_seconds < ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
269
253
|
sleep(0.05)
|
270
254
|
end
|
271
255
|
end
|
@@ -3,14 +3,16 @@
|
|
3
3
|
# collects stats from currently running process
|
4
4
|
module PrometheusExporter::Instrumentation
|
5
5
|
class ActiveRecord < PeriodicStats
|
6
|
-
ALLOWED_CONFIG_LABELS = %i
|
6
|
+
ALLOWED_CONFIG_LABELS = %i[database username host port]
|
7
7
|
|
8
8
|
def self.start(client: nil, frequency: 30, custom_labels: {}, config_labels: [])
|
9
9
|
client ||= PrometheusExporter::Client.default
|
10
10
|
|
11
11
|
# Not all rails versions support connection pool stats
|
12
12
|
unless ::ActiveRecord::Base.connection_pool.respond_to?(:stat)
|
13
|
-
client.logger.error(
|
13
|
+
client.logger.error(
|
14
|
+
"ActiveRecord connection pool stats not supported in your rails version",
|
15
|
+
)
|
14
16
|
return
|
15
17
|
end
|
16
18
|
|
@@ -29,7 +31,9 @@ module PrometheusExporter::Instrumentation
|
|
29
31
|
|
30
32
|
def self.validate_config_labels(config_labels)
|
31
33
|
return if config_labels.size == 0
|
32
|
-
|
34
|
+
if (config_labels - ALLOWED_CONFIG_LABELS).size > 0
|
35
|
+
raise "Invalid Config Labels, available options #{ALLOWED_CONFIG_LABELS}"
|
36
|
+
end
|
33
37
|
end
|
34
38
|
|
35
39
|
def initialize(metric_labels, config_labels)
|
@@ -55,7 +59,7 @@ module PrometheusExporter::Instrumentation
|
|
55
59
|
pid: pid,
|
56
60
|
type: "active_record",
|
57
61
|
hostname: ::PrometheusExporter.hostname,
|
58
|
-
metric_labels: labels(pool)
|
62
|
+
metric_labels: labels(pool),
|
59
63
|
}
|
60
64
|
metric.merge!(pool.stat)
|
61
65
|
metrics << metric
|
@@ -66,12 +70,20 @@ module PrometheusExporter::Instrumentation
|
|
66
70
|
|
67
71
|
def labels(pool)
|
68
72
|
if ::ActiveRecord.version < Gem::Version.new("6.1.0.rc1")
|
69
|
-
@metric_labels.merge(pool_name: pool.spec.name).merge(
|
70
|
-
|
71
|
-
|
73
|
+
@metric_labels.merge(pool_name: pool.spec.name).merge(
|
74
|
+
pool
|
75
|
+
.spec
|
76
|
+
.config
|
77
|
+
.select { |k, v| @config_labels.include? k }
|
78
|
+
.map { |k, v| [k.to_s.dup.prepend("dbconfig_"), v] }
|
79
|
+
.to_h,
|
80
|
+
)
|
72
81
|
else
|
73
82
|
@metric_labels.merge(pool_name: pool.db_config.name).merge(
|
74
|
-
@config_labels.each_with_object({})
|
83
|
+
@config_labels.each_with_object({}) do |l, acc|
|
84
|
+
acc["dbconfig_#{l}"] = pool.db_config.public_send(l)
|
85
|
+
end,
|
86
|
+
)
|
75
87
|
end
|
76
88
|
end
|
77
89
|
end
|
@@ -2,24 +2,33 @@
|
|
2
2
|
|
3
3
|
module PrometheusExporter::Instrumentation
|
4
4
|
class DelayedJob
|
5
|
-
JOB_CLASS_REGEXP =
|
5
|
+
JOB_CLASS_REGEXP = /job_class: ((\w+:{0,2})+)/.freeze
|
6
6
|
|
7
7
|
class << self
|
8
8
|
def register_plugin(client: nil, include_module_name: false)
|
9
9
|
instrumenter = self.new(client: client)
|
10
10
|
return unless defined?(Delayed::Plugin)
|
11
11
|
|
12
|
-
plugin =
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
plugin =
|
13
|
+
Class.new(Delayed::Plugin) do
|
14
|
+
callbacks do |lifecycle|
|
15
|
+
lifecycle.around(:invoke_job) do |job, *args, &block|
|
16
|
+
max_attempts = Delayed::Worker.max_attempts
|
17
|
+
enqueued_count = Delayed::Job.where(queue: job.queue).count
|
18
|
+
pending_count =
|
19
|
+
Delayed::Job.where(attempts: 0, locked_at: nil, queue: job.queue).count
|
20
|
+
instrumenter.call(
|
21
|
+
job,
|
22
|
+
max_attempts,
|
23
|
+
enqueued_count,
|
24
|
+
pending_count,
|
25
|
+
include_module_name,
|
26
|
+
*args,
|
27
|
+
&block
|
28
|
+
)
|
29
|
+
end
|
20
30
|
end
|
21
31
|
end
|
22
|
-
end
|
23
32
|
|
24
33
|
Delayed::Worker.plugins << plugin
|
25
34
|
end
|
@@ -50,7 +59,7 @@ module PrometheusExporter::Instrumentation
|
|
50
59
|
attempts: attempts,
|
51
60
|
max_attempts: max_attempts,
|
52
61
|
enqueued: enqueued_count,
|
53
|
-
pending: pending_count
|
62
|
+
pending: pending_count,
|
54
63
|
)
|
55
64
|
end
|
56
65
|
end
|
@@ -7,9 +7,7 @@ module PrometheusExporter::Instrumentation
|
|
7
7
|
good_job_collector = new
|
8
8
|
client ||= PrometheusExporter::Client.default
|
9
9
|
|
10
|
-
worker_loop
|
11
|
-
client.send_json(good_job_collector.collect)
|
12
|
-
end
|
10
|
+
worker_loop { client.send_json(good_job_collector.collect) }
|
13
11
|
|
14
12
|
super
|
15
13
|
end
|
@@ -23,7 +21,7 @@ module PrometheusExporter::Instrumentation
|
|
23
21
|
running: ::GoodJob::Job.running.size,
|
24
22
|
finished: ::GoodJob::Job.finished.size,
|
25
23
|
succeeded: ::GoodJob::Job.succeeded.size,
|
26
|
-
discarded: ::GoodJob::Job.discarded.size
|
24
|
+
discarded: ::GoodJob::Job.discarded.size,
|
27
25
|
}
|
28
26
|
end
|
29
27
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# see https://samsaffron.com/archive/2017/10/18/fastest-way-to-profile-a-method-in-ruby
|
4
|
-
module PrometheusExporter::Instrumentation
|
4
|
+
module PrometheusExporter::Instrumentation
|
5
|
+
end
|
5
6
|
|
6
7
|
class PrometheusExporter::Instrumentation::MethodProfiler
|
7
8
|
def self.patch(klass, methods, name, instrument:)
|
@@ -21,9 +22,8 @@ class PrometheusExporter::Instrumentation::MethodProfiler
|
|
21
22
|
end
|
22
23
|
|
23
24
|
def self.start(transfer = nil)
|
24
|
-
Thread.current[:_method_profiler] = transfer ||
|
25
|
-
__start: Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
26
|
-
}
|
25
|
+
Thread.current[:_method_profiler] = transfer ||
|
26
|
+
{ __start: Process.clock_gettime(Process::CLOCK_MONOTONIC) }
|
27
27
|
end
|
28
28
|
|
29
29
|
def self.clear
|
@@ -42,8 +42,8 @@ class PrometheusExporter::Instrumentation::MethodProfiler
|
|
42
42
|
|
43
43
|
def self.define_methods_on_module(klass, methods, name)
|
44
44
|
patch_source_line = __LINE__ + 3
|
45
|
-
|
46
|
-
|
45
|
+
|
46
|
+
patches = methods.map { |method_name| <<~RUBY }.join("\n")
|
47
47
|
def #{method_name}(...)
|
48
48
|
unless prof = Thread.current[:_method_profiler]
|
49
49
|
return super
|
@@ -58,9 +58,8 @@ class PrometheusExporter::Instrumentation::MethodProfiler
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
RUBY
|
61
|
-
end.join("\n")
|
62
61
|
|
63
|
-
klass.module_eval
|
62
|
+
klass.module_eval(patches, __FILE__, patch_source_line)
|
64
63
|
end
|
65
64
|
|
66
65
|
def self.patch_using_prepend(klass, methods, name)
|
@@ -71,14 +70,16 @@ class PrometheusExporter::Instrumentation::MethodProfiler
|
|
71
70
|
|
72
71
|
def self.patch_using_alias_method(klass, methods, name)
|
73
72
|
patch_source_line = __LINE__ + 3
|
74
|
-
|
75
|
-
|
73
|
+
|
74
|
+
patches = methods.map { |method_name| <<~RUBY }.join("\n")
|
76
75
|
unless defined?(#{method_name}__mp_unpatched)
|
77
76
|
alias_method :#{method_name}__mp_unpatched, :#{method_name}
|
77
|
+
|
78
78
|
def #{method_name}(...)
|
79
79
|
unless prof = Thread.current[:_method_profiler]
|
80
80
|
return #{method_name}__mp_unpatched(...)
|
81
81
|
end
|
82
|
+
|
82
83
|
begin
|
83
84
|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
84
85
|
#{method_name}__mp_unpatched(...)
|
@@ -90,8 +91,7 @@ class PrometheusExporter::Instrumentation::MethodProfiler
|
|
90
91
|
end
|
91
92
|
end
|
92
93
|
RUBY
|
93
|
-
end.join("\n")
|
94
94
|
|
95
|
-
klass.class_eval
|
95
|
+
klass.class_eval(patches, __FILE__, patch_source_line)
|
96
96
|
end
|
97
97
|
end
|
@@ -2,21 +2,14 @@
|
|
2
2
|
|
3
3
|
module PrometheusExporter::Instrumentation
|
4
4
|
class PeriodicStats
|
5
|
-
|
6
5
|
def self.start(*args, frequency:, client: nil, **kwargs)
|
7
6
|
client ||= PrometheusExporter::Client.default
|
8
7
|
|
9
|
-
if !(Numeric === frequency)
|
10
|
-
raise ArgumentError.new("Expected frequency to be a number")
|
11
|
-
end
|
8
|
+
raise ArgumentError.new("Expected frequency to be a number") if !(Numeric === frequency)
|
12
9
|
|
13
|
-
if frequency < 0
|
14
|
-
raise ArgumentError.new("Expected frequency to be a positive number")
|
15
|
-
end
|
10
|
+
raise ArgumentError.new("Expected frequency to be a positive number") if frequency < 0
|
16
11
|
|
17
|
-
if !@worker_loop
|
18
|
-
raise ArgumentError.new("Worker loop was not set")
|
19
|
-
end
|
12
|
+
raise ArgumentError.new("Worker loop was not set") if !@worker_loop
|
20
13
|
|
21
14
|
klass = self
|
22
15
|
|
@@ -24,18 +17,18 @@ module PrometheusExporter::Instrumentation
|
|
24
17
|
|
25
18
|
@stop_thread = false
|
26
19
|
|
27
|
-
@thread =
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
20
|
+
@thread =
|
21
|
+
Thread.new do
|
22
|
+
while !@stop_thread
|
23
|
+
begin
|
24
|
+
@worker_loop.call
|
25
|
+
rescue => e
|
26
|
+
client.logger.error("#{klass} Prometheus Exporter Failed To Collect Stats #{e}")
|
27
|
+
ensure
|
28
|
+
sleep frequency
|
29
|
+
end
|
35
30
|
end
|
36
31
|
end
|
37
|
-
end
|
38
|
-
|
39
32
|
end
|
40
33
|
|
41
34
|
def self.started?
|
@@ -57,6 +50,5 @@ module PrometheusExporter::Instrumentation
|
|
57
50
|
end
|
58
51
|
@thread = nil
|
59
52
|
end
|
60
|
-
|
61
53
|
end
|
62
54
|
end
|
@@ -3,9 +3,7 @@
|
|
3
3
|
# collects stats from currently running process
|
4
4
|
module PrometheusExporter::Instrumentation
|
5
5
|
class Process < PeriodicStats
|
6
|
-
|
7
6
|
def self.start(client: nil, type: "ruby", frequency: 30, labels: nil)
|
8
|
-
|
9
7
|
metric_labels =
|
10
8
|
if labels && type
|
11
9
|
labels.merge(type: type)
|
@@ -46,14 +44,22 @@ module PrometheusExporter::Instrumentation
|
|
46
44
|
end
|
47
45
|
|
48
46
|
def rss
|
49
|
-
@pagesize ||=
|
50
|
-
|
47
|
+
@pagesize ||=
|
48
|
+
begin
|
49
|
+
`getconf PAGESIZE`.to_i
|
50
|
+
rescue StandardError
|
51
|
+
4096
|
52
|
+
end
|
53
|
+
begin
|
54
|
+
File.read("/proc/#{pid}/statm").split(" ")[1].to_i * @pagesize
|
55
|
+
rescue StandardError
|
56
|
+
0
|
57
|
+
end
|
51
58
|
end
|
52
59
|
|
53
60
|
def collect_process_stats(metric)
|
54
61
|
metric[:pid] = pid
|
55
62
|
metric[:rss] = rss
|
56
|
-
|
57
63
|
end
|
58
64
|
|
59
65
|
def collect_gc_stats(metric)
|
@@ -68,7 +74,7 @@ module PrometheusExporter::Instrumentation
|
|
68
74
|
end
|
69
75
|
|
70
76
|
def collect_v8_stats(metric)
|
71
|
-
return if !defined?
|
77
|
+
return if !defined?(MiniRacer)
|
72
78
|
|
73
79
|
metric[:v8_heap_count] = metric[:v8_heap_size] = 0
|
74
80
|
metric[:v8_heap_size] = metric[:v8_physical_size] = 0
|
@@ -7,9 +7,7 @@ module PrometheusExporter::Instrumentation
|
|
7
7
|
resque_collector = new
|
8
8
|
client ||= PrometheusExporter::Client.default
|
9
9
|
|
10
|
-
worker_loop
|
11
|
-
client.send_json(resque_collector.collect)
|
12
|
-
end
|
10
|
+
worker_loop { client.send_json(resque_collector.collect) }
|
13
11
|
|
14
12
|
super
|
15
13
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
module PrometheusExporter::Instrumentation
|
4
4
|
class Shoryuken
|
5
|
-
|
6
5
|
def initialize(client: nil)
|
7
6
|
@client = client || PrometheusExporter::Client.default
|
8
7
|
end
|
@@ -19,12 +18,12 @@ module PrometheusExporter::Instrumentation
|
|
19
18
|
ensure
|
20
19
|
duration = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start
|
21
20
|
@client.send_json(
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
type: "shoryuken",
|
22
|
+
queue: queue,
|
23
|
+
name: worker.class.name,
|
24
|
+
success: success,
|
25
|
+
shutdown: shutdown,
|
26
|
+
duration: duration,
|
28
27
|
)
|
29
28
|
end
|
30
29
|
end
|
@@ -3,8 +3,7 @@
|
|
3
3
|
require "yaml"
|
4
4
|
|
5
5
|
module PrometheusExporter::Instrumentation
|
6
|
-
JOB_WRAPPER_CLASS_NAME =
|
7
|
-
"ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
|
6
|
+
JOB_WRAPPER_CLASS_NAME = "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
|
8
7
|
DELAYED_CLASS_NAMES = %w[
|
9
8
|
Sidekiq::Extensions::DelayedClass
|
10
9
|
Sidekiq::Extensions::DelayedModel
|
@@ -24,7 +23,7 @@ module PrometheusExporter::Instrumentation
|
|
24
23
|
type: "sidekiq",
|
25
24
|
name: get_name(job["class"], job),
|
26
25
|
dead: true,
|
27
|
-
custom_labels: worker_custom_labels
|
26
|
+
custom_labels: worker_custom_labels,
|
28
27
|
)
|
29
28
|
end
|
30
29
|
end
|
@@ -44,8 +43,7 @@ module PrometheusExporter::Instrumentation
|
|
44
43
|
end
|
45
44
|
|
46
45
|
def initialize(options = { client: nil })
|
47
|
-
@client =
|
48
|
-
options.fetch(:client, nil) || PrometheusExporter::Client.default
|
46
|
+
@client = options.fetch(:client, nil) || PrometheusExporter::Client.default
|
49
47
|
end
|
50
48
|
|
51
49
|
def call(worker, msg, queue)
|
@@ -67,7 +65,7 @@ module PrometheusExporter::Instrumentation
|
|
67
65
|
success: success,
|
68
66
|
shutdown: shutdown,
|
69
67
|
duration: duration,
|
70
|
-
custom_labels: self.class.get_worker_custom_labels(worker.class, msg)
|
68
|
+
custom_labels: self.class.get_worker_custom_labels(worker.class, msg),
|
71
69
|
)
|
72
70
|
end
|
73
71
|
|