prometheus_exporter 0.4.3 → 0.4.4

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: e93d3054e02dcc5bc4dc87df3be0b87ce3715850d4d116465f31ee525bb9c9f6
4
- data.tar.gz: 681a91ab3490d12b095b5bde5a9eb303202e5c6b688cf57afe38752e49b2d9d4
3
+ metadata.gz: b60596255e84ca5aedae095d4ae7dda21f1c324e49a495e73e5f8e8a6adb3472
4
+ data.tar.gz: 990f03708492b5a2b5d13cf6a9bf67e091bdf62c819b1a559a0a240e6d9660bc
5
5
  SHA512:
6
- metadata.gz: b4b875a1d7799aab1ec0c6ec69570a070a730774cd58cd7a61e54d19bf4f327ddf0f47e6fa10e33084b86fbdcbd407a0e0e715bb190f9bf412b59ce17b9963dd
7
- data.tar.gz: 1face6bafbf0da750d2b88f3d5ed010cb136fad3da776928f7a327db20cc81fd972208f7cbfeb298dd72492489a8838c76429cbe448b87d478dfff79292c2f00
6
+ metadata.gz: d914be65e9857dcf5173e03a8fd230d0a2004aea8cf454fd1671229c856730ee72a9793624eddcf01ee561768d228e9e2e06eddd1a72629726d1dc994f34614b
7
+ data.tar.gz: 6a05a048eaa75641b749761ed823be1aa694e83d3c2f0d35e860e9237dd0f82569dc31c4c3d0e24293b10d1dcd5d36f16d893348c620f21efae9c16596b29b3c
data/README.md CHANGED
@@ -56,10 +56,20 @@ Simplest way of consuming Prometheus exporter is in a single process mode.
56
56
  ```ruby
57
57
  require 'prometheus_exporter/server'
58
58
 
59
+ # client allows instrumentation to send info to server
60
+ require 'prometheus_exporter/client'
61
+ require 'prometheus_exporter/instrumentation'
62
+
59
63
  # port is the port that will provide the /metrics route
60
64
  server = PrometheusExporter::Server::WebServer.new port: 12345
61
65
  server.start
62
66
 
67
+ # wire up a default local client
68
+ PrometheusExporter::Client.default = PrometheusExporter::LocalClient.new(collector: server.collector)
69
+
70
+ # this ensures basic process instrumentation metrics are added such as RSS and Ruby metrics
71
+ PrometheusExporter::Instrumentation::Process.start
72
+
63
73
  gauge = PrometheusExporter::Metric::Gauge.new("rss", "used RSS for process")
64
74
  counter = PrometheusExporter::Metric::Counter.new("web_requests", "number of web requests")
65
75
  summary = PrometheusExporter::Metric::Summary.new("page_load_time", "time it took to load page")
@@ -3,197 +3,213 @@
3
3
  require 'socket'
4
4
  require 'thread'
5
5
 
6
- class PrometheusExporter::Client
6
+ module PrometheusExporter
7
+
8
+ class Client
9
+ class RemoteMetric
10
+ def initialize(name:, help:, type:, client:)
11
+ @name = name
12
+ @help = help
13
+ @client = client
14
+ @type = type
15
+ end
7
16
 
8
- class RemoteMetric
9
- def initialize(name:, help:, type:, client:)
10
- @name = name
11
- @help = help
12
- @client = client
13
- @type = type
14
- end
17
+ def standard_values(value, keys, prometheus_exporter_action = nil)
18
+ values = {
19
+ type: @type,
20
+ help: @help,
21
+ name: @name,
22
+ keys: keys,
23
+ value: value
24
+ }
25
+ values[:prometheus_exporter_action] = prometheus_exporter_action if prometheus_exporter_action
26
+ values
27
+ end
15
28
 
16
- def standard_values(value, keys, prometheus_exporter_action = nil)
17
- values = {
18
- type: @type,
19
- help: @help,
20
- name: @name,
21
- keys: keys,
22
- value: value
23
- }
24
- values[:prometheus_exporter_action] = prometheus_exporter_action if prometheus_exporter_action
25
- values
26
- end
29
+ def observe(value = 1, keys = nil)
30
+ @client.send_json(standard_values(value, keys))
31
+ end
32
+
33
+ def increment(keys = nil, value = 1)
34
+ @client.send_json(standard_values(value, keys, :increment))
35
+ end
36
+
37
+ def decrement(keys = nil, value = 1)
38
+ @client.send_json(standard_values(value, keys, :decrement))
39
+ end
27
40
 
28
- def observe(value = 1, keys = nil)
29
- @client.send_json(standard_values(value, keys))
30
41
  end
31
42
 
32
- def increment(keys = nil, value = 1)
33
- @client.send_json(standard_values(value, keys, :increment))
43
+ def self.default
44
+ @default ||= new
34
45
  end
35
46
 
36
- def decrement(keys = nil, value = 1)
37
- @client.send_json(standard_values(value, keys, :decrement))
47
+ def self.default=(client)
48
+ @default = client
38
49
  end
39
50
 
40
- end
51
+ MAX_SOCKET_AGE = 25
52
+ MAX_QUEUE_SIZE = 10_000
41
53
 
42
- def self.default
43
- @default ||= new
44
- end
54
+ def initialize(host: 'localhost', port: PrometheusExporter::DEFAULT_PORT, max_queue_size: nil, thread_sleep: 0.5, json_serializer: nil, custom_labels: nil)
55
+ @metrics = []
45
56
 
46
- def self.default=(client)
47
- @default = client
48
- end
57
+ @queue = Queue.new
58
+ @socket = nil
59
+ @socket_started = nil
49
60
 
50
- MAX_SOCKET_AGE = 25
51
- MAX_QUEUE_SIZE = 10_000
61
+ max_queue_size ||= MAX_QUEUE_SIZE
62
+ max_queue_size = max_queue_size.to_i
52
63
 
53
- def initialize(host: 'localhost', port: PrometheusExporter::DEFAULT_PORT, max_queue_size: nil, thread_sleep: 0.5, json_serializer: nil, custom_labels: nil)
54
- @metrics = []
64
+ if max_queue_size.to_i <= 0
65
+ raise ArgumentError, "max_queue_size must be larger than 0"
66
+ end
55
67
 
56
- @queue = Queue.new
57
- @socket = nil
58
- @socket_started = nil
68
+ @max_queue_size = max_queue_size
69
+ @host = host
70
+ @port = port
71
+ @worker_thread = nil
72
+ @mutex = Mutex.new
73
+ @thread_sleep = thread_sleep
59
74
 
60
- max_queue_size ||= MAX_QUEUE_SIZE
61
- max_queue_size = max_queue_size.to_i
75
+ @json_serializer = json_serializer == :oj ? PrometheusExporter::OjCompat : JSON
62
76
 
63
- if max_queue_size.to_i <= 0
64
- raise ArgumentError, "max_queue_size must be larger than 0"
77
+ @custom_labels = custom_labels
65
78
  end
66
79
 
67
- @max_queue_size = max_queue_size
68
- @host = host
69
- @port = port
70
- @worker_thread = nil
71
- @mutex = Mutex.new
72
- @thread_sleep = thread_sleep
73
-
74
- @json_serializer = json_serializer == :oj ? PrometheusExporter::OjCompat : JSON
75
-
76
- @custom_labels = custom_labels
77
- end
78
-
79
- def custom_labels=(custom_labels)
80
- @custom_labels = custom_labels
81
- end
82
-
83
- def register(type, name, help)
84
- metric = RemoteMetric.new(type: type, name: name, help: help, client: self)
85
- @metrics << metric
86
- metric
87
- end
80
+ def custom_labels=(custom_labels)
81
+ @custom_labels = custom_labels
82
+ end
88
83
 
89
- def send_json(obj)
90
- payload = @custom_labels.nil? ? obj : obj.merge(custom_labels: @custom_labels)
91
- send(@json_serializer.dump(payload))
92
- end
84
+ def register(type, name, help)
85
+ metric = RemoteMetric.new(type: type, name: name, help: help, client: self)
86
+ @metrics << metric
87
+ metric
88
+ end
93
89
 
94
- def send(str)
95
- @queue << str
96
- if @queue.length > @max_queue_size
97
- STDERR.puts "Prometheus Exporter client is dropping message cause queue is full"
98
- @queue.pop
90
+ def send_json(obj)
91
+ payload = @custom_labels.nil? ? obj : obj.merge(custom_labels: @custom_labels)
92
+ send(@json_serializer.dump(payload))
99
93
  end
100
94
 
101
- ensure_worker_thread!
102
- end
95
+ def send(str)
96
+ @queue << str
97
+ if @queue.length > @max_queue_size
98
+ STDERR.puts "Prometheus Exporter client is dropping message cause queue is full"
99
+ @queue.pop
100
+ end
103
101
 
104
- def process_queue
105
- while @queue.length > 0
106
- ensure_socket!
102
+ ensure_worker_thread!
103
+ end
107
104
 
108
- begin
109
- message = @queue.pop
110
- @socket.write(message.bytesize.to_s(16).upcase)
111
- @socket.write("\r\n")
112
- @socket.write(message)
113
- @socket.write("\r\n")
114
- rescue => e
115
- STDERR.puts "Prometheus Exporter is dropping a message: #{e}"
116
- @socket = nil
117
- raise
105
+ def process_queue
106
+ while @queue.length > 0
107
+ ensure_socket!
108
+
109
+ begin
110
+ message = @queue.pop
111
+ @socket.write(message.bytesize.to_s(16).upcase)
112
+ @socket.write("\r\n")
113
+ @socket.write(message)
114
+ @socket.write("\r\n")
115
+ rescue => e
116
+ STDERR.puts "Prometheus Exporter is dropping a message: #{e}"
117
+ @socket = nil
118
+ raise
119
+ end
118
120
  end
119
121
  end
120
- end
121
122
 
122
- def stop
123
- @mutex.synchronize do
124
- @worker_thread&.kill
125
- while @worker_thread.alive?
126
- sleep 0.001
123
+ def stop
124
+ @mutex.synchronize do
125
+ @worker_thread&.kill
126
+ while @worker_thread.alive?
127
+ sleep 0.001
128
+ end
129
+ @worker_thread = nil
127
130
  end
128
- @worker_thread = nil
129
- end
130
131
 
131
- close_socket!
132
- end
132
+ close_socket!
133
+ end
133
134
 
134
- private
135
+ private
135
136
 
136
- def worker_loop
137
- close_socket_if_old!
138
- process_queue
139
- rescue => e
140
- STDERR.puts "Prometheus Exporter, failed to send message #{e}"
141
- end
137
+ def worker_loop
138
+ close_socket_if_old!
139
+ process_queue
140
+ rescue => e
141
+ STDERR.puts "Prometheus Exporter, failed to send message #{e}"
142
+ end
142
143
 
143
- def ensure_worker_thread!
144
- unless @worker_thread&.alive?
145
- @mutex.synchronize do
146
- return if @worker_thread&.alive?
144
+ def ensure_worker_thread!
145
+ unless @worker_thread&.alive?
146
+ @mutex.synchronize do
147
+ return if @worker_thread&.alive?
147
148
 
148
- @worker_thread = Thread.new do
149
- while true
150
- worker_loop
151
- sleep @thread_sleep
149
+ @worker_thread = Thread.new do
150
+ while true
151
+ worker_loop
152
+ sleep @thread_sleep
153
+ end
152
154
  end
153
155
  end
154
156
  end
155
157
  end
156
- end
157
158
 
158
- def close_socket!
159
- begin
160
- if @socket
161
- @socket.write("0\r\n")
159
+ def close_socket!
160
+ begin
161
+ if @socket
162
+ @socket.write("0\r\n")
163
+ @socket.write("\r\n")
164
+ @socket.flush
165
+ @socket.close
166
+ end
167
+ rescue Errno::EPIPE
168
+ end
169
+
170
+ @socket = nil
171
+ @socket_started = nil
172
+ end
173
+
174
+ def close_socket_if_old!
175
+ if @socket && ((@socket_started + MAX_SOCKET_AGE) < Time.now.to_f)
176
+ close_socket!
177
+ end
178
+ end
179
+
180
+ def ensure_socket!
181
+ close_socket_if_old!
182
+ if !@socket
183
+ @socket = TCPSocket.new @host, @port
184
+ @socket.write("POST /send-metrics HTTP/1.1\r\n")
185
+ @socket.write("Transfer-Encoding: chunked\r\n")
186
+ @socket.write("Host: #{@host}\r\n")
187
+ @socket.write("Connection: Close\r\n")
188
+ @socket.write("Content-Type: application/octet-stream\r\n")
162
189
  @socket.write("\r\n")
163
- @socket.flush
164
- @socket.close
190
+ @socket_started = Time.now.to_f
165
191
  end
166
- rescue Errno::EPIPE
192
+
193
+ nil
194
+ rescue
195
+ @socket = nil
196
+ @socket_started = nil
197
+ raise
167
198
  end
168
199
 
169
- @socket = nil
170
- @socket_started = nil
171
200
  end
172
201
 
173
- def close_socket_if_old!
174
- if @socket && ((@socket_started + MAX_SOCKET_AGE) < Time.now.to_f)
175
- close_socket!
202
+ class LocalClient < Client
203
+ attr_reader :collector
204
+
205
+ def initialize(collector:, json_serializer: nil, custom_labels: nil)
206
+ @collector = collector
207
+ super(json_serializer: json_serializer, custom_labels: custom_labels)
176
208
  end
177
- end
178
209
 
179
- def ensure_socket!
180
- close_socket_if_old!
181
- if !@socket
182
- @socket = TCPSocket.new @host, @port
183
- @socket.write("POST /send-metrics HTTP/1.1\r\n")
184
- @socket.write("Transfer-Encoding: chunked\r\n")
185
- @socket.write("Host: #{@host}\r\n")
186
- @socket.write("Connection: Close\r\n")
187
- @socket.write("Content-Type: application/octet-stream\r\n")
188
- @socket.write("\r\n")
189
- @socket_started = Time.now.to_f
190
- end
191
-
192
- nil
193
- rescue
194
- @socket = nil
195
- @socket_started = nil
196
- raise
210
+ def send(json)
211
+ @collector.process(json)
212
+ end
197
213
  end
198
214
 
199
215
  end
@@ -1,10 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # collects stats from currently running process
2
4
  module PrometheusExporter::Instrumentation
3
5
  class Process
4
6
  def self.start(client: nil, type: "ruby", frequency: 30)
5
7
  process_collector = new(type)
6
8
  client ||= PrometheusExporter::Client.default
7
- Thread.new do
9
+
10
+ stop if @thread
11
+
12
+ @thread = Thread.new do
8
13
  while true
9
14
  begin
10
15
  metric = process_collector.collect
@@ -18,6 +23,13 @@ module PrometheusExporter::Instrumentation
18
23
  end
19
24
  end
20
25
 
26
+ def self.stop
27
+ if t = @thread
28
+ t.kill
29
+ @thread = nil
30
+ end
31
+ end
32
+
21
33
  def initialize(type)
22
34
  @type = type
23
35
  end
@@ -2,6 +2,5 @@ require_relative "instrumentation/process"
2
2
  require_relative "instrumentation/method_profiler"
3
3
  require_relative "instrumentation/sidekiq"
4
4
  require_relative "instrumentation/delayed_job"
5
- require_relative "instrumentation/global"
6
5
  require_relative "instrumentation/puma"
7
6
  require_relative "instrumentation/hutch"
@@ -3,22 +3,6 @@
3
3
  module PrometheusExporter::Server
4
4
 
5
5
  class Collector < CollectorBase
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_ops_total: "Major GC operations by process.",
19
- minor_gc_ops_total: "Minor GC operations by process.",
20
- allocated_objects_total: "Total number of allocated objects by process.",
21
- }
22
6
 
23
7
  def initialize(json_serializer: nil)
24
8
  @process_metrics = []
@@ -39,7 +23,10 @@ module PrometheusExporter::Server
39
23
  end
40
24
 
41
25
  def process(str)
42
- obj = @json_serializer.parse(str)
26
+ process_hash(@json_serializer.parse(str))
27
+ end
28
+
29
+ def process_hash(obj)
43
30
  @mutex.synchronize do
44
31
  if collector = @collectors[obj["type"]]
45
32
  collector.collect(obj)
@@ -1,3 +1,3 @@
1
1
  module PrometheusExporter
2
- VERSION = "0.4.3"
2
+ VERSION = "0.4.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prometheus_exporter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-11 00:00:00.000000000 Z
11
+ date: 2019-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -162,7 +162,6 @@ files:
162
162
  - lib/prometheus_exporter/client.rb
163
163
  - lib/prometheus_exporter/instrumentation.rb
164
164
  - lib/prometheus_exporter/instrumentation/delayed_job.rb
165
- - lib/prometheus_exporter/instrumentation/global.rb
166
165
  - lib/prometheus_exporter/instrumentation/hutch.rb
167
166
  - lib/prometheus_exporter/instrumentation/method_profiler.rb
168
167
  - lib/prometheus_exporter/instrumentation/process.rb
File without changes