prometheus-client-mmap 0.17.0 → 0.19.1
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/README.md +22 -10
- data/ext/fast_mmaped_file/mmap.c +9 -0
- data/lib/prometheus/client/push.rb +120 -12
- data/lib/prometheus/client/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1696ef06da9827e278d689a18f5f2accbdbb7ef1c893de81b538acb75c141af
|
4
|
+
data.tar.gz: 7bc559ef0cf4913378ab3cea8661013584d5dd4bc136d4d12adedd7e4884cfc6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aead55eab5d73783daf0b4d831ab85b046f057a21b0f3becf7556276d1a9a0e9ad051ef777c11a1ff07bf3bc452c3958b33b53e23b2695a1d3389bfecb1a679a
|
7
|
+
data.tar.gz: 37273dce63fa8b8b9ab4b07381dfd59da1ce3ff902a463a20c3629888f6f591cfe04120bbd4ba03d87bcecee08adb3ffba8fa1255d7219ee3718b3c81773fe8c
|
data/README.md
CHANGED
@@ -68,29 +68,41 @@ integrated [example application](examples/rack/README.md).
|
|
68
68
|
The Ruby client can also be used to push its collected metrics to a
|
69
69
|
[Pushgateway][8]. This comes in handy with batch jobs or in other scenarios
|
70
70
|
where it's not possible or feasible to let a Prometheus server scrape a Ruby
|
71
|
-
process.
|
71
|
+
process. TLS and HTTP basic authentication are supported.
|
72
72
|
|
73
73
|
```ruby
|
74
74
|
require 'prometheus/client'
|
75
75
|
require 'prometheus/client/push'
|
76
76
|
|
77
|
-
|
77
|
+
registry = Prometheus::Client.registry
|
78
78
|
# ... register some metrics, set/increment/observe/etc. their values
|
79
79
|
|
80
80
|
# push the registry state to the default gateway
|
81
|
-
Prometheus::Client::Push.new('my-batch-job').add(
|
81
|
+
Prometheus::Client::Push.new(job: 'my-batch-job').add(registry)
|
82
82
|
|
83
|
-
# optional: specify
|
83
|
+
# optional: specify a grouping key that uniquely identifies a job instance, and gateway.
|
84
|
+
#
|
85
|
+
# Note: the labels you use in the grouping key must not conflict with labels set on the
|
86
|
+
# metrics being pushed. If they do, an error will be raised.
|
84
87
|
Prometheus::Client::Push.new(
|
85
|
-
'my-job',
|
88
|
+
job: 'my-batch-job',
|
89
|
+
gateway: 'https://example.domain:1234',
|
90
|
+
grouping_key: { instance: 'some-instance', extra_key: 'foobar' }
|
91
|
+
).add(registry)
|
86
92
|
|
87
|
-
# If you want to replace any previously pushed metrics for a given
|
93
|
+
# If you want to replace any previously pushed metrics for a given grouping key,
|
88
94
|
# use the #replace method.
|
89
|
-
|
90
|
-
|
91
|
-
#
|
95
|
+
#
|
96
|
+
# Unlike #add, this will completely replace the metrics under the specified grouping key
|
97
|
+
# (i.e. anything currently present in the pushgateway for the specified grouping key, but
|
98
|
+
# not present in the registry for that grouping key will be removed).
|
99
|
+
#
|
100
|
+
# See https://github.com/prometheus/pushgateway#put-method for a full explanation.
|
101
|
+
Prometheus::Client::Push.new(job: 'my-batch-job').replace(registry)
|
102
|
+
|
103
|
+
# If you want to delete all previously pushed metrics for a given grouping key,
|
92
104
|
# use the #delete method.
|
93
|
-
Prometheus::Client::Push.new('my-batch-job'
|
105
|
+
Prometheus::Client::Push.new(job: 'my-batch-job').delete
|
94
106
|
```
|
95
107
|
|
96
108
|
## Metrics
|
data/ext/fast_mmaped_file/mmap.c
CHANGED
@@ -409,6 +409,15 @@ VALUE mm_unmap(VALUE obj) {
|
|
409
409
|
}
|
410
410
|
free(i_mm->t->path);
|
411
411
|
}
|
412
|
+
|
413
|
+
// Ensure any lingering RString values get a length of zero. We
|
414
|
+
// can't zero out the address since GET_MMAP() inside
|
415
|
+
// mm_update_obj_i() expects a non-null address and path.
|
416
|
+
i_mm->t->len = 0;
|
417
|
+
i_mm->t->real = 0;
|
418
|
+
mm_update(obj);
|
419
|
+
|
420
|
+
i_mm->t->addr = NULL;
|
412
421
|
i_mm->t->path = NULL;
|
413
422
|
}
|
414
423
|
|
@@ -1,12 +1,15 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
+
require 'base64'
|
3
4
|
require 'thread'
|
4
5
|
require 'net/http'
|
5
6
|
require 'uri'
|
6
7
|
require 'erb'
|
8
|
+
require 'set'
|
7
9
|
|
8
10
|
require 'prometheus/client'
|
9
11
|
require 'prometheus/client/formats/text'
|
12
|
+
require 'prometheus/client/label_set_validator'
|
10
13
|
|
11
14
|
module Prometheus
|
12
15
|
# Client is a ruby implementation for a Prometheus compatible client.
|
@@ -14,23 +17,31 @@ module Prometheus
|
|
14
17
|
# Push implements a simple way to transmit a given registry to a given
|
15
18
|
# Pushgateway.
|
16
19
|
class Push
|
20
|
+
class HttpError < StandardError; end
|
21
|
+
class HttpRedirectError < HttpError; end
|
22
|
+
class HttpClientError < HttpError; end
|
23
|
+
class HttpServerError < HttpError; end
|
24
|
+
|
17
25
|
DEFAULT_GATEWAY = 'http://localhost:9091'.freeze
|
18
26
|
PATH = '/metrics/job/%s'.freeze
|
19
|
-
INSTANCE_PATH = '/metrics/job/%s/instance/%s'.freeze
|
20
27
|
SUPPORTED_SCHEMES = %w(http https).freeze
|
21
28
|
|
22
|
-
attr_reader :job, :
|
29
|
+
attr_reader :job, :gateway, :path
|
23
30
|
|
24
|
-
def initialize(job:,
|
31
|
+
def initialize(job:, gateway: DEFAULT_GATEWAY, grouping_key: {}, **kwargs)
|
25
32
|
raise ArgumentError, "job cannot be nil" if job.nil?
|
26
33
|
raise ArgumentError, "job cannot be empty" if job.empty?
|
34
|
+
@validator = LabelSetValidator.new()
|
35
|
+
@validator.validate(grouping_key)
|
27
36
|
|
28
37
|
@mutex = Mutex.new
|
29
38
|
@job = job
|
30
|
-
@instance = instance
|
31
39
|
@gateway = gateway || DEFAULT_GATEWAY
|
32
|
-
@
|
40
|
+
@grouping_key = grouping_key
|
41
|
+
@path = build_path(job, grouping_key)
|
42
|
+
|
33
43
|
@uri = parse("#{@gateway}#{@path}")
|
44
|
+
validate_no_basic_auth!(@uri)
|
34
45
|
|
35
46
|
@http = Net::HTTP.new(@uri.host, @uri.port)
|
36
47
|
@http.use_ssl = (@uri.scheme == 'https')
|
@@ -38,6 +49,11 @@ module Prometheus
|
|
38
49
|
@http.read_timeout = kwargs[:read_timeout] if kwargs[:read_timeout]
|
39
50
|
end
|
40
51
|
|
52
|
+
def basic_auth(user, password)
|
53
|
+
@user = user
|
54
|
+
@password = password
|
55
|
+
end
|
56
|
+
|
41
57
|
def add(registry)
|
42
58
|
synchronize do
|
43
59
|
request(Net::HTTP::Post, registry)
|
@@ -70,26 +86,118 @@ module Prometheus
|
|
70
86
|
raise ArgumentError, "#{url} is not a valid URL: #{e}"
|
71
87
|
end
|
72
88
|
|
73
|
-
def build_path(job,
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
89
|
+
def build_path(job, grouping_key)
|
90
|
+
path = format(PATH, ERB::Util::url_encode(job))
|
91
|
+
|
92
|
+
grouping_key.each do |label, value|
|
93
|
+
if value.include?('/')
|
94
|
+
encoded_value = Base64.urlsafe_encode64(value)
|
95
|
+
path += "/#{label}@base64/#{encoded_value}"
|
96
|
+
# While it's valid for the urlsafe_encode64 function to return an
|
97
|
+
# empty string when the input string is empty, it doesn't work for
|
98
|
+
# our specific use case as we're putting the result into a URL path
|
99
|
+
# segment. A double slash (`//`) can be normalised away by HTTP
|
100
|
+
# libraries, proxies, and web servers.
|
101
|
+
#
|
102
|
+
# For empty strings, we use a single padding character (`=`) as the
|
103
|
+
# value.
|
104
|
+
#
|
105
|
+
# See the pushgateway docs for more details:
|
106
|
+
#
|
107
|
+
# https://github.com/prometheus/pushgateway/blob/6393a901f56d4dda62cd0f6ab1f1f07c495b6354/README.md#url
|
108
|
+
elsif value.empty?
|
109
|
+
path += "/#{label}@base64/="
|
110
|
+
else
|
111
|
+
path += "/#{label}/#{ERB::Util::url_encode(value)}"
|
112
|
+
end
|
78
113
|
end
|
114
|
+
|
115
|
+
path
|
79
116
|
end
|
80
117
|
|
81
118
|
def request(req_class, registry = nil)
|
119
|
+
validate_no_label_clashes!(registry) if registry
|
120
|
+
|
82
121
|
req = req_class.new(@uri)
|
83
122
|
req.content_type = Formats::Text::CONTENT_TYPE
|
84
|
-
req.basic_auth(@
|
123
|
+
req.basic_auth(@user, @password) if @user
|
85
124
|
req.body = Formats::Text.marshal(registry) if registry
|
86
125
|
|
87
|
-
@http.request(req)
|
126
|
+
response = @http.request(req)
|
127
|
+
validate_response!(response)
|
128
|
+
|
129
|
+
response
|
88
130
|
end
|
89
131
|
|
90
132
|
def synchronize
|
91
133
|
@mutex.synchronize { yield }
|
92
134
|
end
|
135
|
+
|
136
|
+
def validate_no_basic_auth!(uri)
|
137
|
+
if uri.user || uri.password
|
138
|
+
raise ArgumentError, <<~EOF
|
139
|
+
Setting Basic Auth credentials in the gateway URL is not supported, please call the `basic_auth` method.
|
140
|
+
|
141
|
+
Received username `#{uri.user}` in gateway URL. Instead of passing
|
142
|
+
Basic Auth credentials like this:
|
143
|
+
|
144
|
+
```
|
145
|
+
push = Prometheus::Client::Push.new(job: "my-job", gateway: "http://user:password@localhost:9091")
|
146
|
+
```
|
147
|
+
|
148
|
+
please pass them like this:
|
149
|
+
|
150
|
+
```
|
151
|
+
push = Prometheus::Client::Push.new(job: "my-job", gateway: "http://localhost:9091")
|
152
|
+
push.basic_auth("user", "password")
|
153
|
+
```
|
154
|
+
|
155
|
+
While URLs do support passing Basic Auth credentials using the
|
156
|
+
`http://user:password@example.com/` syntax, the username and
|
157
|
+
password in that syntax have to follow the usual rules for URL
|
158
|
+
encoding of characters per RFC 3986
|
159
|
+
(https://datatracker.ietf.org/doc/html/rfc3986#section-2.1).
|
160
|
+
|
161
|
+
Rather than place the burden of correctly performing that encoding
|
162
|
+
on users of this gem, we decided to have a separate method for
|
163
|
+
supplying Basic Auth credentials, with no requirement to URL encode
|
164
|
+
the characters in them.
|
165
|
+
EOF
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def validate_no_label_clashes!(registry)
|
170
|
+
# There's nothing to check if we don't have a grouping key
|
171
|
+
return if @grouping_key.empty?
|
172
|
+
|
173
|
+
# We could be doing a lot of comparisons, so let's do them against a
|
174
|
+
# set rather than an array
|
175
|
+
grouping_key_labels = @grouping_key.keys.to_set
|
176
|
+
|
177
|
+
registry.metrics.each do |metric|
|
178
|
+
metric.values.keys.first.keys.each do |label|
|
179
|
+
if grouping_key_labels.include?(label)
|
180
|
+
raise LabelSetValidator::InvalidLabelSetError,
|
181
|
+
"label :#{label} from grouping key collides with label of the " \
|
182
|
+
"same name from metric :#{metric.name} and would overwrite it"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def validate_response!(response)
|
189
|
+
status = Integer(response.code)
|
190
|
+
if status >= 300
|
191
|
+
message = "status: #{response.code}, message: #{response.message}, body: #{response.body}"
|
192
|
+
if status <= 399
|
193
|
+
raise HttpRedirectError, message
|
194
|
+
elsif status <= 499
|
195
|
+
raise HttpClientError, message
|
196
|
+
else
|
197
|
+
raise HttpServerError, message
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
93
201
|
end
|
94
202
|
end
|
95
203
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prometheus-client-mmap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.19.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Schmidt
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-03-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fuzzbert
|
@@ -178,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
178
178
|
- !ruby/object:Gem::Version
|
179
179
|
version: '0'
|
180
180
|
requirements: []
|
181
|
-
rubygems_version: 3.
|
181
|
+
rubygems_version: 3.4.8
|
182
182
|
signing_key:
|
183
183
|
specification_version: 4
|
184
184
|
summary: A suite of instrumentation metric primitivesthat can be exposed through a
|