prometheus-client 2.1.0 → 4.0.0
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 +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.
|