prometheus_exporter 0.1.9 → 0.1.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 86a92ab30771272b941d1d453d9a48ec06b77f614ec966490702c270b90e369b
4
- data.tar.gz: c606f0aacbcd0d79607ae3ea7f4bbe63b2632c4c431a8f9d19a86d8b072a8543
3
+ metadata.gz: '0670768fb402bef5d0e563cf3fb0a8299637f03f975f73ed7bf58ee8571bb682'
4
+ data.tar.gz: 1db696d86b7de07df16fd2abd3b35cc44d0d19e041d98cd6dc6738f245eccea4
5
5
  SHA512:
6
- metadata.gz: 58ec62718537d203ebb9cfa2b2f52ce02ffd878c15845d4fba8a5f0e9c505719b5567af123d075f8e88ff6afed7efdff282178a67a552a335255376cf5799ecd
7
- data.tar.gz: 2058b506f5485c86033a9534642a8740852dd351dc43a04cb5eb10fb78921bb7dc85a74505d0830b0c4d7b1abcc722ababcc0d3a2c20f6307ed608af9a38f706
6
+ metadata.gz: 062d0dbedc25eb1f4c267f434b4f4f1a76b9a70c3c1b0eb8d8c4d44afe63003737152afff75af41099a7e48b81c8c6206e9ace60cd26f92a8a3664030dfd13ee
7
+ data.tar.gz: 1a2afb4920a3cd2d15214b1b212d7828e62b022a804fba37fb1a8797a6ca93c6c90da8333524474e2dc32271e1a8a1abbb4e554be40d5df52c1ec4d65e723d7b
@@ -8,8 +8,10 @@ require_relative "./../lib/prometheus_exporter/server"
8
8
  def run
9
9
  port = PrometheusExporter::DEFAULT_PORT
10
10
  prefix = "ruby_"
11
- collector = nil
11
+ collector_filename = nil
12
12
  verbose = false
13
+ type_collectors = []
14
+ collector_class = PrometheusExporter::Server::Collector
13
15
 
14
16
  OptionParser.new do |opt|
