Coverage Report

Created: 2024-04-25 06:27

/src/pdns/pdns/statbag.hh
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * This file is part of PowerDNS or dnsdist.
3
 * Copyright -- PowerDNS.COM B.V. and its contributors
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of version 2 of the GNU General Public License as
7
 * published by the Free Software Foundation.
8
 *
9
 * In addition, for the avoidance of any doubt, permission is granted to
10
 * link this program with OpenSSL and to (re)distribute the binaries
11
 * produced as the result of such linking.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
 */
22
#pragma once
23
#include <map>
24
#include <functional>
25
#include <string>
26
#include <vector>
27
#include "lock.hh"
28
#include "namespaces.hh"
29
#include "iputils.hh"
30
#include "circular_buffer.hh"
31
32
template<typename T, typename Comp=std::less<T> >
33
class StatRing
34
{
35
public:
36
  StatRing(unsigned int size=10000);
37
  StatRing(const StatRing&) = delete;
38
  StatRing& operator=(const StatRing&) = delete;
39
  StatRing& operator=(StatRing&&) = delete;
40
0
  StatRing(StatRing&&) = default;
Unexecuted instantiation: StatRing<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, CIStringCompare>::StatRing(StatRing<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, CIStringCompare>&&)
Unexecuted instantiation: StatRing<SComboAddress, std::__1::less<SComboAddress> >::StatRing(StatRing<SComboAddress, std::__1::less<SComboAddress> >&&)
Unexecuted instantiation: StatRing<std::__1::tuple<DNSName, QType>, std::__1::less<std::__1::tuple<DNSName, QType> > >::StatRing(StatRing<std::__1::tuple<DNSName, QType>, std::__1::less<std::__1::tuple<DNSName, QType> > >&&)
41
42
  void account(const T &item);
43
44
  uint64_t getSize() const;
45
  uint64_t getEntriesCount() const;
46
  void resize(unsigned int newsize);
47
  void reset();
48
  void setHelp(const string &str);
49
  string getHelp() const;
50
51
  vector<pair<T, unsigned int> > get() const;
52
private:
53
  static bool popisort(const pair<T,int> &a, const pair<T,int> &b)
54
0
  {
55
0
    return (a.second > b.second);
56
0
  }
Unexecuted instantiation: StatRing<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, CIStringCompare>::popisort(std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, int> const&, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, int> const&)
Unexecuted instantiation: StatRing<SComboAddress, std::__1::less<SComboAddress> >::popisort(std::__1::pair<SComboAddress, int> const&, std::__1::pair<SComboAddress, int> const&)
Unexecuted instantiation: StatRing<std::__1::tuple<DNSName, QType>, std::__1::less<std::__1::tuple<DNSName, QType> > >::popisort(std::__1::pair<std::__1::tuple<DNSName, QType>, int> const&, std::__1::pair<std::__1::tuple<DNSName, QType>, int> const&)
57
58
  boost::circular_buffer<T> d_items;
59
  string d_help;
60
};
61
62
enum class StatType : uint8_t {
63
  counter = 1,
64
  gauge = 2,
65
};
66
67
//! use this to gather and query statistics
68
class StatBag
69
{
70
  map<string, std::unique_ptr<AtomicCounter>> d_stats;
71
  map<string, string> d_keyDescriptions;
72
  map<string, StatType> d_statTypes;
73
  map<string, LockGuarded<StatRing<string, CIStringCompare> > > d_rings;
74
  map<string, LockGuarded<StatRing<SComboAddress> > > d_comboRings;
75
  map<string, LockGuarded<StatRing<std::tuple<DNSName, QType> > > > d_dnsnameqtyperings;
76
  typedef std::function<uint64_t(const std::string&)> func_t;
77
  typedef map<string, func_t> funcstats_t;
78
  funcstats_t d_funcstats;
79
  bool d_doRings;
80
81
  std::set<string> d_blacklist;
82
83
  void registerRingStats(const string& name);
84
85
public:
86
  StatBag(); //!< Naked constructor. You need to declare keys before this class becomes useful
87
  ~StatBag();
88
  void declare(const string &key, const string &descrip="", StatType statType=StatType::counter); //!< Before you can store or access a key, you need to declare it
89
  void declare(const string &key, const string &descrip, func_t func, StatType statType); //!< Before you can store or access a key, you need to declare it
90
91
  void declareRing(const string &name, const string &title, unsigned int size=10000);
92
  void declareComboRing(const string &name, const string &help, unsigned int size=10000);
93
  void declareDNSNameQTypeRing(const string &name, const string &help, unsigned int size=10000);
94
  vector<pair<string, unsigned int> >getRing(const string &name);
95
  string getRingTitle(const string &name);
96
  void ringAccount(const char* name, const string &item)
97
0
  {
98
0
    if (d_doRings)  {
99
0
      auto it = d_rings.find(name);
100
0
      if (it == d_rings.end()) {
101
0
  throw runtime_error("Attempting to account to nonexistent ring '"+std::string(name)+"'");
102
0
      }
103
0
104
0
      it->second.lock()->account(item);
105
0
    }
106
0
  }
107
  void ringAccount(const char* name, const ComboAddress &item)
108
0
  {
109
0
    if (d_doRings) {
110
0
      auto it = d_comboRings.find(name);
111
0
      if (it == d_comboRings.end()) {
112
0
  throw runtime_error("Attempting to account to nonexistent comboRing '"+std::string(name)+"'");
113
0
      }
114
0
      it->second.lock()->account(item);
115
0
    }
116
0
  }
117
  void ringAccount(const char* name, const DNSName &dnsname, const QType &qtype)
118
0
  {
119
0
    if (d_doRings) {
120
0
      auto it = d_dnsnameqtyperings.find(name);
121
0
      if (it == d_dnsnameqtyperings.end()) {
122
0
  throw runtime_error("Attempting to account to nonexistent dnsname+qtype ring '"+std::string(name)+"'");
123
0
      }
124
0
      it->second.lock()->account(std::tuple(dnsname, qtype));
125
0
    }
126
0
  }
127
128
  void doRings()
129
0
  {
130
0
    d_doRings=true;
131
0
  }
132
133
  vector<string>listRings() const;
134
  bool ringExists(const string &name) const;
135
  void resetRing(const string &name);
136
  void resizeRing(const string &name, unsigned int newsize);
137
  uint64_t getRingSize(const string &name);
138
  uint64_t getRingEntriesCount(const string &name);
139
140
  string directory(const string &prefix = ""); //!< Returns a list of all data stored. If prefix is given, only stats named with this prefix are returned.
141
  vector<string> getEntries(); //!< returns a vector with datums (items)
142
  string getDescrip(const string &item); //!< Returns the description of this datum/item
143
  StatType getStatType(const string &item); //!< Returns the stats type for the metrics endpoint
144
  void exists(const string &key); //!< call this function to throw an exception in case a key does not exist
145
  inline void deposit(const string &key, int value); //!< increment the statistics behind this key by value amount
146
  inline void inc(const string &key); //!< increase this key's value by one
147
  void set(const string &key, unsigned long value); //!< set this key's value
148
  unsigned long read(const string &key); //!< read the value behind this key
149
  AtomicCounter *getPointer(const string &key); //!< get a direct pointer to the value behind a key. Use this for high performance increments
150
  string getValueStr(const string &key); //!< read a value behind a key, and return it as a string
151
  void blacklist(const string &str);
152
153
  bool d_allowRedeclare; // only set this true during tests, never in production code
154
};
155
156
inline void StatBag::deposit(const string &key, int value)
157
0
{
158
0
  exists(key);
159
0
160
0
  *d_stats[key]+=value;
161
0
}
162
163
inline void StatBag::inc(const string &key)
164
0
{
165
0
  deposit(key, 1);
166
0
}