]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Allow to specify a name that is used for Prometheus export only.
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 28 Oct 2020 09:39:23 +0000 (10:39 +0100)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 28 Oct 2020 09:39:23 +0000 (10:39 +0100)
This can be used to specify names that are structured using Prometheus
conventions. If no name Prometheus name is given, do a more thorough
conversion to a name Prometheus likes by replacng any non-alnum
char by an underscore.

pdns/lua-recursor4.cc
pdns/rec_channel.hh
pdns/rec_channel_rec.cc
pdns/recursordist/docs/lua-scripting/statistics.rst
pdns/ws-recursor.cc

index 0fdf23772ecba2c393a9c32e3973b26ae21768be..7ddd538e9ef4ecce894f6e3c67521f720826586c 100644 (file)
@@ -354,8 +354,8 @@ void RecursorLua4::postPrepareContext()
 
   d_pd.push_back({"now", &g_now});
 
-  d_lw->writeFunction("getMetric", [](const std::string& str) {
-      return DynMetric{getDynMetric(str)};
+  d_lw->writeFunction("getMetric", [](const std::string& str, boost::optional<std::string> prometheusName) {
+    return DynMetric{getDynMetric(str, prometheusName ? *prometheusName : "")};
     });
 
   d_lw->registerFunction("inc", &DynMetric::inc);
index 09c8f1def596d48694a704401cc30b64a62a52f8..3862bfeed535032a3106aa3204e4de9249c4692c 100644 (file)
@@ -72,7 +72,7 @@ public:
 
 enum class StatComponent { API, Carbon, RecControl, SNMP };
 
-std::map<std::string, std::string> getAllStatsMap(StatComponent component);
+std::map<std::string, std::string> getAllStatsMap(StatComponent component, bool prometheusName = false);
 extern std::mutex g_carbon_config_lock;
 std::vector<std::pair<DNSName, uint16_t> >* pleaseGetQueryRing();
 std::vector<std::pair<DNSName, uint16_t> >* pleaseGetServfailQueryRing();
@@ -83,7 +83,7 @@ std::vector<ComboAddress>* pleaseGetBogusRemotes();
 std::vector<ComboAddress>* pleaseGetLargeAnswerRemotes();
 std::vector<ComboAddress>* pleaseGetTimeouts();
 DNSName getRegisteredName(const DNSName& dom);
-std::atomic<unsigned long>* getDynMetric(const std::string& str);
+std::atomic<unsigned long>* getDynMetric(const std::string& str, const std::string& prometheusName);
 optional<uint64_t> getStatByName(const std::string& name);
 bool isStatBlacklisted(StatComponent component, const std::string& name);
 void blacklistStat(StatComponent component, const string& name);
index a192962a232dbb22d99088987d5ab936632efb6c..7278d4eec14fff9031f627786662e9740e059773 100644 (file)
@@ -43,7 +43,12 @@ static map<string, const uint32_t*> d_get32bitpointers;
 static map<string, const std::atomic<uint64_t>*> d_getatomics;
 static map<string, function< uint64_t() > >  d_get64bitmembers;
 static std::mutex d_dynmetricslock;
-static map<string, std::atomic<unsigned long>* > d_dynmetrics;
+struct dynmetrics {
+  std::atomic<unsigned long> *d_ptr;
+  std::string d_prometheusName;
+};
+
+static map<string, dynmetrics> d_dynmetrics;
 
 static std::map<StatComponent, std::set<std::string>> s_blacklistedStats;
 
@@ -82,16 +87,24 @@ static void addGetStat(const string& name, function<uint64_t ()> f )
   d_get64bitmembers[name]=f;
 }
 
-std::atomic<unsigned long>* getDynMetric(const std::string& str)
+std::atomic<unsigned long>* getDynMetric(const std::string& str, const std::string& prometheusName)
 {
   std::lock_guard<std::mutex> l(d_dynmetricslock);
   auto f = d_dynmetrics.find(str);
   if(f != d_dynmetrics.end())
-    return f->second;
+    return f->second.d_ptr;
 
-  auto ret = new std::atomic<unsigned long>();
+  std::string name(str);
+  if (!prometheusName.empty()) {
+    name = prometheusName;
+  } else {
+    std::replace_if(name.begin(), name.end(), [](char c){
+      return !isalnum(static_cast<unsigned char>(c));}, '_');
+  }
+
+  auto ret = dynmetrics{new std::atomic<unsigned long>(), name};
   d_dynmetrics[str]= ret;
-  return ret;
+  return ret.d_ptr;
 }
 
 static optional<uint64_t> get(const string& name)
@@ -106,9 +119,9 @@ static optional<uint64_t> get(const string& name)
     return d_get64bitmembers.find(name)->second();
 
   std::lock_guard<std::mutex> l(d_dynmetricslock);
-  auto f =rplookup(d_dynmetrics, name);
-  if(f)
-    return (*f)->load();
+  auto f = rplookup(d_dynmetrics, name);
+  if (f)
+    return f->d_ptr->load();
   
   return ret;
 }
