prometheus-client 2.1.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +63 -12
- data/lib/prometheus/client/histogram.rb +19 -7
- data/lib/prometheus/client/label_set_validator.rb +9 -2
- data/lib/prometheus/client/metric.rb +21 -6
- data/lib/prometheus/client/push.rb +126 -12
- data/lib/prometheus/client/registry.rb +4 -4
- data/lib/prometheus/client/summary.rb +6 -1
- data/lib/prometheus/client/version.rb +1 -1
- data/lib/prometheus/middleware/collector.rb +12 -4
- data/lib/prometheus/middleware/exporter.rb +6 -1
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d86fc24651a441455a293ead401451df5f6954499943f9c752117fe5f879b5cd
|
4
|
+
data.tar.gz: 5aaa58ced22e1050e7a4687a44b251710d5f12281f1572a2375d71f733c4ffc0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81ddb196287e2d977e6210c6b56a58459cbf4eab56e6e38ac55929a4a59d9749c64f043153b64ae120c591ed35a364b088df3f156b9825b79c69df8bfecbb240
|
7
|
+
data.tar.gz: dfe9c36fc511b3adde97198d6e53705d62d7502af016e6636cd9191cb94434126ee4a0d80e73eccddf8ad3c2d0fe116319c1f769b8fdedfcd0213a3d1176abce
|
data/README.md
CHANGED
@@ -5,8 +5,7 @@ through a HTTP interface. Intended to be used together with a
|
|
5
5
|
[Prometheus server][1].
|
6
6
|
|
7
7
|
[![Gem Version][4]](http://badge.fury.io/rb/prometheus-client)
|
8
|
-
[![Build Status][3]](
|
9
|
-
[![Coverage Status][7]](https://coveralls.io/r/prometheus/client_ruby)
|
8
|
+
[![Build Status][3]](https://circleci.com/gh/prometheus/client_ruby/tree/master.svg?style=svg)
|
10
9
|
|
11
10
|
## Usage
|
12
11
|
|
@@ -71,7 +70,7 @@ integrated [example application](examples/rack/README.md).
|
|
71
70
|
The Ruby client can also be used to push its collected metrics to a
|
72
71
|
[Pushgateway][8]. This comes in handy with batch jobs or in other scenarios
|
73
72
|
where it's not possible or feasible to let a Prometheus server scrape a Ruby
|
74
|
-
process. TLS and basic
|
73
|
+
process. TLS and HTTP basic authentication are supported.
|
75
74
|
|
76
75
|
```ruby
|
77
76
|
require 'prometheus/client'
|
@@ -81,18 +80,59 @@ registry = Prometheus::Client.registry
|
|
81
80
|
# ... register some metrics, set/increment/observe/etc. their values
|
82
81
|
|
83
82
|
# push the registry state to the default gateway
|
84
|
-
Prometheus::Client::Push.new('my-batch-job').add(registry)
|
83
|
+
Prometheus::Client::Push.new(job: 'my-batch-job').add(registry)
|
84
|
+
|
85
|
+
# optional: specify a grouping key that uniquely identifies a job instance, and gateway.
|
86
|
+
#
|
87
|
+
# Note: the labels you use in the grouping key must not conflict with labels set on the
|
88
|
+
# metrics being pushed. If they do, an error will be raised.
|
89
|
+
Prometheus::Client::Push.new(
|
90
|
+
job: 'my-batch-job',
|
91
|
+
gateway: 'https://example.domain:1234',
|
92
|
+
grouping_key: { instance: 'some-instance', extra_key: 'foobar' }
|
93
|
+
).add(registry)
|
94
|
+
|
95
|
+
# If you want to replace any previously pushed metrics for a given grouping key,
|
96
|
+
# use the #replace method.
|
97
|
+
#
|
98
|
+
# Unlike #add, this will completely replace the metrics under the specified grouping key
|
99
|
+
# (i.e. anything currently present in the pushgateway for the specified grouping key, but
|
100
|
+
# not present in the registry for that grouping key will be removed).
|
101
|
+
#
|
102
|
+
# See https://github.com/prometheus/pushgateway#put-method for a full explanation.
|
103
|
+
Prometheus::Client::Push.new(job: 'my-batch-job').replace(registry)
|
104
|
+
|
105
|
+
# If you want to delete all previously pushed metrics for a given grouping key,
|
106
|
+
# use the #delete method.
|
107
|
+
Prometheus::Client::Push.new(job: 'my-batch-job').delete
|
108
|
+
```
|
85
109
|
|
86
|
-
|
87
|
-
Prometheus::Client::Push.new('my-batch-job', 'foobar', 'https://example.domain:1234').add(registry)
|
110
|
+
#### Basic authentication
|
88
111
|
|
89
|
-
|
90
|
-
|
91
|
-
|
112
|
+
By design, `Prometheus::Client::Push` doesn't read credentials for HTTP basic
|
113
|
+
authentication when they are passed in via the gateway URL using the
|
114
|
+
`http://user:password@example.com:9091` syntax, and will in fact raise an error if they're
|
115
|
+
supplied that way.
|
92
116
|
|
93
|
-
|
94
|
-
|
95
|
-
|
117
|
+
The reason for this is that when using that syntax, the username and password
|
118
|
+
have to follow the usual rules for URL encoding of characters [per RFC
|
119
|
+
3986](https://datatracker.ietf.org/doc/html/rfc3986#section-2.1).
|
120
|
+
|
121
|
+
Rather than place the burden of correctly performing that encoding on users of this gem,
|
122
|
+
we decided to have a separate method for supplying HTTP basic authentication credentials,
|
123
|
+
with no requirement to URL encode the characters in them.
|
124
|
+
|
125
|
+
Instead of passing credentials like this:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
push = Prometheus::Client::Push.new(job: "my-job", gateway: "http://user:password@localhost:9091")
|
129
|
+
```
|
130
|
+
|
131
|
+
please pass them like this:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
push = Prometheus::Client::Push.new(job: "my-job", gateway: "http://localhost:9091")
|
135
|
+
push.basic_auth("user", "password")
|
96
136
|
```
|
97
137
|
|
98
138
|
## Metrics
|
@@ -389,6 +429,17 @@ If you are running in pre-fork servers (such as Unicorn or Puma with multiple pr
|
|
389
429
|
make sure you do this **before** the server forks. Otherwise, each child process may delete
|
390
430
|
files created by other processes on *this* run, instead of deleting old files.
|
391
431
|
|
432
|
+
**Declare metrics before fork**: As well as deleting files before your process forks, you
|
433
|
+
should make sure to declare your metrics before forking too. Because the metric registry
|
434
|
+
is held in memory, any metrics declared after forking will only be present in child
|
435
|
+
processes where the code declaring them ran, and as a result may not be consistently
|
436
|
+
exported when scraped (i.e. they will only appear when a child process that declared them
|
437
|
+
is scraped).
|
438
|
+
|
439
|
+
If you're absolutely sure that every child process will run the metric declaration code,
|
440
|
+
then you won't run into this issue, but the simplest approach is to declare the metrics
|
441
|
+
before forking.
|
442
|
+
|
392
443
|
**Large numbers of files**: Because there is an individual file per metric and per process
|
393
444
|
(which is done to optimize for observation performance), you may end up with a large number
|
394
445
|
of files. We don't currently have a solution for this problem, but we're working on it.
|
@@ -6,7 +6,7 @@ module Prometheus
|
|
6
6
|
module Client
|
7
7
|
# A histogram samples observations (usually things like request durations
|
8
8
|
# or response sizes) and counts them in configurable buckets. It also
|
9
|
-
# provides a sum of all observed values.
|
9
|
+
# provides a total count and sum of all observed values.
|
10
10
|
class Histogram < Metric
|
11
11
|
# DEFAULT_BUCKETS are the default Histogram buckets. The default buckets
|
12
12
|
# are tailored to broadly measure the response time (in seconds) of a
|
@@ -42,18 +42,30 @@ module Prometheus
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def with_labels(labels)
|
45
|
-
self.class.new(name,
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
new_metric = self.class.new(name,
|
46
|
+
docstring: docstring,
|
47
|
+
labels: @labels,
|
48
|
+
preset_labels: preset_labels.merge(labels),
|
49
|
+
buckets: @buckets,
|
50
|
+
store_settings: @store_settings)
|
51
|
+
|
52
|
+
# The new metric needs to use the same store as the "main" declared one, otherwise
|
53
|
+
# any observations on that copy with the pre-set labels won't actually be exported.
|
54
|
+
new_metric.replace_internal_store(@store)
|
55
|
+
|
56
|
+
new_metric
|
51
57
|
end
|
52
58
|
|
53
59
|
def type
|
54
60
|
:histogram
|
55
61
|
end
|
56
62
|
|
63
|
+
# Records a given value. The recorded value is usually positive
|
64
|
+
# or zero. A negative value is accepted but prevents current
|
65
|
+
# versions of Prometheus from properly detecting counter resets
|
66
|
+
# in the sum of observations. See
|
67
|
+
# https://prometheus.io/docs/practices/histograms/#count-and-sum-of-observations
|
68
|
+
# for details.
|
57
69
|
def observe(value, labels: {})
|
58
70
|
bucket = buckets.find {|upper_limit| upper_limit >= value }
|
59
71
|
bucket = "+Inf" if bucket.nil?
|
@@ -7,6 +7,7 @@ module Prometheus
|
|
7
7
|
class LabelSetValidator
|
8
8
|
# TODO: we might allow setting :instance in the future
|
9
9
|
BASE_RESERVED_LABELS = [:job, :instance, :pid].freeze
|
10
|
+
LABEL_NAME_REGEX = /\A[a-zA-Z_][a-zA-Z0-9_]*\Z/
|
10
11
|
|
11
12
|
class LabelSetError < StandardError; end
|
12
13
|
class InvalidLabelSetError < LabelSetError; end
|
@@ -59,9 +60,15 @@ module Prometheus
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def validate_name(key)
|
62
|
-
|
63
|
+
if key.to_s.start_with?('__')
|
64
|
+
raise ReservedLabelError, "label #{key} must not start with __"
|
65
|
+
end
|
66
|
+
|
67
|
+
unless key.to_s =~ LABEL_NAME_REGEX
|
68
|
+
raise InvalidLabelError, "label name must match /#{LABEL_NAME_REGEX}/"
|
69
|
+
end
|
63
70
|
|
64
|
-
|
71
|
+
true
|
65
72
|
end
|
66
73
|
|
67
74
|
def validate_reserved_key(key)
|
@@ -7,7 +7,7 @@ module Prometheus
|
|
7
7
|
module Client
|
8
8
|
# Metric
|
9
9
|
class Metric
|
10
|
-
attr_reader :name, :docstring, :preset_labels
|
10
|
+
attr_reader :name, :docstring, :labels, :preset_labels
|
11
11
|
|
12
12
|
def initialize(name,
|
13
13
|
docstring:,
|
@@ -40,8 +40,17 @@ module Prometheus
|
|
40
40
|
metric_type: type,
|
41
41
|
metric_settings: store_settings
|
42
42
|
)
|
43
|
+
|
44
|
+
# WARNING: Our internal store can be replaced later by `with_labels`
|
45
|
+
# Everything we do after this point needs to still work if @store gets replaced
|
46
|
+
init_label_set({}) if labels.empty?
|
47
|
+
end
|
48
|
+
|
49
|
+
protected def replace_internal_store(new_store)
|
50
|
+
@store = new_store
|
43
51
|
end
|
44
52
|
|
53
|
+
|
45
54
|
# Returns the value for the given label set
|
46
55
|
def get(labels: {})
|
47
56
|
label_set = label_set_for(labels)
|
@@ -49,11 +58,17 @@ module Prometheus
|
|
49
58
|
end
|
50
59
|
|
51
60
|
def with_labels(labels)
|
52
|
-
self.class.new(name,
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
61
|
+
new_metric = self.class.new(name,
|
62
|
+
docstring: docstring,
|
63
|
+
labels: @labels,
|
64
|
+
preset_labels: preset_labels.merge(labels),
|
65
|
+
store_settings: @store_settings)
|
66
|
+
|
67
|
+
# The new metric needs to use the same store as the "main" declared one, otherwise
|
68
|
+
# any observations on that copy with the pre-set labels won't actually be exported.
|
69
|
+
new_metric.replace_internal_store(@store)
|
70
|
+
|
71
|
+
new_metric
|
57
72
|
end
|
58
73
|
|
59
74
|
def init_label_set(labels)
|
@@ -1,11 +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'
|
7
|
+
require 'erb'
|
8
|
+
require 'set'
|
6
9
|
|
7
10
|
require 'prometheus/client'
|
8
11
|
require 'prometheus/client/formats/text'
|
12
|
+
require 'prometheus/client/label_set_validator'
|
9
13
|
|
10
14
|
module Prometheus
|
11
15
|
# Client is a ruby implementation for a Prometheus compatible client.
|
@@ -13,23 +17,41 @@ module Prometheus
|
|
13
17
|
# Push implements a simple way to transmit a given registry to a given
|
14
18
|
# Pushgateway.
|
15
19
|
class Push
|
20
|
+
class HttpError < StandardError; end
|
21
|
+
class HttpRedirectError < HttpError; end
|
22
|
+
class HttpClientError < HttpError; end
|
23
|
+
class HttpServerError < HttpError; end
|
24
|
+
|
16
25
|
DEFAULT_GATEWAY = 'http://localhost:9091'.freeze
|
17
26
|
PATH = '/metrics/job/%s'.freeze
|
18
|
-
INSTANCE_PATH = '/metrics/job/%s/instance/%s'.freeze
|
19
27
|
SUPPORTED_SCHEMES = %w(http https).freeze
|
20
28
|
|
21
|
-
attr_reader :job, :
|
29
|
+
attr_reader :job, :gateway, :path
|
30
|
+
|
31
|
+
def initialize(job:, gateway: DEFAULT_GATEWAY, grouping_key: {}, **kwargs)
|
32
|
+
raise ArgumentError, "job cannot be nil" if job.nil?
|
33
|
+
raise ArgumentError, "job cannot be empty" if job.empty?
|
34
|
+
@validator = LabelSetValidator.new(expected_labels: grouping_key.keys)
|
35
|
+
@validator.validate_symbols!(grouping_key)
|
22
36
|
|
23
|
-
def initialize(job, instance = nil, gateway = nil)
|
24
37
|
@mutex = Mutex.new
|
25
38
|
@job = job
|
26
|
-
@instance = instance
|
27
39
|
@gateway = gateway || DEFAULT_GATEWAY
|
28
|
-
@
|
40
|
+
@grouping_key = grouping_key
|
41
|
+
@path = build_path(job, grouping_key)
|
42
|
+
|
29
43
|
@uri = parse("#{@gateway}#{@path}")
|
44
|
+
validate_no_basic_auth!(@uri)
|
30
45
|
|
31
46
|
@http = Net::HTTP.new(@uri.host, @uri.port)
|
32
47
|
@http.use_ssl = (@uri.scheme == 'https')
|
48
|
+
@http.open_timeout = kwargs[:open_timeout] if kwargs[:open_timeout]
|
49
|
+
@http.read_timeout = kwargs[:read_timeout] if kwargs[:read_timeout]
|
50
|
+
end
|
51
|
+
|
52
|
+
def basic_auth(user, password)
|
53
|
+
@user = user
|
54
|
+
@password = password
|
33
55
|
end
|
34
56
|
|
35
57
|
def add(registry)
|
@@ -64,26 +86,118 @@ module Prometheus
|
|
64
86
|
raise ArgumentError, "#{url} is not a valid URL: #{e}"
|
65
87
|
end
|
66
88
|
|
67
|
-
def build_path(job,
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
72
113
|
end
|
114
|
+
|
115
|
+
path
|
73
116
|
end
|
74
117
|
|
75
118
|
def request(req_class, registry = nil)
|
119
|
+
validate_no_label_clashes!(registry) if registry
|
120
|
+
|
76
121
|
req = req_class.new(@uri)
|
77
122
|
req.content_type = Formats::Text::CONTENT_TYPE
|
78
|
-
req.basic_auth(@
|
123
|
+
req.basic_auth(@user, @password) if @user
|
79
124
|
req.body = Formats::Text.marshal(registry) if registry
|
80
125
|
|
81
|
-
@http.request(req)
|
126
|
+
response = @http.request(req)
|
127
|
+
validate_response!(response)
|
128
|
+
|
129
|
+
response
|
82
130
|
end
|
83
131
|
|
84
132
|
def synchronize
|
85
133
|
@mutex.synchronize { yield }
|
86
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.labels.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
|
87
201
|
end
|
88
202
|
end
|
89
203
|
end
|
@@ -22,7 +22,7 @@ module Prometheus
|
|
22
22
|
name = metric.name
|
23
23
|
|
24
24
|
@mutex.synchronize do
|
25
|
-
if
|
25
|
+
if @metrics.key?(name.to_sym)
|
26
26
|
raise AlreadyRegisteredError, "#{name} has already been registered"
|
27
27
|
end
|
28
28
|
@metrics[name.to_sym] = metric
|
@@ -73,15 +73,15 @@ module Prometheus
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def exist?(name)
|
76
|
-
@metrics.key?(name)
|
76
|
+
@mutex.synchronize { @metrics.key?(name) }
|
77
77
|
end
|
78
78
|
|
79
79
|
def get(name)
|
80
|
-
@metrics[name.to_sym]
|
80
|
+
@mutex.synchronize { @metrics[name.to_sym] }
|
81
81
|
end
|
82
82
|
|
83
83
|
def metrics
|
84
|
-
@metrics.values
|
84
|
+
@mutex.synchronize { @metrics.values }
|
85
85
|
end
|
86
86
|
end
|
87
87
|
end
|
@@ -11,7 +11,12 @@ module Prometheus
|
|
11
11
|
:summary
|
12
12
|
end
|
13
13
|
|
14
|
-
# Records a given value.
|
14
|
+
# Records a given value. The recorded value is usually positive
|
15
|
+
# or zero. A negative value is accepted but prevents current
|
16
|
+
# versions of Prometheus from properly detecting counter resets
|
17
|
+
# in the sum of observations. See
|
18
|
+
# https://prometheus.io/docs/practices/histograms/#count-and-sum-of-observations
|
19
|
+
# for details.
|
15
20
|
def observe(value, labels: {})
|
16
21
|
base_label_set = label_set_for(labels)
|
17
22
|
|
@@ -67,15 +67,17 @@ module Prometheus
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def record(env, code, duration)
|
70
|
+
path = generate_path(env)
|
71
|
+
|
70
72
|
counter_labels = {
|
71
73
|
code: code,
|
72
74
|
method: env['REQUEST_METHOD'].downcase,
|
73
|
-
path:
|
75
|
+
path: path,
|
74
76
|
}
|
75
77
|
|
76
78
|
duration_labels = {
|
77
79
|
method: env['REQUEST_METHOD'].downcase,
|
78
|
-
path:
|
80
|
+
path: path,
|
79
81
|
}
|
80
82
|
|
81
83
|
@requests.increment(labels: counter_labels)
|
@@ -85,10 +87,16 @@ module Prometheus
|
|
85
87
|
nil
|
86
88
|
end
|
87
89
|
|
90
|
+
def generate_path(env)
|
91
|
+
full_path = [env['SCRIPT_NAME'], env['PATH_INFO']].join
|
92
|
+
|
93
|
+
strip_ids_from_path(full_path)
|
94
|
+
end
|
95
|
+
|
88
96
|
def strip_ids_from_path(path)
|
89
97
|
path
|
90
|
-
.gsub(%r{/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(
|
91
|
-
.gsub(%r{/\d+(
|
98
|
+
.gsub(%r{/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?=/|$)}, '/:uuid\\1')
|
99
|
+
.gsub(%r{/\d+(?=/|$)}, '/:id\\1')
|
92
100
|
end
|
93
101
|
end
|
94
102
|
end
|
@@ -21,11 +21,12 @@ module Prometheus
|
|
21
21
|
@app = app
|
22
22
|
@registry = options[:registry] || Client.registry
|
23
23
|
@path = options[:path] || '/metrics'
|
24
|
+
@port = options[:port]
|
24
25
|
@acceptable = build_dictionary(FORMATS, FALLBACK)
|
25
26
|
end
|
26
27
|
|
27
28
|
def call(env)
|
28
|
-
if env['PATH_INFO'] == @path
|
29
|
+
if metrics_port?(env['SERVER_PORT']) && env['PATH_INFO'] == @path
|
29
30
|
format = negotiate(env, @acceptable)
|
30
31
|
format ? respond_with(format) : not_acceptable(FORMATS)
|
31
32
|
else
|
@@ -86,6 +87,10 @@ module Prometheus
|
|
86
87
|
memo[format::MEDIA_TYPE] = format
|
87
88
|
end
|
88
89
|
end
|
90
|
+
|
91
|
+
def metrics_port?(request_port)
|
92
|
+
@port.nil? || @port.to_s == request_port
|
93
|
+
end
|
89
94
|
end
|
90
95
|
end
|
91
96
|
end
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prometheus-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Kochie
|
8
8
|
- Chris Sinjakli
|
9
9
|
- Daniel Magliola
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2022-03-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: benchmark-ips
|
@@ -40,10 +40,10 @@ dependencies:
|
|
40
40
|
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
42
|
version: '0'
|
43
|
-
description:
|
43
|
+
description:
|
44
44
|
email:
|
45
45
|
- superq@gmail.com
|
46
|
-
- chris@
|
46
|
+
- chris@sinjakli.co.uk
|
47
47
|
- dmagliola@crystalgears.com
|
48
48
|
executables: []
|
49
49
|
extensions: []
|
@@ -71,9 +71,9 @@ files:
|
|
71
71
|
- lib/prometheus/middleware/exporter.rb
|
72
72
|
homepage: https://github.com/prometheus/client_ruby
|
73
73
|
licenses:
|
74
|
-
- Apache
|
74
|
+
- Apache-2.0
|
75
75
|
metadata: {}
|
76
|
-
post_install_message:
|
76
|
+
post_install_message:
|
77
77
|
rdoc_options: []
|
78
78
|
require_paths:
|
79
79
|
- lib
|
@@ -88,8 +88,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
requirements: []
|
91
|
-
rubygems_version: 3.
|
92
|
-
signing_key:
|
91
|
+
rubygems_version: 3.3.4
|
92
|
+
signing_key:
|
93
93
|
specification_version: 4
|
94
94
|
summary: A suite of instrumentation metric primitivesthat can be exposed through a
|
95
95
|
web services interface.
|