prometheus_exporter 0.1.9 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
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