|
| 1 | +# Upgrading from 0.9 to 0.10.x |
| 2 | + |
| 3 | +## Objectives |
| 4 | + |
| 5 | +0.10.0 represents a big step forward for the Prometheus Ruby client, which comes with some |
| 6 | +breaking changes. The objectives behind those changes are: |
| 7 | + |
| 8 | +1. Bringing the Ruby client in line with [Prometheus conventions and best |
| 9 | + practices](https://prometheus.io/docs/instrumenting/writing_clientlibs/) |
| 10 | +2. Adding support for multi-process web servers like Unicorn. This was done by introducing |
| 11 | + the notion of pluggable storage backends. |
| 12 | + |
| 13 | + The client can now be configured with different storage backends, and we provide 3 with |
| 14 | + the gem: thread-safe (default), thread-unsafe (best performance in single-threaded use |
| 15 | + cases), and a multi-process backend that can be used in forking web servers like |
| 16 | + Unicorn. |
| 17 | + |
| 18 | + Users of the library can build their own storage backend to support different |
| 19 | + use cases provided they conform to the same interface. |
| 20 | + |
| 21 | +## Ruby |
| 22 | + |
| 23 | +The minimum supported Ruby version is now 2.3. This will change over time according to our |
| 24 | +[compatibility policy](COMPATIBILITY.md). |
| 25 | + |
| 26 | +## Data Stores |
| 27 | + |
| 28 | +The single biggest feature in this release is support for multi-process web servers. |
| 29 | + |
| 30 | +The way this was achieved was by introducing a standard interface for metric storage |
| 31 | +backends and providing implementations for the most common use-cases. |
| 32 | + |
| 33 | +If you're using a multi-process web server, you'll want `DirectFileStore`, which |
| 34 | +aggregates metrics across the processes. |
| 35 | + |
| 36 | +```ruby |
| 37 | +Prometheus::Client.config.data_store = Prometheus::Client::DataStores::DirectFileStore.new(dir: '/tmp/direct_file_store') |
| 38 | +``` |
| 39 | + |
| 40 | +The default store is the `Synchronized` store, which provides a threadsafe implementation, |
| 41 | +but one which doesn't work in multi-process scenarios. |
| 42 | + |
| 43 | +If you're absolutely sure that you won't use multiple threads or processes, you can use the |
| 44 | +`SingleThreaded` data store and avoid the locking overhead. Note that in almost all use |
| 45 | +cases the performance overhead won't matter, which is why we use the `Synchronized` store |
| 46 | +by default. |
| 47 | + |
| 48 | +## Keyword arguments (kwargs) |
| 49 | + |
| 50 | +Many multi-parameter methods have had their arguments changed to keyword arguments for |
| 51 | +improved clarity at the callsite. |
| 52 | + |
| 53 | +### 0.9 |
| 54 | +```ruby |
| 55 | +counter = Prometheus::Client::Counter.new(:service_requests_total, '...') |
| 56 | +``` |
| 57 | + |
| 58 | +### 0.10 |
| 59 | +```ruby |
| 60 | +counter = Prometheus::Client::Counter.new(:service_requests_total, docstring: '...') |
| 61 | +``` |
| 62 | + |
| 63 | +### Labels |
| 64 | + |
| 65 | +Labels must now be declared at metric initialization. Observing a value with a label that |
| 66 | +wasn't passed in at initialization will raise an error. |
| 67 | + |
| 68 | +### 0.9 |
| 69 | + |
| 70 | +```ruby |
| 71 | +counter = Prometheus::Client::Counter.new(:service_requests_total, '...') |
| 72 | +counter.increment({ service: 'foo' }) |
| 73 | +``` |
| 74 | + |
| 75 | +### 0.10 |
| 76 | + |
| 77 | +```ruby |
| 78 | +counter = Prometheus::Client::Counter.new(:service_requests_total, docstring: '...', labels: [:service]) |
| 79 | +counter.increment(labels: { service: 'foo' }) |
| 80 | +``` |
| 81 | + |
| 82 | +## Histograms |
| 83 | + |
| 84 | +Keys in the hash returned from the get method are now strings. |
| 85 | + |
| 86 | +Histograms now include a "+Inf" bucket as well as the sum of all observations. |
| 87 | + |
| 88 | +### 0.9 |
| 89 | + |
| 90 | +```ruby |
| 91 | +histogram = Prometheus::Client::Histogram.new(:service_latency_seconds, '...', {}, [0.1, 0.3, 1.2]) |
| 92 | + |
| 93 | +histogram.observe({ service: 'users' }, 0.1) |
| 94 | +histogram.observe({ service: 'users' }, 0.3) |
| 95 | +histogram.observe({ service: 'users' }, 0.4) |
| 96 | +histogram.observe({ service: 'users' }, 1.2) |
| 97 | +histogram.observe({ service: 'users' }, 1.5) |
| 98 | + |
| 99 | +histogram.get({ service: 'users' }) |
| 100 | +# => {0.1=>1.0, 0.3=>2.0, 1.2=>4.0} |
| 101 | +``` |
| 102 | +### 0.10 |
| 103 | + |
| 104 | +```ruby |
| 105 | +histogram = Prometheus::Client::Histogram.new(:service_latency_seconds, docstring: '...', labels: [:service], buckets: [0.1, 0.3, 1.2]) |
| 106 | + |
| 107 | +histogram.observe(0.1, labels: { service: 'users' }) |
| 108 | +histogram.observe(0.3, labels: { service: 'users' }) |
| 109 | +histogram.observe(0.4, labels: { service: 'users' }) |
| 110 | +histogram.observe(1.2, labels: { service: 'users' }) |
| 111 | +histogram.observe(1.5, labels: { service: 'users' }) |
| 112 | + |
| 113 | +histogram.get(labels: { service: 'users' }) |
| 114 | +# => {"0.1"=>0.0, "0.3"=>1.0, "1.2"=>3.0, "+Inf"=>5.0, "sum"=>3.5} |
| 115 | +``` |
| 116 | + |
| 117 | +## Summaries |
| 118 | + |
| 119 | +Summaries no longer include quantiles. They include the sum and the count instead. |
| 120 | + |
| 121 | +### 0.9 |
| 122 | + |
| 123 | +```ruby |
| 124 | +summary = Prometheus::Client::Histogram.new(:service_latency_seconds, '...', {}, [0.1, 0.3, 1.2]) |
| 125 | + |
| 126 | +summary.observe({ service: 'users' }, 0.1) |
| 127 | +summary.observe({ service: 'users' }, 0.3) |
| 128 | +summary.observe({ service: 'users' }, 0.4) |
| 129 | +summary.observe({ service: 'users' }, 1.2) |
| 130 | +summary.observe({ service: 'users' }, 1.5) |
| 131 | + |
| 132 | +summary.get({ service: 'users' }) |
| 133 | +# => {0.1=>1.0, 0.3=>2.0, 1.2=>4.0} |
| 134 | +``` |
| 135 | +### 0.10 |
| 136 | + |
| 137 | +```ruby |
| 138 | +summary = Prometheus::Client::Summary.new(:service_latency_seconds, docstring: '...', labels: [:service]) |
| 139 | + |
| 140 | +summary.observe(0.1, labels: { service: 'users' }) |
| 141 | +summary.observe(0.3, labels: { service: 'users' }) |
| 142 | +summary.observe(0.4, labels: { service: 'users' }) |
| 143 | +summary.observe(1.2, labels: { service: 'users' }) |
| 144 | +summary.observe(1.5, labels: { service: 'users' }) |
| 145 | + |
| 146 | +summary.get(labels: { service: 'users' }) |
| 147 | +# => {"count"=>5.0, "sum"=>3.5} |
| 148 | +``` |
| 149 | + |
| 150 | +## Rack middleware |
| 151 | + |
| 152 | +Because metric labels must be declared up front, we've removed support for customising the |
| 153 | +labels set in the default Rack middleware we provide. |
| 154 | + |
| 155 | +We did make an attempt to preserve that ability, but decided that the interface was too |
| 156 | +confusing and removed it in #121. We might revisit this and have another try at a better |
| 157 | +interface in the future. |
| 158 | + |
| 159 | +## Extra reserved label: `pid` |
| 160 | + |
| 161 | +When adding support for multi-process web servers, we realised that aggregating gauges |
| 162 | +reported by individual processes (e.g. by summing them) is almost never what you want to |
| 163 | +do. |
| 164 | + |
| 165 | +We decided to expose each process's value individually, with a `pid` label set to |
| 166 | +differentiate between the proesses. Because of that, `pid` is now a reserved label. |
0 commit comments