15
17
  opt.on('-p',
@@ -21,8 +23,11 @@ def run
21
23
  opt.on('--prefix METRIC_PREFIX', String, "Prefix to apply to all metrics (default: #{prefix})") do |o|
22
24
  prefix = o.to_s
23
25
  end
24
- opt.on('-c', '--collector CUSTOM_COLLECTOR', String, "(optional) Custom collector to run") do |o|
25
- collector = o.to_s
26
+ opt.on('-c', '--collector FILE', String, "(optional) Custom collector to run") do |o|
27
+ collector_filename = o.to_s
28
+ end
29
+ opt.on('-a', '--type-collector FILE', String, "(optional) Custom type collectors to run in main collector") do |o|
30
+ type_collectors << o
26
31
  end
27
32
  opt.on('-v', '--verbose') do |o|
28
33
  verbose = true
@@ -32,24 +37,42 @@ def run
32
37
 
33
38
  PrometheusExporter::Metric::Base.default_prefix = prefix
34
39
 
35
- if collector
36
- eval File.read(collector)
40
+ if collector_filename
41
+ eval File.read(collector_filename)
42
+
43
+ found = false
37
44
 
38
45
  ObjectSpace.each_object(Class) do |klass|
39
46
  if klass < PrometheusExporter::Server::CollectorBase
40
- collector = klass
47
+ collector_class = klass
48
+ found = true
41
49
  end
42
50
  end
43
51
 
44
- if !collector
45
- STDERR.puts "Can not find a class inheriting off PrometheusExporter::Server::Collector"
52
+ if !found
53
+ STDERR.puts "Can not find a class inheriting off PrometheusExporter::Server::CollectorBase"
46
54
  usage
47
55
  exit 1
48
56
  end
49
57
  end
50
58
 
59
+ collector = collector_class.new
60
+
61
+ if type_collectors.length > 0
62
+ type_collectors.each do |t|
63
+ eval File.read(t)
64
+ end
65
+
66
+ ObjectSpace.each_object(Class) do |klass|
67
+ if klass < PrometheusExporter::Server::TypeCollector
68
+ collector.register_collector klass.new
69
+ STDERR.puts "Registered TypeCollector: #{klass}" if verbose
70
+ end
71
+ end
72
+ end
73
+
51
74
  puts "#{Time.now} Starting prometheus exporter on port #{port}"
52
- server = PrometheusExporter::Server::WebServer.new port: port, collector: collector&.new, verbose: verbose
75
+ server = PrometheusExporter::Server::WebServer.new port: port, collector: collector, verbose: verbose
53
76
  server.start
54
77
  sleep
55
78
 
@@ -1,3 +1,7 @@
1
+ require_relative "server/type_collector"
2
+ require_relative "server/web_collector"
3
+ require_relative "server/process_collector"
4
+ require_relative "server/sidekiq_collector"
1
5
  require_relative "server/collector_base"
2
6
  require_relative "server/collector"
3
7
  require_relative "server/web_server"
@@ -23,19 +23,22 @@ module PrometheusExporter::Server
23
23
  def initialize
24
24
  @process_metrics = []
25
25
  @metrics = {}
26
- @buffer = []
27
26
  @mutex = Mutex.new
27
+ @collectors = {}
28
+ register_collector(WebCollector.new)
29
+ register_collector(ProcessCollector.new)
30
+ register_collector(SidekiqCollector.new)
31
+ end
32
+
33
+ def register_collector(collector)
34
+ @collectors[collector.type] = collector
28
35
  end
29
36
 
30
37
  def process(str)
31
38
  obj = JSON.parse(str)
32
39
  @mutex.synchronize do
33
- if obj["type"] == "web"
34
- observe_web(obj)
35
- elsif obj["type"] == "process"
36
- observe_process(obj)
37
- elsif obj["type"] == "sidekiq"
38
- observe_sidekiq(obj)
40
+ if collector = @collectors[obj["type"]]
41
+ collector.observe(obj)
39
42
  else
40
43
  metric = @metrics[obj["name"]]
41
44
  if !metric
@@ -48,132 +51,13 @@ module PrometheusExporter::Server
48
51
 
49
52
  def prometheus_metrics_text
50
53
  @mutex.synchronize do
51
- val = @metrics.values.map(&:to_prometheus_text).join("\n")
52
-
53
- metrics = {}
54
-
55
- if @process_metrics.length > 0
56
- val << "\n"
57
-
58
- @process_metrics.map do |m|
59
- metric_key = { pid: m["pid"], type: m["process_type"] }
60
-
61
- PROCESS_GAUGES.map do |k, help|
62
- k = k.to_s
63
- if v = m[k]
64
- g = metrics[k] ||= PrometheusExporter::Metric::Gauge.new(k, help)
65
- g.observe(v, metric_key)
66
- end
67
- end
68
-
69
- PROCESS_COUNTERS.map do |k, help|
70
- k = k.to_s
71
- if v = m[k]
72
- c = metrics[k] ||= PrometheusExporter::Metric::Counter.new(k, help)
73
- c.observe(v, metric_key)
74
- end
75
- end
76
-
77
- end
78
-
79
- val << metrics.values.map(&:to_prometheus_text).join("\n")
80
- end
81
-
82
- val
54
+ (@metrics.values + @collectors.values.map(&:metrics).flatten)
55
+ .map(&:to_prometheus_text).join("\n")
83
56
  end
84
57
  end
85
58
 
86
59
  protected
87
60
 
88
- def register_metric(metric)
89
- @mutex.synchronize do
90
- @metrics << metric
91
- end
92
- end
93
-
94
- def ensure_web_metrics
95
- unless @http_requests
96
- @metrics["http_requests"] = @http_requests = PrometheusExporter::Metric::Counter.new(
97
- "http_requests",
98
- "Total HTTP requests from web app"
99
- )
100
-
101
- @metrics["http_duration_seconds"] = @http_duration_seconds = PrometheusExporter::Metric::Summary.new(
102
- "http_duration_seconds",
103
- "Time spent in HTTP reqs in seconds"
104
- )
105
-
106
- @metrics["http_redis_duration_seconds"] = @http_redis_duration_seconds = PrometheusExporter::Metric::Summary.new(
107
- "http_redis_duration_seconds",
108
- "Time spent in HTTP reqs in redis seconds"
109
- )
110
-
111
- @metrics["http_sql_duration_seconds"] = @http_sql_duration_seconds = PrometheusExporter::Metric::Summary.new(
112
- "http_sql_duration_seconds",
113
- "Time spent in HTTP reqs in SQL in seconds"
114
- )
115
- end
116
- end
117
-
118
- def observe_web(obj)
119
- ensure_web_metrics
120
-
121
- labels = {
122
- controller: obj["controller"] || "other",
123
- action: obj["action"] || "other"
124
- }
125
-
126
- @http_requests.observe(1, labels.merge(status: obj["status"]))
127
-
128
- if timings = obj["timings"]
129
- @http_duration_seconds.observe(timings["total_duration"], labels)
130
- if redis = timings["redis"]
131
- @http_redis_duration_seconds.observe(redis["duration"], labels)
132
- end
133
- if sql = timings["sql"]
134
- @http_sql_duration_seconds.observe(sql["duration"], labels)
135
- end
136
- end
137
- end
138
-
139
- def observe_process(obj)
140
- now = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
141
-
142
- obj["created_at"] = now
143
-
144
- @process_metrics.delete_if do |current|
145
- obj["pid"] == current["pid"] || (current["created_at"] + MAX_PROCESS_METRIC_AGE < now)
146
- end
147
- @process_metrics << obj
148
- end
149
-
150
- def observe_sidekiq(obj)
151
- ensure_sidekiq_metrics
152
- @sidekiq_job_duration_seconds.observe(obj["duration"], job_name: obj["name"])
153
- @sidekiq_job_count.observe(1, job_name: obj["name"])
154
- @sidekiq_failed_job_count.observe(1, job_name: obj["name"]) if !obj["success"]
155
- end
156
-
157
- def ensure_sidekiq_metrics
158
- if !@sidekiq_job_count
159
-
160
- @metrics["sidekiq_job_duration_seconds"] =
161
- @sidekiq_job_duration_seconds =
162
- PrometheusExporter::Metric::Counter.new(
163
- "sidekiq_job_duration_seconds", "Total time spent in sidekiq jobs")
164
-
165
- @metrics["sidekiq_job_count"] =
166
- @sidekiq_job_count =
167
- PrometheusExporter::Metric::Counter.new(
168
- "sidekiq_job_count", "Total number of sidekiq jobs executed")
169
-
170
- @metrics["sidekiq_failed_job_count"] =
171
- @sidekiq_failed_job_count =
172
- PrometheusExporter::Metric::Counter.new(
173
- "sidekiq_failed_job_count", "Total number failed sidekiq jobs executed")
174
- end
175
- end
176
-
177
61
  def register_metric_unsafe(obj)
178
62
  name = obj["name"]
179
63
  help = obj["help"]
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrometheusExporter::Server
4
+
5
+ class ProcessCollector < TypeCollector
6
+ MAX_PROCESS_METRIC_AGE = 60
7
+ PROCESS_GAUGES = {
8
+ heap_free_slots: "Free ruby heap slots",
9
+ heap_live_slots: "Used ruby heap slots",
10
+ v8_heap_size: "Total JavaScript V8 heap size (bytes)",
11
+ v8_used_heap_size: "Total used JavaScript V8 heap size (bytes)",
12
+ v8_physical_size: "Physical size consumed by V8 heaps",
13
+ v8_heap_count: "Number of V8 contexts running",
14
+ rss: "Total RSS used by process",
15
+ }
16
+
17
+ PROCESS_COUNTERS = {
18
+ major_gc_count: "Major GC operations by process",
19
+ minor_gc_count: "Minor GC operations by process",
20
+ total_allocated_objects: "Total number of allocateds objects by process",
21
+ }
22
+
23
+ def initialize
24
+ @process_metrics = []
25
+ end
26
+
27
+ def type
28
+ "process"
29
+ end
30
+
31
+ def metrics
32
+ return [] if @process_metrics.length == 0
33
+
34
+ metrics = {}
35
+
36
+ @process_metrics.map do |m|
37
+ metric_key = { pid: m["pid"], type: m["process_type"] }
38
+
39
+ PROCESS_GAUGES.map do |k, help|
40
+ k = k.to_s
41
+ if v = m[k]
42
+ g = metrics[k] ||= PrometheusExporter::Metric::Gauge.new(k, help)
43
+ g.observe(v, metric_key)
44
+ end
45
+ end
46
+
47
+ PROCESS_COUNTERS.map do |k, help|
48
+ k = k.to_s
49
+ if v = m[k]
50
+ c = metrics[k] ||= PrometheusExporter::Metric::Counter.new(k, help)
51
+ c.observe(v, metric_key)
52
+ end
53
+ end
54
+ end
55
+
56
+ metrics.values
57
+ end
58
+
59
+ def observe(obj)
60
+ now = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
61
+
62
+ obj["created_at"] = now
63
+
64
+ @process_metrics.delete_if do |current|
65
+ obj["pid"] == current["pid"] || (current["created_at"] + MAX_PROCESS_METRIC_AGE < now)
66
+ end
67
+ @process_metrics << obj
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,42 @@
1
+ module PrometheusExporter::Server
2
+ class SidekiqCollector < TypeCollector
3
+
4
+ def type
5
+ "sidekiq"
6
+ end
7
+
8
+ def observe(obj)
9
+ ensure_sidekiq_metrics
10
+ @sidekiq_job_duration_seconds.observe(obj["duration"], job_name: obj["name"])
11
+ @sidekiq_job_count.observe(1, job_name: obj["name"])
12
+ @sidekiq_failed_job_count.observe(1, job_name: obj["name"]) if !obj["success"]
13
+ end
14
+
15
+ def metrics
16
+ if @sidekiq_job_count
17
+ [@sidekiq_job_duration_seconds, @sidekiq_job_count, @sidekiq_failed_job_count]
18
+ else
19
+ []
20
+ end
21
+ end
22
+
23
+ protected
24
+
25
+ def ensure_sidekiq_metrics
26
+ if !@sidekiq_job_count
27
+
28
+ @sidekiq_job_duration_seconds =
29
+ PrometheusExporter::Metric::Counter.new(
30
+ "sidekiq_job_duration_seconds", "Total time spent in sidekiq jobs")
31
+
32
+ @sidekiq_job_count =
33
+ PrometheusExporter::Metric::Counter.new(
34
+ "sidekiq_job_count", "Total number of sidekiq jobs executed")
35
+
36
+ @sidekiq_failed_job_count =
37
+ PrometheusExporter::Metric::Counter.new(
38
+ "sidekiq_failed_job_count", "Total number failed sidekiq jobs executed")
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ module PrometheusExporter::Server
2
+ class TypeCollector
3
+ def type
4
+ raise "must implement type"
5
+ end
6
+
7
+ def collect(obj)
8
+ raise "must implement collect"
9
+ end
10
+
11
+ def metrics
12
+ raise "must implement metrics"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrometheusExporter::Server
4
+ class WebCollector < TypeCollector
5
+ def initialize
6
+ @metrics = {}
7
+ end
8
+
9
+ def type
10
+ "web"
11
+ end
12
+
13
+ def collect(obj)
14
+ ensure_metrics
15
+ observe(obj)
16
+ end
17
+
18
+ def metrics
19
+ @metrics.values
20
+ end
21
+
22
+ protected
23
+
24
+ def ensure_metrics
25
+ unless @http_requests
26
+ @metrics["http_requests"] = @http_requests = PrometheusExporter::Metric::Counter.new(
27
+ "http_requests",
28
+ "Total HTTP requests from web app"
29
+ )
30
+
31
+ @metrics["http_duration_seconds"] = @http_duration_seconds = PrometheusExporter::Metric::Summary.new(
32
+ "http_duration_seconds",
33
+ "Time spent in HTTP reqs in seconds"
34
+ )
35
+
36
+ @metrics["http_redis_duration_seconds"] = @http_redis_duration_seconds = PrometheusExporter::Metric::Summary.new(
37
+ "http_redis_duration_seconds",
38
+ "Time spent in HTTP reqs in redis seconds"
39
+ )
40
+
41
+ @metrics["http_sql_duration_seconds"] = @http_sql_duration_seconds = PrometheusExporter::Metric::Summary.new(
42
+ "http_sql_duration_seconds",
43
+ "Time spent in HTTP reqs in SQL in seconds"
44
+ )
45
+ end
46
+ end
47
+
48
+ def observe(obj)
49
+
50
+ labels = {
51
+ controller: obj["controller"] || "other",
52
+ action: obj["action"] || "other"
53
+ }
54
+
55
+ @http_requests.observe(1, labels.merge(status: obj["status"]))
56
+
57
+ if timings = obj["timings"]
58
+ @http_duration_seconds.observe(timings["total_duration"], labels)
59
+ if redis = timings["redis"]
60
+ @http_redis_duration_seconds.observe(redis["duration"], labels)
61
+ end
62
+ if sql = timings["sql"]
63
+ @http_sql_duration_seconds.observe(sql["duration"], labels)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -1,3 +1,3 @@
1
1
  module PrometheusExporter
2
- VERSION = "0.1.9"
2
+ VERSION = "0.1.10"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prometheus_exporter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
@@ -130,6 +130,10 @@ files:
130
130
  - lib/prometheus_exporter/server.rb
131
131
  - lib/prometheus_exporter/server/collector.rb
132
132
  - lib/prometheus_exporter/server/collector_base.rb
133
+ - lib/prometheus_exporter/server/process_collector.rb
134
+ - lib/prometheus_exporter/server/sidekiq_collector.rb
135
+ - lib/prometheus_exporter/server/type_collector.rb
136
+ - lib/prometheus_exporter/server/web_collector.rb
133
137
  - lib/prometheus_exporter/server/web_server.rb
134
138
  - lib/prometheus_exporter/version.rb
135
139
  - prometheus_exporter.gemspec