|
| 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 | + |
1 | 166 | # Upgrading from 0.9 to 0.10.x |
2 | 167 |
|
3 | 168 | ## Objectives |
|
0 commit comments