@@ -118,7 +131,7 @@ optional<uint64_t> getStatByName(const std::string& name)
   return get(name);
 }
 
-map<string,string> getAllStatsMap(StatComponent component)
+map<string,string> getAllStatsMap(StatComponent component, bool prometheusNames)
 {
   map<string,string> ret;
   const auto& blacklistMap = s_blacklistedStats.at(component);
@@ -144,7 +157,8 @@ map<string,string> getAllStatsMap(StatComponent component)
     std::lock_guard<std::mutex> l(d_dynmetricslock);
     for(const auto& a : d_dynmetrics) {
       if (blacklistMap.count(a.first) == 0) {
-        ret.insert({a.first, std::to_string(*a.second)});
+        ret.insert({prometheusNames ? a.second.d_prometheusName : a.first,
+            std::to_string(*a.second.d_ptr)});
       }
     }
   }
index b37c1a37565257c6ccc59ee6883c18cc34e1f31d..eafbf1be52b79636fedd93c77fba8d8c37484022 100644 (file)
@@ -14,12 +14,16 @@ Create a custom metric with:
 
   myMetric=getMetric("myspecialmetric")
 
-.. function:: getMetric(name) -> Metric
+.. function:: getMetric(name [, prometheusName]) -> Metric
 
   Returns the :class:`Metric` object with the name ``name``, creating the metric if it does not exist.
 
   :param str name: The metric to retrieve
 
+  .. versionadded:: 4.5.0
+
+  :param string prometheusName: The optional Prometheus specific name.
+
 .. class:: Metric
 
   Represents a custom metric
index 68feb47e1ac469c1cc07b5c22b9f4d7ead966cf9..68755465bdb7775d85fa5888cc2335a88a8f6ef6 100644 (file)
@@ -437,13 +437,14 @@ static void prometheusMetrics(HttpRequest *req, HttpResponse *resp) {
 
     std::ostringstream output;
     typedef map <string, string> varmap_t;
-    varmap_t varmap = getAllStatsMap(
-            StatComponent::API); // Argument controls blacklisting of any stats. So stats-api-blacklist will be used to block returned stats.
+    
+    // Argument controls blacklisting of any stats. So
+    // stats-api-blacklist will be used to block returned stats.
+    // Second arg tells to use the prometheus names.
+    varmap_t varmap = getAllStatsMap(StatComponent::API, true);
     for (const auto &tup :  varmap) {
         std::string metricName = tup.first;
-
-        // Prometheus suggest using '_' instead of '-'
-        std::string prometheusMetricName = "pdns_recursor_" + boost::replace_all_copy(metricName, "-", "_");
+        std::string prometheusMetricName = "pdns_recursor_" + metricName;
 
         MetricDefinition metricDetails;