blob: bce1917b732dac1dd011bbd0eac85cfcc9cefd76 [file]
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License
#ifndef __PROCESS_METRICS_PUSH_GAUGE_HPP__
#define __PROCESS_METRICS_PUSH_GAUGE_HPP__
#include <memory>
#include <string>
#include <process/metrics/metric.hpp>
namespace process {
namespace metrics {
// A Metric that represents an instantaneous measurement of a value
// (e.g. number of items in a queue).
//
// A push-based gauge differs from a pull-based gauge in that the
// client is responsible for pushing the latest value into the gauge
// whenever it changes. This can be challenging in some cases as it
// requires the client to have a good handle on when the gauge value
// changes (rather than just computing the current value when asked).
//
// NOTE: It is highly recommended to use push-based gauges if
// possible as they provide significant performance benefits over
// pull-based gauges. Pull-based gauge suffer from delays getting
// processed on the event queue of a `Process`, as well as incur
// computation cost on the `Process` each time the metrics are
// collected. Push-based gauges, on the other hand, incur no cost
// to the owning `Process` when metrics are collected, and instead
// incur a trivial cost when the `Process` pushes new values in.
class PushGauge : public Metric
{
public:
// 'name' is the unique name for the instance of Gauge being constructed.
// It will be the key exposed in the JSON endpoint.
//
// 'f' is the function that is called when the Metric value is requested.
// The user of `Gauge` must ensure that `f` is safe to execute up until
// the removal of the `Gauge` (via `process::metrics::remove(...)`) is
// complete.
explicit PushGauge(const std::string& name)
: Metric(name, None()), data(new Data()) {}
~PushGauge() override {}
Future<double> value() const override
{
return static_cast<double>(data->value.load());
}
PushGauge& operator=(double v)
{
data->value.store(v);
push(v);
return *this;
}
PushGauge& operator++() { return *this += 1; }
PushGauge& operator+=(double v)
{
double prev;
while (true) {
prev = data->value.load();
if (data->value.compare_exchange_weak(prev, prev + v)) {
break;
}
}
push(static_cast<double>(prev + v));
return *this;
}
PushGauge& operator--() { return *this -= 1; }
PushGauge& operator-=(double v)
{
double prev;
while (true) {
prev = data->value.load();
if (data->value.compare_exchange_weak(prev, prev - v)) {
break;
}
}
push(static_cast<double>(prev - v));
return *this;
}
private:
struct Data
{
explicit Data() : value(0) {}
std::atomic<double> value;
};
std::shared_ptr<Data> data;
};
} // namespace metrics {
} // namespace process {
#endif // __PROCESS_METRICS_PUSH_GAUGE_HPP__