Skip to content

Commit 3f4ed61

Browse files
committed
Update UPGRADING.md for 3.0.0
Signed-off-by: Chris Sinjakli <chris@sinjakli.co.uk>
1 parent 7b1e73c commit 3f4ed61

1 file changed

Lines changed: 165 additions & 0 deletions

File tree

UPGRADING.md

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,168 @@
1+
# Upgrading from 2.x.x to 3.x.x
2+
3+
## Objectives
4+
5+
Most of the breaking changes in 3.0.0 are in `Prometheus::Client::Push`, which has had a
6+
fairly major overhaul.
7+
8+
As well as that, there are a handful of smaller breaking changes.
9+
10+
## Ruby
11+
12+
The minimum supported Ruby version is now 2.6. This will change over time according to our
13+
[compatibility policy](COMPATIBILITY.md).
14+
15+
## Push client improvements
16+
17+
### Keyword arguments
18+
19+
In line with changes we made for the 0.10.0 release (see below),
20+
`Prometheus::Client::Push` now favours the use of keyword arguments for improved clarity
21+
at the callsites. Specifically, the constructor now takes several keyword arguments rather
22+
than relying entirely on positional arguments. Where you would previously have written:
23+
24+
```ruby
25+
Prometheus::Client::Push.new('my-batch-job', 'some-instance', 'https://example.domain:1234')
26+
```
27+
28+
you would now write:
29+
30+
```ruby
31+
Prometheus::Client::Push.new(
32+
job: 'my-batch-job',
33+
gateway: 'https://example.domain:1234',
34+
grouping_key: { instance: 'some-instance', extra_key: 'foobar' }
35+
).add(registry)
36+
```
37+
38+
### Removal of `instance` in favour of `grouping_key`
39+
40+
Previously, it was possible to specify the instance of a job for which metrics were being
41+
pushed, like:
42+
43+
```ruby
44+
Prometheus::Client::Push.new('my-batch-job', 'some-instance').add(registry)
45+
```
46+
47+
What this really did under-the-hood was set a grouping key with a single key-value pair in
48+
it. The Pushgateway itself [supports arbitrary grouping
49+
keys](https://github.com/prometheus/pushgateway#url) made up of many key-value pairs. We
50+
now support submitting metrics with such grouping keys:
51+
52+
```ruby
53+
Prometheus::Client::Push.new(
54+
job: 'my-batch-job',
55+
grouping_key: { instance: 'some-instance', extra_key: 'foobar' }
56+
).add(registry)
57+
```
58+
59+
### Separate method for setting basic auth credentials
60+
61+
Previously, when initializing a `Prometheus::Client::Push` instance with HTTP Basic
62+
Authentication credentials, you would make a call like:
63+
64+
```ruby
65+
push = Prometheus::Client::Push.new("my-job", "some-instance", "http://user:password@localhost:9091")
66+
```
67+
68+
In most cases, this was fine, but would break if the user or password contained any
69+
non-URL-safe characters ([per RFC
70+
3986](https://datatracker.ietf.org/doc/html/rfc3986#section-2.1)).
71+
72+
While it is possible to pass those characters using percent-encoding, previous versions of
73+
`Prometheus::Client::Push` didn't decode them before passing them into the HTTP client,
74+
meaning that approach wouldn't work as the credentials we sent to the server would be
75+
wrong.
76+
77+
We [discussed how to fix
78+
it](https://github.com/prometheus/client_ruby/issues/170#issuecomment-1003765815) and
79+
decided it would be better to have a separate method for supplying HTTP Basic
80+
Authentication credentials, with no requirement for percent-encoding, than to make users
81+
jump through the hoops of correctly encoding the username and password in the gateway URL.
82+
83+
In the 3.x.x release series, HTTP Basic Authentication credentials should be passed like
84+
this:
85+
86+
```ruby
87+
push = Prometheus::Client::Push.new(job: "my-job", gateway: "http://localhost:9091")
88+
push.basic_auth("user", "password")
89+
```
90+
91+
We also explicitly reject usernames and passwords being passed in the gateway URL, and
92+
will raise an error if they are passed that way.
93+
94+
### Presence of `job` is now validated
95+
96+
We now validate that the `job` passed to the `Prometheus::Client::Push` initializer is not
97+
`nil` and isn't the empty string.
98+
99+
### Raising errors on non-2xx responses from Pushgateway
100+
101+
Previously, if the Pushgateway (or a proxy between us and it) returned a non-2xx HTTP
102+
response, we would silently fail to submit metrics to it.
103+
104+
Now, an appropriate error is raised, indicating which class of non-2xx response was
105+
received. If you want to `rescue` those errors and handle them explicitly, they are all
106+
subclasses of `Prometheus::Client::Push::HttpError`. If you only want to handle some of
107+
them, or want to handle each class of non-2xx response differently, you can `rescue` one
108+
or more of:
109+
110+
- `Prometheus::Client::Push::HttpRedirectError`
111+
- `Prometheus::Client::Push::HttpClientError`
112+
- `Prometheus::Client::Push::HttpServerError`
113+
114+
_Note: `Prometheus::Client::Push` does not follow redirects. You should configure the
115+
client to talk directly to an instance of the Pushgateway._
116+
117+
### Fixed encoding of spaces in `job` and `instance`
118+
119+
In a [previous
120+
commit](https://github.com/prometheus/client_ruby/pull/188/commits/f31bdcb8eda943f8ddf720e0b9d65ac22124cc93)
121+
we addressed the deprecation (and later removal in Ruby 3.0) of `URI.escape` by switching
122+
to `CGI.escape` for encoding the values of `job` and `instance` which would ultimately end
123+
up in the grouping key.
124+
125+
Unfortunately, this proved to be a subtly breaking change, as `CGI.escape` encodes spaces
126+
(`" "`) as `"+"` rather than `"%20"`. This led to spaces in the values of `job` and
127+
`instance` being turned into literal plus signs.
128+
129+
In 3.x.x, [we have
130+
switched](https://github.com/prometheus/client_ruby/pull/220/commits/ec5c5aa6979aa295d91fbc16e76e5eb09f82a256)
131+
to `ERB::Util::url_encode`, which handles this case correctly. You may notice your metrics
132+
being published under a different grouping key as a result of this change (if either your
133+
`job` or `instance` values contained spaces).
134+
135+
## Automatic initialization of time series with no labels
136+
137+
The [Prometheus documentation on best
138+
practices](https://prometheus.io/docs/practices/instrumentation/#avoid-missing-metrics)
139+
recommends exporting a default value for any time series you know will exist in advance.
140+
For series with no labels, other Prometheus clients (including Go, Java, and Python) do
141+
this automatically, so we have matched that behaviour in the 3.x.x series.
142+
143+
## Path generation fix in Collector middleware
144+
145+
Previously, we did not include `Rack::Request`'s `SCRIPT_NAME` when building paths in
146+
`Prometheus::Middleware::Collector`. We have now added this, which means that any
147+
application using the included collector middleware with a non-empty `SCRIPT_NAME` will
148+
generate different path labels.
149+
150+
This will most typically be present when mounting several Rack applications in the same
151+
server process, such as when using [Rails
152+
Engines](https://guides.rubyonrails.org/engines.html).
153+
154+
## Improved validation of label names
155+
156+
Earlier versions of the Ruby Prometheus client performed limited validation of label names
157+
(e.g. ensuring that they didn't start with `__`). The validation rules for label names are
158+
specified [in the Prometheus
159+
documentation](https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels),
160+
and we now apply them during metric declaration. Specifically, we have added a check that
161+
label names match the regex `[a-zA-Z_][a-zA-Z0-9_]*`.
162+
163+
Any labels previously let through by the lack of validation were invalid, and likely would
164+
have caused problems when scraped by Prometheus server.
165+
1166
# Upgrading from 0.9 to 0.10.x
2167

3168
## Objectives

0 commit comments

Comments
 (0)