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