summaryrefslogtreecommitdiffstats
path: root/metrics/src/vespa/metrics/valuemetric.h
blob: ce132e3ffddb3b22a8d043ccde6a2ba53020b968 (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
158
159
160
161
162
// Copyright 2016 Yahoo Inc. 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 {
    virtual bool visit(MetricVisitor& visitor,
                       bool tagAsAutoGenerated = false) const
    {
        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, const String& tags,
                        const String& description, MetricSet* owner)
        : Metric(name, tags, description, owner) {}

    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;
    void sendLogEvent(Metric::String name, double value) 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, LOG_IF_UNSET = 8 };

    virtual bool summedAverage() const
        { return _values.hasFlag(SUMMED_AVERAGE); }
    bool unsetOnZeroValue() const
        { return _values.hasFlag(UNSET_ON_ZERO_VALUE); }
    bool logIfUnset() const { return _values.hasFlag(LOG_IF_UNSET); }

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

    void addValueWithCount(AvgVal avg, TotVal tot, uint32_t count);

    // 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 String& name, const String& tags,
                const String& description, MetricSet* owner = 0);

    ValueMetric(const ValueMetric<AvgVal, TotVal, SumOnAdd>&,
                CopyType, MetricSet* owner);

    ValueMetric(const String& name, Tags dimensions,
                const String& description, MetricSet* owner = 0);

    ~ValueMetric();

    virtual MetricValueClass::UP getValues() const
        { return MetricValueClass::UP(new Values(_values.getValues())); }

    void unsetOnZeroValue() { _values.setFlag(UNSET_ON_ZERO_VALUE); }
    void logOnlyIfSet() { _values.removeFlag(LOG_IF_UNSET); }

    virtual ValueMetric * clone(
            std::vector<Metric::LP>&, CopyType type, MetricSet* owner,
            bool /*includeUnused*/) const
        { return new ValueMetric<AvgVal,TotVal,SumOnAdd>(*this, type, 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) { addValueWithCount(avg, avg * count, count); } }
    void addTotalValueWithCount(TotVal tot, uint32_t count)
    { if (count) { addValueWithCount(tot / count, tot, count); } }
    void addValueBatch(AvgVal avg, uint32_t count) {
        addAvgValueWithCount(avg, count);
    }
    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; }
    AvgVal getLast() const { return _values.getValues()._last; }

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

    virtual bool logEvent(const String& fullName) const;

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

    virtual int64_t getLongValue(const stringref & id) const;
    virtual double getDoubleValue(const stringref & id) const;


    virtual bool inUse(const MetricValueClass& v) const {
        const Values& values(static_cast<const Values&>(v));
        return (values._total != 0
                || (values._count != 0 && !unsetOnZeroValue()));
    }
    virtual bool used() const {
        return inUse(_values.getValues());
    }

    virtual void addMemoryUsage(MemoryConsumption&) const;

    virtual void printDebug(std::ostream&, const std::string& indent) const;

    virtual void addToPart(Metric&) const;
    virtual void addToSnapshot(Metric&, std::vector<Metric::LP>&) const;
};

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

} // metrics