prometheus_exporter 0.7.0 → 2.3.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/CHANGELOG +298 -35
- data/README.md +276 -53
- data/{bin → exe}/prometheus_exporter +20 -7
- data/lib/prometheus_exporter/client.rb +41 -32
- data/lib/prometheus_exporter/instrumentation/active_record.rb +29 -35
- data/lib/prometheus_exporter/instrumentation/delayed_job.rb +28 -13
- data/lib/prometheus_exporter/instrumentation/good_job.rb +28 -0
- data/lib/prometheus_exporter/instrumentation/hutch.rb +1 -1
- data/lib/prometheus_exporter/instrumentation/method_profiler.rb +67 -27
- data/lib/prometheus_exporter/instrumentation/periodic_stats.rb +54 -0
- data/lib/prometheus_exporter/instrumentation/process.rb +25 -27
- data/lib/prometheus_exporter/instrumentation/puma.rb +36 -27
- data/lib/prometheus_exporter/instrumentation/resque.rb +33 -0
- data/lib/prometheus_exporter/instrumentation/shoryuken.rb +6 -7
- data/lib/prometheus_exporter/instrumentation/sidekiq.rb +51 -23
- data/lib/prometheus_exporter/instrumentation/sidekiq_process.rb +45 -0
- data/lib/prometheus_exporter/instrumentation/sidekiq_queue.rb +38 -33
- data/lib/prometheus_exporter/instrumentation/sidekiq_stats.rb +32 -0
- data/lib/prometheus_exporter/instrumentation/unicorn.rb +12 -17
- data/lib/prometheus_exporter/instrumentation.rb +5 -0
- data/lib/prometheus_exporter/metric/base.rb +20 -17
- data/lib/prometheus_exporter/metric/counter.rb +1 -3
- data/lib/prometheus_exporter/metric/gauge.rb +6 -6
- data/lib/prometheus_exporter/metric/histogram.rb +15 -5
- data/lib/prometheus_exporter/metric/summary.rb +5 -14
- data/lib/prometheus_exporter/middleware.rb +72 -38
- data/lib/prometheus_exporter/server/active_record_collector.rb +16 -14
- data/lib/prometheus_exporter/server/collector.rb +29 -17
- data/lib/prometheus_exporter/server/collector_base.rb +0 -2
- data/lib/prometheus_exporter/server/delayed_job_collector.rb +76 -33
- data/lib/prometheus_exporter/server/good_job_collector.rb +52 -0
- data/lib/prometheus_exporter/server/hutch_collector.rb +19 -11
- data/lib/prometheus_exporter/server/metrics_container.rb +66 -0
- data/lib/prometheus_exporter/server/process_collector.rb +15 -14
- data/lib/prometheus_exporter/server/puma_collector.rb +21 -18
- data/lib/prometheus_exporter/server/resque_collector.rb +50 -0
- data/lib/prometheus_exporter/server/runner.rb +49 -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 +47 -0
- data/lib/prometheus_exporter/server/sidekiq_queue_collector.rb +12 -12
- data/lib/prometheus_exporter/server/sidekiq_stats_collector.rb +49 -0
- data/lib/prometheus_exporter/server/type_collector.rb +2 -0
- data/lib/prometheus_exporter/server/unicorn_collector.rb +32 -33
- data/lib/prometheus_exporter/server/web_collector.rb +48 -31
- data/lib/prometheus_exporter/server/web_server.rb +70 -48
- data/lib/prometheus_exporter/server.rb +4 -0
- data/lib/prometheus_exporter/version.rb +1 -1
- data/lib/prometheus_exporter.rb +12 -13
- metadata +19 -206
- data/.github/workflows/ci.yml +0 -42
- data/.gitignore +0 -13
- data/.rubocop.yml +0 -7
- data/Appraisals +0 -10
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -8
- data/Guardfile +0 -8
- data/Rakefile +0 -12
- data/bench/bench.rb +0 -45
- data/examples/custom_collector.rb +0 -27
- data/gemfiles/.bundle/config +0 -2
- data/gemfiles/ar_60.gemfile +0 -5
- data/gemfiles/ar_61.gemfile +0 -7
- data/prometheus_exporter.gemspec +0 -46
|
@@ -14,8 +14,8 @@ module PrometheusExporter::Server
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def collect(obj)
|
|
17
|
-
default_labels = { job_name: obj[
|
|
18
|
-
custom_labels = obj[
|
|
17
|
+
default_labels = { job_name: obj["name"] }
|
|
18
|
+
custom_labels = obj["custom_labels"]
|
|
19
19
|
labels = custom_labels.nil? ? default_labels : default_labels.merge(custom_labels)
|
|
20
20
|
|
|
21
21
|
ensure_hutch_metrics
|
|
@@ -36,15 +36,23 @@ module PrometheusExporter::Server
|
|
|
36
36
|
|
|
37
37
|
def ensure_hutch_metrics
|
|
38
38
|
if !@hutch_jobs_total
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
@hutch_job_duration_seconds =
|
|
40
|
+
PrometheusExporter::Metric::Counter.new(
|
|
41
|
+
"hutch_job_duration_seconds",
|
|
42
|
+
"Total time spent in hutch jobs.",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
@hutch_jobs_total =
|
|
46
|
+
PrometheusExporter::Metric::Counter.new(
|
|
47
|
+
"hutch_jobs_total",
|
|
48
|
+
"Total number of hutch jobs executed.",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
@hutch_failed_jobs_total =
|
|
52
|
+
PrometheusExporter::Metric::Counter.new(
|
|
53
|
+
"hutch_failed_jobs_total",
|
|
54
|
+
"Total number failed hutch jobs executed.",
|
|
55
|
+
)
|
|
48
56
|
end
|
|
49
57
|
end
|
|
50
58
|
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PrometheusExporter::Server
|
|
4
|
+
class MetricsContainer
|
|
5
|
+
METRIC_MAX_AGE = 60
|
|
6
|
+
METRIC_EXPIRE_ATTR = "_expire_at"
|
|
7
|
+
|
|
8
|
+
attr_reader :data, :ttl
|
|
9
|
+
attr_accessor :filter
|
|
10
|
+
|
|
11
|
+
def initialize(ttl: METRIC_MAX_AGE, expire_attr: METRIC_EXPIRE_ATTR, filter: nil)
|
|
12
|
+
@data = []
|
|
13
|
+
@ttl = ttl
|
|
14
|
+
@expire_attr = expire_attr
|
|
15
|
+
@filter = filter
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def <<(obj)
|
|
19
|
+
now = get_time
|
|
20
|
+
obj[@expire_attr] = now + @ttl
|
|
21
|
+
|
|
22
|
+
expire(time: now, new_metric: obj)
|
|
23
|
+
|
|
24
|
+
@data << obj
|
|
25
|
+
@data
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def [](key)
|
|
29
|
+
@data.tap { expire }[key]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def size(&blk)
|
|
33
|
+
wrap_expire(:size, &blk)
|
|
34
|
+
end
|
|
35
|
+
alias_method :length, :size
|
|
36
|
+
|
|
37
|
+
def map(&blk)
|
|
38
|
+
wrap_expire(:map, &blk)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def each(&blk)
|
|
42
|
+
wrap_expire(:each, &blk)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def expire(time: nil, new_metric: nil)
|
|
46
|
+
time ||= get_time
|
|
47
|
+
|
|
48
|
+
@data.delete_if do |metric|
|
|
49
|
+
expired = metric[@expire_attr] < time
|
|
50
|
+
expired ||= filter.call(new_metric, metric) if @filter && new_metric
|
|
51
|
+
expired
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def get_time
|
|
58
|
+
::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def wrap_expire(method_name, &blk)
|
|
62
|
+
expire
|
|
63
|
+
@data.public_send(method_name, &blk)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module PrometheusExporter::Server
|
|
4
|
-
|
|
5
4
|
class ProcessCollector < TypeCollector
|
|
6
|
-
|
|
5
|
+
MAX_METRIC_AGE = 60
|
|
6
|
+
|
|
7
7
|
PROCESS_GAUGES = {
|
|
8
8
|
heap_free_slots: "Free ruby heap slots.",
|
|
9
9
|
heap_live_slots: "Used ruby heap slots.",
|
|
@@ -12,6 +12,12 @@ module PrometheusExporter::Server
|
|
|
12
12
|
v8_physical_size: "Physical size consumed by V8 heaps.",
|
|
13
13
|
v8_heap_count: "Number of V8 contexts running.",
|
|
14
14
|
rss: "Total RSS used by process.",
|
|
15
|
+
malloc_increase_bytes_limit:
|
|
16
|
+
"Limit before Ruby triggers a GC against current objects (bytes).",
|
|
17
|
+
oldmalloc_increase_bytes_limit:
|
|
18
|
+
"Limit before Ruby triggers a major GC against old objects (bytes).",
|
|
19
|
+
marking_time: "Time spent in GC marking.",
|
|
20
|
+
sweeping_time: "Time spent in GC sweeping.",
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
PROCESS_COUNTERS = {
|
|
@@ -21,7 +27,10 @@ module PrometheusExporter::Server
|
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
def initialize
|
|
24
|
-
@process_metrics =
|
|
30
|
+
@process_metrics = MetricsContainer.new(ttl: MAX_METRIC_AGE)
|
|
31
|
+
@process_metrics.filter = ->(new_metric, old_metric) do
|
|
32
|
+
new_metric["pid"] == old_metric["pid"] && new_metric["hostname"] == old_metric["hostname"]
|
|
33
|
+
end
|
|
25
34
|
end
|
|
26
35
|
|
|
27
36
|
def type
|
|
@@ -34,8 +43,9 @@ module PrometheusExporter::Server
|
|
|
34
43
|
metrics = {}
|
|
35
44
|
|
|
36
45
|
@process_metrics.map do |m|
|
|
37
|
-
metric_key =
|
|
38
|
-
|
|
46
|
+
metric_key =
|
|
47
|
+
(m["metric_labels"] || {}).merge("pid" => m["pid"], "hostname" => m["hostname"])
|
|
48
|
+
metric_key.merge!(m["custom_labels"]) if m["custom_labels"]
|
|
39
49
|
|
|
40
50
|
PROCESS_GAUGES.map do |k, help|
|
|
41
51
|
k = k.to_s
|
|
@@ -58,15 +68,6 @@ module PrometheusExporter::Server
|
|
|
58
68
|
end
|
|
59
69
|
|
|
60
70
|
def collect(obj)
|
|
61
|
-
now = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
|
62
|
-
|
|
63
|
-
obj["created_at"] = now
|
|
64
|
-
|
|
65
|
-
@process_metrics.delete_if do |current|
|
|
66
|
-
(obj["pid"] == current["pid"] && obj["hostname"] == current["hostname"]) ||
|
|
67
|
-
(current["created_at"] + MAX_PROCESS_METRIC_AGE < now)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
71
|
@process_metrics << obj
|
|
71
72
|
end
|
|
72
73
|
end
|
|
@@ -4,17 +4,27 @@ module PrometheusExporter::Server
|
|
|
4
4
|
class PumaCollector < TypeCollector
|
|
5
5
|
MAX_PUMA_METRIC_AGE = 30
|
|
6
6
|
PUMA_GAUGES = {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
workers: "Number of puma workers.",
|
|
8
|
+
booted_workers: "Number of puma workers booted.",
|
|
9
|
+
old_workers: "Number of old puma workers.",
|
|
10
|
+
running_threads: "Number of puma threads currently running.",
|
|
11
|
+
request_backlog: "Number of requests waiting to be processed by a puma thread.",
|
|
12
|
+
thread_pool_capacity: "Number of puma threads available at current scale.",
|
|
13
|
+
max_threads: "Number of puma threads at available at max scale.",
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
if defined?(::Puma::Const) &&
|
|
17
|
+
Gem::Version.new(::Puma::Const::VERSION) >= Gem::Version.new("6.6.0")
|
|
18
|
+
PUMA_GAUGES[
|
|
19
|
+
:busy_threads
|
|
20
|
+
] = "Wholistic stat reflecting the overall current state of work to be done and the capacity to do it"
|
|
21
|
+
end
|
|
22
|
+
|
|
16
23
|
def initialize
|
|
17
|
-
@puma_metrics =
|
|
24
|
+
@puma_metrics = MetricsContainer.new(ttl: MAX_PUMA_METRIC_AGE)
|
|
25
|
+
@puma_metrics.filter = ->(new_metric, old_metric) do
|
|
26
|
+
new_metric["pid"] == old_metric["pid"] && new_metric["hostname"] == old_metric["hostname"]
|
|
27
|
+
end
|
|
18
28
|
end
|
|
19
29
|
|
|
20
30
|
def type
|
|
@@ -28,12 +38,9 @@ module PrometheusExporter::Server
|
|
|
28
38
|
|
|
29
39
|
@puma_metrics.map do |m|
|
|
30
40
|
labels = {}
|
|
31
|
-
if m["phase"]
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if m["custom_labels"]
|
|
35
|
-
labels.merge!(m["custom_labels"])
|
|
36
|
-
end
|
|
41
|
+
labels.merge!(phase: m["phase"]) if m["phase"]
|
|
42
|
+
labels.merge!(m["custom_labels"]) if m["custom_labels"]
|
|
43
|
+
labels.merge!(m["metric_labels"]) if m["metric_labels"]
|
|
37
44
|
|
|
38
45
|
PUMA_GAUGES.map do |k, help|
|
|
39
46
|
k = k.to_s
|
|
@@ -48,10 +55,6 @@ module PrometheusExporter::Server
|
|
|
48
55
|
end
|
|
49
56
|
|
|
50
57
|
def collect(obj)
|
|
51
|
-
now = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
|
52
|
-
|
|
53
|
-
obj["created_at"] = now
|
|
54
|
-
@puma_metrics.delete_if { |m| m["created_at"] + MAX_PUMA_METRIC_AGE < now }
|
|
55
58
|
@puma_metrics << obj
|
|
56
59
|
end
|
|
57
60
|
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PrometheusExporter::Server
|
|
4
|
+
class ResqueCollector < TypeCollector
|
|
5
|
+
MAX_METRIC_AGE = 30
|
|
6
|
+
RESQUE_GAUGES = {
|
|
7
|
+
processed_jobs: "Total number of processed Resque jobs.",
|
|
8
|
+
failed_jobs: "Total number of failed Resque jobs.",
|
|
9
|
+
pending_jobs: "Total number of pending Resque jobs.",
|
|
10
|
+
queues: "Total number of Resque queues.",
|
|
11
|
+
workers: "Total number of Resque workers running.",
|
|
12
|
+
working: "Total number of Resque workers working.",
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
@resque_metrics = MetricsContainer.new(ttl: MAX_METRIC_AGE)
|
|
17
|
+
@gauges = {}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def type
|
|
21
|
+
"resque"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def metrics
|
|
25
|
+
return [] if resque_metrics.length == 0
|
|
26
|
+
|
|
27
|
+
resque_metrics.map do |metric|
|
|
28
|
+
labels = metric.fetch("custom_labels", {})
|
|
29
|
+
|
|
30
|
+
RESQUE_GAUGES.map do |name, help|
|
|
31
|
+
name = name.to_s
|
|
32
|
+
if value = metric[name]
|
|
33
|
+
gauge = gauges[name] ||= PrometheusExporter::Metric::Gauge.new("resque_#{name}", help)
|
|
34
|
+
gauge.observe(value, labels)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
gauges.values
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def collect(object)
|
|
43
|
+
@resque_metrics << object
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
attr_reader :resque_metrics, :gauges
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require_relative '../instrumentation/unicorn'
|
|
3
|
+
require_relative "../client"
|
|
5
4
|
|
|
6
5
|
module PrometheusExporter::Server
|
|
7
|
-
class RunnerException < StandardError
|
|
8
|
-
|
|
6
|
+
class RunnerException < StandardError
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class WrongInheritance < RunnerException
|
|
10
|
+
end
|
|
9
11
|
|
|
10
12
|
class Runner
|
|
11
13
|
def initialize(options = {})
|
|
@@ -17,37 +19,67 @@ module PrometheusExporter::Server
|
|
|
17
19
|
@prefix = nil
|
|
18
20
|
@auth = nil
|
|
19
21
|
@realm = nil
|
|
22
|
+
@histogram = nil
|
|
20
23
|
|
|
21
|
-
options.each
|
|
22
|
-
send("#{k}=", v) if self.class.method_defined?("#{k}=")
|
|
23
|
-
end
|
|
24
|
+
options.each { |k, v| send("#{k}=", v) if self.class.method_defined?("#{k}=") }
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
def start
|
|
27
28
|
PrometheusExporter::Metric::Base.default_prefix = prefix
|
|
28
29
|
PrometheusExporter::Metric::Base.default_labels = label
|
|
29
30
|
|
|
31
|
+
if histogram
|
|
32
|
+
PrometheusExporter::Metric::Base.default_aggregation = PrometheusExporter::Metric::Histogram
|
|
33
|
+
end
|
|
34
|
+
|
|
30
35
|
register_type_collectors
|
|
31
36
|
|
|
32
37
|
unless collector.is_a?(PrometheusExporter::Server::CollectorBase)
|
|
33
|
-
raise WrongInheritance,
|
|
38
|
+
raise WrongInheritance,
|
|
39
|
+
"Collector class must be inherited from PrometheusExporter::Server::CollectorBase"
|
|
34
40
|
end
|
|
35
41
|
|
|
36
42
|
if unicorn_listen_address && unicorn_pid_file
|
|
43
|
+
require_relative "../instrumentation"
|
|
44
|
+
|
|
37
45
|
local_client = PrometheusExporter::LocalClient.new(collector: collector)
|
|
38
46
|
PrometheusExporter::Instrumentation::Unicorn.start(
|
|
39
47
|
pid_file: unicorn_pid_file,
|
|
40
48
|
listener_address: unicorn_listen_address,
|
|
41
|
-
client: local_client
|
|
49
|
+
client: local_client,
|
|
42
50
|
)
|
|
43
51
|
end
|
|
44
52
|
|
|
45
|
-
server =
|
|
46
|
-
|
|
53
|
+
@server =
|
|
54
|
+
server_class.new(
|
|
55
|
+
port: port,
|
|
56
|
+
bind: bind,
|
|
57
|
+
collector: collector,
|
|
58
|
+
timeout: timeout,
|
|
59
|
+
verbose: verbose,
|
|
60
|
+
auth: auth,
|
|
61
|
+
realm: realm,
|
|
62
|
+
)
|
|
63
|
+
@server.start
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def stop
|
|
67
|
+
@server.stop
|
|
47
68
|
end
|
|
48
69
|
|
|
49
70
|
attr_accessor :unicorn_listen_address, :unicorn_pid_file
|
|
50
|
-
attr_writer :prefix,
|
|
71
|
+
attr_writer :prefix,
|
|
72
|
+
:port,
|
|
73
|
+
:bind,
|
|
74
|
+
:collector_class,
|
|
75
|
+
:type_collectors,
|
|
76
|
+
:timeout,
|
|
77
|
+
:verbose,
|
|
78
|
+
:server_class,
|
|
79
|
+
:label,
|
|
80
|
+
:auth,
|
|
81
|
+
:realm,
|
|
82
|
+
:histogram
|
|
51
83
|
|
|
52
84
|
def auth
|
|
53
85
|
@auth || nil
|
|
@@ -82,7 +114,7 @@ module PrometheusExporter::Server
|
|
|
82
114
|
end
|
|
83
115
|
|
|
84
116
|
def verbose
|
|
85
|
-
return @verbose if defined?
|
|
117
|
+
return @verbose if defined?(@verbose)
|
|
86
118
|
false
|
|
87
119
|
end
|
|
88
120
|
|
|
@@ -98,6 +130,10 @@ module PrometheusExporter::Server
|
|
|
98
130
|
@label ||= PrometheusExporter::DEFAULT_LABEL
|
|
99
131
|
end
|
|
100
132
|
|
|
133
|
+
def histogram
|
|
134
|
+
@histogram || false
|
|
135
|
+
end
|
|
136
|
+
|
|
101
137
|
private
|
|
102
138
|
|
|
103
139
|
def register_type_collectors
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module PrometheusExporter::Server
|
|
4
4
|
class ShoryukenCollector < TypeCollector
|
|
5
|
-
|
|
6
5
|
def initialize
|
|
7
6
|
@shoryuken_jobs_total = nil
|
|
8
7
|
@shoryuken_job_duration_seconds = nil
|
|
@@ -16,8 +15,8 @@ module PrometheusExporter::Server
|
|
|
16
15
|
end
|
|
17
16
|
|
|
18
17
|
def collect(obj)
|
|
19
|
-
default_labels = { job_name: obj[
|
|
20
|
-
custom_labels = obj[
|
|
18
|
+
default_labels = { job_name: obj["name"], queue_name: obj["queue"] }
|
|
19
|
+
custom_labels = obj["custom_labels"]
|
|
21
20
|
labels = custom_labels.nil? ? default_labels : default_labels.merge(custom_labels)
|
|
22
21
|
|
|
23
22
|
ensure_shoryuken_metrics
|
|
@@ -30,10 +29,10 @@ module PrometheusExporter::Server
|
|
|
30
29
|
def metrics
|
|
31
30
|
if @shoryuken_jobs_total
|
|
32
31
|
[
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
@shoryuken_job_duration_seconds,
|
|
33
|
+
@shoryuken_jobs_total,
|
|
34
|
+
@shoryuken_restarted_jobs_total,
|
|
35
|
+
@shoryuken_failed_jobs_total,
|
|
37
36
|
]
|
|
38
37
|
else
|
|
39
38
|
[]
|
|
@@ -44,23 +43,29 @@ module PrometheusExporter::Server
|
|
|
44
43
|
|
|
45
44
|
def ensure_shoryuken_metrics
|
|
46
45
|
if !@shoryuken_jobs_total
|
|
47
|
-
|
|
48
46
|
@shoryuken_job_duration_seconds =
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
PrometheusExporter::Metric::Counter.new(
|
|
48
|
+
"shoryuken_job_duration_seconds",
|
|
49
|
+
"Total time spent in shoryuken jobs.",
|
|
50
|
+
)
|
|
51
51
|
|
|
52
52
|
@shoryuken_jobs_total =
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
PrometheusExporter::Metric::Counter.new(
|
|
54
|
+
"shoryuken_jobs_total",
|
|
55
|
+
"Total number of shoryuken jobs executed.",
|
|
56
|
+
)
|
|
55
57
|
|
|
56
58
|
@shoryuken_restarted_jobs_total =
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
PrometheusExporter::Metric::Counter.new(
|
|
60
|
+
"shoryuken_restarted_jobs_total",
|
|
61
|
+
"Total number of shoryuken jobs that we restarted because of a shoryuken shutdown.",
|
|
62
|
+
)
|
|
59
63
|
|
|
60
64
|
@shoryuken_failed_jobs_total =
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
PrometheusExporter::Metric::Counter.new(
|
|
66
|
+
"shoryuken_failed_jobs_total",
|
|
67
|
+
"Total number of failed shoryuken jobs.",
|
|
68
|
+
)
|
|
64
69
|
end
|
|
65
70
|
end
|
|
66
71
|
end
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module PrometheusExporter::Server
|
|
4
4
|
class SidekiqCollector < TypeCollector
|
|
5
|
-
|
|
6
5
|
def initialize
|
|
7
6
|
@sidekiq_jobs_total = nil
|
|
8
7
|
@sidekiq_job_duration_seconds = nil
|
|
@@ -17,8 +16,8 @@ module PrometheusExporter::Server
|
|
|
17
16
|
end
|
|
18
17
|
|
|
19
18
|
def collect(obj)
|
|
20
|
-
default_labels = { job_name: obj[
|
|
21
|
-
custom_labels = obj[
|
|
19
|
+
default_labels = { job_name: obj["name"], queue: obj["queue"] }
|
|
20
|
+
custom_labels = obj["custom_labels"]
|
|
22
21
|
labels = custom_labels.nil? ? default_labels : default_labels.merge(custom_labels)
|
|
23
22
|
|
|
24
23
|
ensure_sidekiq_metrics
|
|
@@ -50,26 +49,35 @@ module PrometheusExporter::Server
|
|
|
50
49
|
|
|
51
50
|
def ensure_sidekiq_metrics
|
|
52
51
|
if !@sidekiq_jobs_total
|
|
53
|
-
|
|
54
52
|
@sidekiq_job_duration_seconds =
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
PrometheusExporter::Metric::Base.default_aggregation.new(
|
|
54
|
+
"sidekiq_job_duration_seconds",
|
|
55
|
+
"Total time spent in sidekiq jobs.",
|
|
56
|
+
)
|
|
57
57
|
|
|
58
58
|
@sidekiq_jobs_total =
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
PrometheusExporter::Metric::Counter.new(
|
|
60
|
+
"sidekiq_jobs_total",
|
|
61
|
+
"Total number of sidekiq jobs executed.",
|
|
62
|
+
)
|
|
61
63
|
|
|
62
64
|
@sidekiq_restarted_jobs_total =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
PrometheusExporter::Metric::Counter.new(
|
|
66
|
+
"sidekiq_restarted_jobs_total",
|
|
67
|
+
"Total number of sidekiq jobs that we restarted because of a sidekiq shutdown.",
|
|
68
|
+
)
|
|
65
69
|
|
|
66
70
|
@sidekiq_failed_jobs_total =
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
PrometheusExporter::Metric::Counter.new(
|
|
72
|
+
"sidekiq_failed_jobs_total",
|
|
73
|
+
"Total number of failed sidekiq jobs.",
|
|
74
|
+
)
|
|
69
75
|
|
|
70
76
|
@sidekiq_dead_jobs_total =
|
|
71
|
-
|
|
72
|
-
|
|
77
|
+
PrometheusExporter::Metric::Counter.new(
|
|
78
|
+
"sidekiq_dead_jobs_total",
|
|
79
|
+
"Total number of dead sidekiq jobs.",
|
|
80
|
+
)
|
|
73
81
|
end
|
|
74
82
|
end
|
|
75
83
|
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PrometheusExporter::Server
|
|
4
|
+
class SidekiqProcessCollector < PrometheusExporter::Server::TypeCollector
|
|
5
|
+
MAX_METRIC_AGE = 60
|
|
6
|
+
|
|
7
|
+
SIDEKIQ_PROCESS_GAUGES = {
|
|
8
|
+
"busy" => "Number of running jobs",
|
|
9
|
+
"concurrency" => "Maximum concurrency",
|
|
10
|
+
}.freeze
|
|
11
|
+
|
|
12
|
+
attr_reader :sidekiq_metrics, :gauges
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
@sidekiq_metrics = MetricsContainer.new(ttl: MAX_METRIC_AGE)
|
|
16
|
+
@gauges = {}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def type
|
|
20
|
+
"sidekiq_process"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def metrics
|
|
24
|
+
SIDEKIQ_PROCESS_GAUGES.each_key { |name| gauges[name]&.reset! }
|
|
25
|
+
|
|
26
|
+
sidekiq_metrics.map do |metric|
|
|
27
|
+
labels = metric.fetch("labels", {})
|
|
28
|
+
SIDEKIQ_PROCESS_GAUGES.map do |name, help|
|
|
29
|
+
if (value = metric[name])
|
|
30
|
+
gauge =
|
|
31
|
+
gauges[name] ||= PrometheusExporter::Metric::Gauge.new(
|
|
32
|
+
"sidekiq_process_#{name}",
|
|
33
|
+
help,
|
|
34
|
+
)
|
|
35
|
+
gauge.observe(value, labels)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
gauges.values
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def collect(object)
|
|
44
|
+
@sidekiq_metrics << object["process"]
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -1,30 +1,33 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
module PrometheusExporter::Server
|
|
3
3
|
class SidekiqQueueCollector < TypeCollector
|
|
4
|
-
|
|
4
|
+
MAX_METRIC_AGE = 60
|
|
5
5
|
|
|
6
6
|
SIDEKIQ_QUEUE_GAUGES = {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
"backlog" => "Size of the sidekiq queue.",
|
|
8
|
+
"latency_seconds" => "Latency of the sidekiq queue.",
|
|
9
9
|
}.freeze
|
|
10
10
|
|
|
11
11
|
attr_reader :sidekiq_metrics, :gauges
|
|
12
12
|
|
|
13
13
|
def initialize
|
|
14
|
-
@sidekiq_metrics =
|
|
14
|
+
@sidekiq_metrics = MetricsContainer.new(ttl: MAX_METRIC_AGE)
|
|
15
15
|
@gauges = {}
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def type
|
|
19
|
-
|
|
19
|
+
"sidekiq_queue"
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def metrics
|
|
23
|
+
SIDEKIQ_QUEUE_GAUGES.each_key { |name| gauges[name]&.reset! }
|
|
24
|
+
|
|
23
25
|
sidekiq_metrics.map do |metric|
|
|
24
26
|
labels = metric.fetch("labels", {})
|
|
25
27
|
SIDEKIQ_QUEUE_GAUGES.map do |name, help|
|
|
26
28
|
if (value = metric[name])
|
|
27
|
-
gauge =
|
|
29
|
+
gauge =
|
|
30
|
+
gauges[name] ||= PrometheusExporter::Metric::Gauge.new("sidekiq_queue_#{name}", help)
|
|
28
31
|
gauge.observe(value, labels)
|
|
29
32
|
end
|
|
30
33
|
end
|
|
@@ -34,12 +37,9 @@ module PrometheusExporter::Server
|
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
def collect(object)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
40
|
+
object["queues"].each do |queue|
|
|
41
|
+
queue["labels"].merge!(object["custom_labels"]) if object["custom_labels"]
|
|
42
|
+
@sidekiq_metrics << queue
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
end
|