aboutsummaryrefslogtreecommitdiffstats
path: root/metrics/src/vespa/metrics/valuemetric.h
blob: 75d78e42cf4716a22e8c9674ead87fbc851a91ae (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
/**
 * @class metrics::ValueMetric
 * @ingroup metrics
 *
 * @brief Creates a metric measuring any value.
 *
 * A value metric have the following properties:
 *   - Logs the average as a value event. (It is not strictly increasing)
 *   - When summing average metrics together, the sum becomes the average of
 *     all values added to both.
 */

#pragma once

#include "valuemetricvalues.h"
#include "metric.h"
#include <cmath>

namespace metrics {

struct AbstractValueMetric : public Metric {
    bool visit(MetricVisitor& visitor, bool tagAsAutoGenerated = false) const override {
        return visitor.visitValueMetric(*this, tagAsAutoGenerated);
    }
    virtual MetricValueClass::UP getValues() const = 0;
    virtual bool inUse(const MetricValueClass& v) const = 0;
    virtual bool summedAverage() const = 0;

protected:
    AbstractValueMetric(const String& name, Tags dimensions,
                        const String& description, MetricSet* owner)
        : Metric(name, std::move(dimensions), description, owner) {}

    AbstractValueMetric(const AbstractValueMetric& other, MetricSet* owner)
        : Metric(other, owner) {}

    void logWarning(const char* msg, const char *op) const;
    void logNonFiniteValueWarning() const;
};

template<typename AvgVal, typename TotVal, bool SumOnAdd>
class ValueMetric : public AbstractValueMetric {
    using String = Metric::String; // Redefine so template finds it easy
    using Values = ValueMetricValues<AvgVal, TotVal>;

    MetricValueSet<Values> _values;

    enum Flag {
        SUMMED_AVERAGE = 2, UNSET_ON_ZERO_VALUE = 4
    };

    bool summedAverage() const override { return _values.hasFlag(SUMMED_AVERAGE); }

    bool unsetOnZeroValue() const { return _values.hasFlag(UNSET_ON_ZERO_VALUE); }

    void add(const Values &values, bool sumOnAdd);

    void dec(const Values &values);

    void addValueWithCount(AvgVal avg, TotVal tot, uint32_t count, AvgVal min, AvgVal max);
    void addValueWithCount(AvgVal avg, TotVal tot, uint32_t count) {
        addValueWithCount(avg, tot, count, avg, avg);
    }

    // Finite number (not infinity/NaN) check using type trait tag dispatch.
    // 2nd param is instance of std::true_type iff AvgVal is floating point.
    bool checkFinite(AvgVal v, std::true_type) {
        if (!std::isfinite(v)) {
            logNonFiniteValueWarning();
            return false;
        }
        return true;
    }

    bool checkFinite(AvgVal, std::false_type) { return true; }

public:
    ValueMetric(const ValueMetric<AvgVal, TotVal, SumOnAdd> &, MetricSet *owner);
    ValueMetric(const String &name, Tags dimensions, const String &description)
        : ValueMetric(name, std::move(dimensions), description, nullptr)
    {}
    ValueMetric(const String &name, Tags dimensions, const String &description, MetricSet *owner);

    ~ValueMetric() override;

    MetricValueClass::UP getValues() const override {
        return std::make_unique<Values>(_values.getValues());
    }

    void unsetOnZeroValue() { _values.setFlag(UNSET_ON_ZERO_VALUE); }

    ValueMetric *clone(std::vector<Metric::UP> &, CopyType , MetricSet *owner, bool) const override {
        return new ValueMetric<AvgVal,TotVal,SumOnAdd>(*this, owner);
    }

    ValueMetric & operator+=(const ValueMetric &);

    friend ValueMetric operator+(const ValueMetric & a, const ValueMetric & b) {
        ValueMetric t(a); t += b; return t;
    }

    void addAvgValueWithCount(AvgVal avg, uint32_t count) {
        if (count > 0) {
            addValueWithCount(avg, avg * count, count);
        }
    }
    void addTotalValueWithCount(TotVal tot, uint32_t count) {
        if (count > 0) {
            addValueWithCount(tot / count, tot, count);
        }
    }
    void addValueBatch(AvgVal avg, uint32_t count, AvgVal min, AvgVal max) {
        if (count > 0) {
            addValueWithCount(avg, avg * count, count, min, max);
        }
    }
    virtual void addValue(AvgVal avg) { addAvgValueWithCount(avg, 1); }
    virtual void set(AvgVal avg) { addValue(avg); }
    virtual void inc(AvgVal val = 1);
    virtual void dec(AvgVal val = 1);

    double getAverage() const;
    AvgVal getMinimum() const { return _values.getValues()._min; }
    AvgVal getMaximum() const { return _values.getValues()._max; }
    AvgVal getCount() const { return _values.getValues()._count; }
    TotVal getTotal() const { return _values.getValues()._total; }

    AvgVal getLast() const { return _values.getValues()._last; }

    void reset() override { _values.reset(); }

    void print(std::ostream&, bool verbose,
               const std::string& indent, uint64_t secondsPassed) const override;

    int64_t getLongValue(stringref id) const override;
    double getDoubleValue(stringref id) const override;

    bool inUse(const MetricValueClass& v) const override {
        const Values& values(static_cast<const Values&>(v));
        return (values._total != 0
                || (values._count != 0 && !unsetOnZeroValue()));
    }
    bool used() const override { return inUse(_values.getValues()); }
    void addMemoryUsage(MemoryConsumption&) const override;
    void printDebug(std::ostream&, const std::string& indent) const override;
    void addToPart(Metric&) const override;
    void addToSnapshot(Metric&, std::vector<Metric::UP> &) const override;
};

using DoubleValueMetric = ValueMetric<double, double, true>;
using DoubleAverageMetric = ValueMetric<double, double, false>;
using LongValueMetric = ValueMetric<int64_t, int64_t, true>;
using LongAverageMetric = ValueMetric<int64_t, int64_t, false>;

} // metrics