]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Implemented prometheus metrics-endpoint for auth
authorMischan Toosarani-Hausberger <migosch@gmail.com>
Mon, 1 Jun 2020 20:26:51 +0000 (22:26 +0200)
committerMischan Toosarani-Hausberger <migosch@gmail.com>
Fri, 5 Jun 2020 21:28:18 +0000 (23:28 +0200)
docs/http-api/index.rst
pdns/common_startup.cc
pdns/statbag.cc
pdns/statbag.hh
pdns/ws-auth.cc

index ae62df5c748c9468114822ecdc3d0595f8585506..decfd4dc26d04da79afebc9ebde981e6e572194c 100644 (file)
@@ -21,6 +21,276 @@ The following webserver related configuration items are available:
 * :ref:`setting-webserver-allow-from`: Netmasks that are allowed to connect to the webserver
 * :ref:`setting-webserver-max-bodysize`: Maximum request/response body size in megabytes
 
+
+Metrics Endpoint
+----------------
+
+The webserver exposes a metrics-endpoint that follows the `prometheus exposition-format <https://github.com/prometheus/docs/blob/master/content/docs/instrumenting/exposition_formats.md>`_ on path ``/metrics``.
+
+The metrics listed are equivalent to the variables section on the index-page of the webserver (prefixed with ``pdns_auth_`` and replacing dashes with underscores).
+
+A simple ``GET`` request will return a response similar to the following:
+
+.. http:get:: /metrics
+
+  HTTP/1.1 200 OK
+  Connection: close
+  Content-Length: 12044
+  Content-Type: text/plain
+  Server: PowerDNS/0.0.19015.0.master.ge719aae4e8
+
+  # HELP pdns_auth_corrupt_packets Number of corrupt packets received
+  # TYPE pdns_auth_corrupt_packets counter
+  pdns_auth_corrupt_packets 0
+  # HELP pdns_auth_deferred_cache_inserts Amount of cache inserts that were deferred because of maintenance
+  # TYPE pdns_auth_deferred_cache_inserts counter
+  pdns_auth_deferred_cache_inserts 0
+  # HELP pdns_auth_deferred_cache_lookup Amount of cache lookups that were deferred because of maintenance
+  # TYPE pdns_auth_deferred_cache_lookup counter
+  pdns_auth_deferred_cache_lookup 0
+  # HELP pdns_auth_deferred_packetcache_inserts Amount of packet cache inserts that were deferred because of maintenance
+  # TYPE pdns_auth_deferred_packetcache_inserts counter
+  pdns_auth_deferred_packetcache_inserts 0
+  # HELP pdns_auth_deferred_packetcache_lookup Amount of packet cache lookups that were deferred because of maintenance
+  # TYPE pdns_auth_deferred_packetcache_lookup counter
+  pdns_auth_deferred_packetcache_lookup 0
+  # HELP pdns_auth_dnsupdate_answers DNS update packets successfully answered.
+  # TYPE pdns_auth_dnsupdate_answers counter
+  pdns_auth_dnsupdate_answers 0
+  # HELP pdns_auth_dnsupdate_changes DNS update changes to records in total.
+  # TYPE pdns_auth_dnsupdate_changes counter
+  pdns_auth_dnsupdate_changes 0
+  # HELP pdns_auth_dnsupdate_queries DNS update packets received.
+  # TYPE pdns_auth_dnsupdate_queries counter
+  pdns_auth_dnsupdate_queries 0
+  # HELP pdns_auth_dnsupdate_refused DNS update packets that are refused.
+  # TYPE pdns_auth_dnsupdate_refused counter
+  pdns_auth_dnsupdate_refused 0
+  # HELP pdns_auth_incoming_notifications NOTIFY packets received.
+  # TYPE pdns_auth_incoming_notifications counter
+  pdns_auth_incoming_notifications 0
+  # HELP pdns_auth_overload_drops Queries dropped because backends overloaded
+  # TYPE pdns_auth_overload_drops counter
+  pdns_auth_overload_drops 0
+  # HELP pdns_auth_packetcache_hit Number of hits on the packet cache
+  # TYPE pdns_auth_packetcache_hit counter
+  pdns_auth_packetcache_hit 0
+  # HELP pdns_auth_packetcache_miss Number of misses on the packet cache
+  # TYPE pdns_auth_packetcache_miss counter
+  pdns_auth_packetcache_miss 0
+  # HELP pdns_auth_packetcache_size Number of entries in the packet cache
+  # TYPE pdns_auth_packetcache_size counter
+  pdns_auth_packetcache_size 0
+  # HELP pdns_auth_query_cache_hit Number of hits on the query cache
+  # TYPE pdns_auth_query_cache_hit counter
+  pdns_auth_query_cache_hit 0
+  # HELP pdns_auth_query_cache_miss Number of misses on the query cache
+  # TYPE pdns_auth_query_cache_miss counter
+  pdns_auth_query_cache_miss 0
+  # HELP pdns_auth_query_cache_size Number of entries in the query cache
+  # TYPE pdns_auth_query_cache_size counter
+  pdns_auth_query_cache_size 0
+  # HELP pdns_auth_rd_queries Number of recursion desired questions
+  # TYPE pdns_auth_rd_queries counter
+  pdns_auth_rd_queries 0
+  # HELP pdns_auth_recursing_answers Number of recursive answers sent out
+  # TYPE pdns_auth_recursing_answers counter
+  pdns_auth_recursing_answers 0
+  # HELP pdns_auth_recursing_questions Number of questions sent to recursor
+  # TYPE pdns_auth_recursing_questions counter
+  pdns_auth_recursing_questions 0
+  # HELP pdns_auth_recursion_unanswered Number of packets unanswered by configured recursor
+  # TYPE pdns_auth_recursion_unanswered counter
+  pdns_auth_recursion_unanswered 0
+  # HELP pdns_auth_security_status Security status based on regular polling
+  # TYPE pdns_auth_security_status counter
+  pdns_auth_security_status 0
+  # HELP pdns_auth_servfail_packets Number of times a server-failed packet was sent out
+  # TYPE pdns_auth_servfail_packets counter
+  pdns_auth_servfail_packets 0
+  # HELP pdns_auth_signatures Number of DNSSEC signatures made
+  # TYPE pdns_auth_signatures counter
+  pdns_auth_signatures 0
+  # HELP pdns_auth_tcp_answers Number of answers sent out over TCP
+  # TYPE pdns_auth_tcp_answers counter
+  pdns_auth_tcp_answers 0
+  # HELP pdns_auth_tcp_answers_bytes Total size of answers sent out over TCP
+  # TYPE pdns_auth_tcp_answers_bytes counter
+  pdns_auth_tcp_answers_bytes 0
+  # HELP pdns_auth_tcp_queries Number of TCP queries received
+  # TYPE pdns_auth_tcp_queries counter
+  pdns_auth_tcp_queries 0
+  # HELP pdns_auth_tcp4_answers Number of IPv4 answers sent out over TCP
+  # TYPE pdns_auth_tcp4_answers counter
+  pdns_auth_tcp4_answers 0
+  # HELP pdns_auth_tcp4_answers_bytes Total size of answers sent out over TCPv4
+  # TYPE pdns_auth_tcp4_answers_bytes counter
+  pdns_auth_tcp4_answers_bytes 0
+  # HELP pdns_auth_tcp4_queries Number of IPv4 TCP queries received
+  # TYPE pdns_auth_tcp4_queries counter
+  pdns_auth_tcp4_queries 0
+  # HELP pdns_auth_tcp6_answers Number of IPv6 answers sent out over TCP
+  # TYPE pdns_auth_tcp6_answers counter
+  pdns_auth_tcp6_answers 0
+  # HELP pdns_auth_tcp6_answers_bytes Total size of answers sent out over TCPv6
+  # TYPE pdns_auth_tcp6_answers_bytes counter
+  pdns_auth_tcp6_answers_bytes 0
+  # HELP pdns_auth_tcp6_queries Number of IPv6 TCP queries received
+  # TYPE pdns_auth_tcp6_queries counter
+  pdns_auth_tcp6_queries 0
+  # HELP pdns_auth_timedout_packets Number of packets which weren't answered within timeout set
+  # TYPE pdns_auth_timedout_packets counter
+  pdns_auth_timedout_packets 0
+  # HELP pdns_auth_udp_answers Number of answers sent out over UDP
+  # TYPE pdns_auth_udp_answers counter
+  pdns_auth_udp_answers 0
+  # HELP pdns_auth_udp_answers_bytes Total size of answers sent out over UDP
+  # TYPE pdns_auth_udp_answers_bytes counter
+  pdns_auth_udp_answers_bytes 0
+  # HELP pdns_auth_udp_do_queries Number of UDP queries received with DO bit
+  # TYPE pdns_auth_udp_do_queries counter
+  pdns_auth_udp_do_queries 0
+  # HELP pdns_auth_udp_queries Number of UDP queries received
+  # TYPE pdns_auth_udp_queries counter
+  pdns_auth_udp_queries 0
+  # HELP pdns_auth_udp4_answers Number of IPv4 answers sent out over UDP
+  # TYPE pdns_auth_udp4_answers counter
+  pdns_auth_udp4_answers 0
+  # HELP pdns_auth_udp4_answers_bytes Total size of answers sent out over UDPv4
+  # TYPE pdns_auth_udp4_answers_bytes counter
+  pdns_auth_udp4_answers_bytes 0
+  # HELP pdns_auth_udp4_queries Number of IPv4 UDP queries received
+  # TYPE pdns_auth_udp4_queries counter
+  pdns_auth_udp4_queries 0
+  # HELP pdns_auth_udp6_answers Number of IPv6 answers sent out over UDP
+  # TYPE pdns_auth_udp6_answers counter
+  pdns_auth_udp6_answers 0
+  # HELP pdns_auth_udp6_answers_bytes Total size of answers sent out over UDPv6
+  # TYPE pdns_auth_udp6_answers_bytes counter
+  pdns_auth_udp6_answers_bytes 0
+  # HELP pdns_auth_udp6_queries Number of IPv6 UDP queries received
+  # TYPE pdns_auth_udp6_queries counter
+  pdns_auth_udp6_queries 0
+  # HELP pdns_auth_cpu_iowait Time spent waiting for I/O to complete by the whole system, in units of USER_HZ
+  # TYPE pdns_auth_cpu_iowait counter
+  pdns_auth_cpu_iowait 2739
+  # HELP pdns_auth_cpu_steal Stolen time, which is the time spent by the whole system in other operating systems when running in a virtualized environment, in units of USER_HZ
+  # TYPE pdns_auth_cpu_steal counter
+  pdns_auth_cpu_steal 0
+  # HELP pdns_auth_fd_usage Number of open filedescriptors
+  # TYPE pdns_auth_fd_usage gauge
+  pdns_auth_fd_usage 26
+  # HELP pdns_auth_key_cache_size Number of entries in the key cache
+  # TYPE pdns_auth_key_cache_size gauge
+  pdns_auth_key_cache_size 0
+  # HELP pdns_auth_latency Average number of microseconds needed to answer a question
+  # TYPE pdns_auth_latency gauge
+  pdns_auth_latency 0
+  # HELP pdns_auth_meta_cache_size Number of entries in the metadata cache
+  # TYPE pdns_auth_meta_cache_size gauge
+  pdns_auth_meta_cache_size 0
+  # HELP pdns_auth_open_tcp_connections Number of currently open TCP connections
+  # TYPE pdns_auth_open_tcp_connections gauge
+  pdns_auth_open_tcp_connections 0
+  # HELP pdns_auth_qsize_q Number of questions waiting for database attention
+  # TYPE pdns_auth_qsize_q gauge
+  pdns_auth_qsize_q 0
+  # HELP pdns_auth_real_memory_usage Actual unique use of memory in bytes (approx)
+  # TYPE pdns_auth_real_memory_usage gauge
+  pdns_auth_real_memory_usage 133189632
+  # HELP pdns_auth_ring_logmessages_capacity Maximum number of entries in the logmessages ring
+  # TYPE pdns_auth_ring_logmessages_capacity counter
+  pdns_auth_ring_logmessages_capacity 10000
+  # HELP pdns_auth_ring_logmessages_size Number of entries in the logmessages ring
+  # TYPE pdns_auth_ring_logmessages_size counter
+  pdns_auth_ring_logmessages_size 7
+  # HELP pdns_auth_ring_noerror_queries_capacity Maximum number of entries in the noerror-queries ring
+  # TYPE pdns_auth_ring_noerror_queries_capacity counter
+  pdns_auth_ring_noerror_queries_capacity 10000
+  # HELP pdns_auth_ring_noerror_queries_size Number of entries in the noerror-queries ring
+  # TYPE pdns_auth_ring_noerror_queries_size counter
+  pdns_auth_ring_noerror_queries_size 0
+  # HELP pdns_auth_ring_nxdomain_queries_capacity Maximum number of entries in the nxdomain-queries ring
+  # TYPE pdns_auth_ring_nxdomain_queries_capacity counter
+  pdns_auth_ring_nxdomain_queries_capacity 10000
+  # HELP pdns_auth_ring_nxdomain_queries_size Number of entries in the nxdomain-queries ring
+  # TYPE pdns_auth_ring_nxdomain_queries_size counter
+  pdns_auth_ring_nxdomain_queries_size 0
+  # HELP pdns_auth_ring_queries_capacity Maximum number of entries in the queries ring
+  # TYPE pdns_auth_ring_queries_capacity counter
+  pdns_auth_ring_queries_capacity 10000
+  # HELP pdns_auth_ring_queries_size Number of entries in the queries ring
+  # TYPE pdns_auth_ring_queries_size counter
+  pdns_auth_ring_queries_size 0
+  # HELP pdns_auth_ring_remotes_capacity Maximum number of entries in the remotes ring
+  # TYPE pdns_auth_ring_remotes_capacity counter
+  pdns_auth_ring_remotes_capacity 10000
+  # HELP pdns_auth_ring_remotes_corrupt_capacity Maximum number of entries in the remotes-corrupt ring
+  # TYPE pdns_auth_ring_remotes_corrupt_capacity counter
+  pdns_auth_ring_remotes_corrupt_capacity 10000
+  # HELP pdns_auth_ring_remotes_corrupt_size Number of entries in the remotes-corrupt ring
+  # TYPE pdns_auth_ring_remotes_corrupt_size counter
+  pdns_auth_ring_remotes_corrupt_size 0
+  # HELP pdns_auth_ring_remotes_size Number of entries in the remotes ring
+  # TYPE pdns_auth_ring_remotes_size counter
+  pdns_auth_ring_remotes_size 0
+  # HELP pdns_auth_ring_remotes_unauth_capacity Maximum number of entries in the remotes-unauth ring
+  # TYPE pdns_auth_ring_remotes_unauth_capacity counter
+  pdns_auth_ring_remotes_unauth_capacity 10000
+  # HELP pdns_auth_ring_remotes_unauth_size Number of entries in the remotes-unauth ring
+  # TYPE pdns_auth_ring_remotes_unauth_size counter
+  pdns_auth_ring_remotes_unauth_size 0
+  # HELP pdns_auth_ring_servfail_queries_capacity Maximum number of entries in the servfail-queries ring
+  # TYPE pdns_auth_ring_servfail_queries_capacity counter
+  pdns_auth_ring_servfail_queries_capacity 10000
+  # HELP pdns_auth_ring_servfail_queries_size Number of entries in the servfail-queries ring
+  # TYPE pdns_auth_ring_servfail_queries_size counter
+  pdns_auth_ring_servfail_queries_size 0
+  # HELP pdns_auth_ring_unauth_queries_capacity Maximum number of entries in the unauth-queries ring
+  # TYPE pdns_auth_ring_unauth_queries_capacity counter
+  pdns_auth_ring_unauth_queries_capacity 10000
+  # HELP pdns_auth_ring_unauth_queries_size Number of entries in the unauth-queries ring
+  # TYPE pdns_auth_ring_unauth_queries_size counter
+  pdns_auth_ring_unauth_queries_size 0
+  # HELP pdns_auth_signature_cache_size Number of entries in the signature cache
+  # TYPE pdns_auth_signature_cache_size gauge
+  pdns_auth_signature_cache_size 0
+  # HELP pdns_auth_sys_msec Number of msec spent in system time
+  # TYPE pdns_auth_sys_msec counter
+  pdns_auth_sys_msec 56
+  # HELP pdns_auth_udp_in_errors UDP 'in' errors
+  # TYPE pdns_auth_udp_in_errors counter
+  pdns_auth_udp_in_errors 151
+  # HELP pdns_auth_udp_noport_errors UDP 'noport' errors
+  # TYPE pdns_auth_udp_noport_errors counter
+  pdns_auth_udp_noport_errors 9
+  # HELP pdns_auth_udp_recvbuf_errors UDP 'recvbuf' errors
+  # TYPE pdns_auth_udp_recvbuf_errors counter
+  pdns_auth_udp_recvbuf_errors 0
+  # HELP pdns_auth_udp_sndbuf_errors UDP 'sndbuf' errors
+  # TYPE pdns_auth_udp_sndbuf_errors counter
+  pdns_auth_udp_sndbuf_errors 9
+  # HELP pdns_auth_uptime Uptime of process in seconds
+  # TYPE pdns_auth_uptime counter
+  pdns_auth_uptime 672
+  # HELP pdns_auth_user_msec Number of msec spent in user time
+  # TYPE pdns_auth_user_msec counter
+  pdns_auth_user_msec 48
+
+
+Prometheus can then be configured to scrape metrics from this endpoint using a simple job description like the following:
+
+.. prometheus scrape-job::
+
+  scrape_configs:
+    - job_name: 'pdns_auth'
+      scrape_interval: 1m
+      static_configs:
+        - targets: ['pdns_auth_host:pdns_auth_ws_port'] 
+
+Further details can be gathered from the `prometheus docs <https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config>`_.
+
+
 Enabling the API
 ----------------
 
index f5a777c1435c59713b50dc6a80e280ba5982915f..1c67740d2200b6de91cf43df72d7c5cdf928c648 100644 (file)
@@ -333,9 +333,9 @@ void declareStats(void)
   S.declare("tcp6-queries","Number of IPv6 TCP queries received");
   S.declare("tcp6-answers","Number of IPv6 answers sent out over TCP");
 
-  S.declare("open-tcp-connections","Number of currently open TCP connections", getTCPConnectionCount);;
+  S.declare("open-tcp-connections","Number of currently open TCP connections", getTCPConnectionCount, StatType::gauge);
 
-  S.declare("qsize-q","Number of questions waiting for database attention", getQCount);
+  S.declare("qsize-q","Number of questions waiting for database attention", getQCount, StatType::gauge);
 
   S.declare("dnsupdate-queries", "DNS update packets received.");
   S.declare("dnsupdate-answers", "DNS update packets successfully answered.");
@@ -344,31 +344,31 @@ void declareStats(void)
 
   S.declare("incoming-notifications", "NOTIFY packets received.");
 
-  S.declare("uptime", "Uptime of process in seconds", uptimeOfProcess);
-  S.declare("real-memory-usage", "Actual unique use of memory in bytes (approx)", getRealMemoryUsage);
-  S.declare("special-memory-usage", "Actual unique use of memory in bytes (approx)", getSpecialMemoryUsage);
-  S.declare("fd-usage", "Number of open filedescriptors", getOpenFileDescriptors);
+  S.declare("uptime", "Uptime of process in seconds", uptimeOfProcess, StatType::counter);
+  S.declare("real-memory-usage", "Actual unique use of memory in bytes (approx)", getRealMemoryUsage, StatType::gauge);
+  S.declare("special-memory-usage", "Actual unique use of memory in bytes (approx)", getSpecialMemoryUsage, StatType::gauge);
+  S.declare("fd-usage", "Number of open filedescriptors", getOpenFileDescriptors, StatType::gauge);
 #ifdef __linux__
-  S.declare("udp-recvbuf-errors", "UDP 'recvbuf' errors", udpErrorStats);
-  S.declare("udp-sndbuf-errors", "UDP 'sndbuf' errors", udpErrorStats);
-  S.declare("udp-noport-errors", "UDP 'noport' errors", udpErrorStats);
-  S.declare("udp-in-errors", "UDP 'in' errors", udpErrorStats);
+  S.declare("udp-recvbuf-errors", "UDP 'recvbuf' errors", udpErrorStats, StatType::counter);
+  S.declare("udp-sndbuf-errors", "UDP 'sndbuf' errors", udpErrorStats, StatType::counter);
+  S.declare("udp-noport-errors", "UDP 'noport' errors", udpErrorStats, StatType::counter);
+  S.declare("udp-in-errors", "UDP 'in' errors", udpErrorStats, StatType::counter);
 #endif
 
-  S.declare("sys-msec", "Number of msec spent in system time", getSysUserTimeMsec);
-  S.declare("user-msec", "Number of msec spent in user time", getSysUserTimeMsec);
+  S.declare("sys-msec", "Number of msec spent in system time", getSysUserTimeMsec, StatType::counter);
+  S.declare("user-msec", "Number of msec spent in user time", getSysUserTimeMsec, StatType::counter);
 
 #ifdef __linux__
-  S.declare("cpu-iowait", "Time spent waiting for I/O to complete by the whole system, in units of USER_HZ", getCPUIOWait);
-  S.declare("cpu-steal", "Stolen time, which is the time spent by the whole system in other operating systems when running in a virtualized environment, in units of USER_HZ", getCPUSteal);
+  S.declare("cpu-iowait", "Time spent waiting for I/O to complete by the whole system, in units of USER_HZ", getCPUIOWait, StatType::counter);
+  S.declare("cpu-steal", "Stolen time, which is the time spent by the whole system in other operating systems when running in a virtualized environment, in units of USER_HZ", getCPUSteal, StatType::counter);
 #endif
 
-  S.declare("meta-cache-size", "Number of entries in the metadata cache", DNSSECKeeper::dbdnssecCacheSizes);
-  S.declare("key-cache-size", "Number of entries in the key cache", DNSSECKeeper::dbdnssecCacheSizes);
-  S.declare("signature-cache-size", "Number of entries in the signature cache", signatureCacheSize);
+  S.declare("meta-cache-size", "Number of entries in the metadata cache", DNSSECKeeper::dbdnssecCacheSizes, StatType::gauge);
+  S.declare("key-cache-size", "Number of entries in the key cache", DNSSECKeeper::dbdnssecCacheSizes, StatType::gauge);
+  S.declare("signature-cache-size", "Number of entries in the signature cache", signatureCacheSize, StatType::gauge);
 
   S.declare("servfail-packets","Number of times a server-failed packet was sent out");
-  S.declare("latency","Average number of microseconds needed to answer a question", getLatency);
+  S.declare("latency","Average number of microseconds needed to answer a question", getLatency, StatType::gauge);
   S.declare("timedout-packets","Number of packets which weren't answered within timeout set");
   S.declare("security-status", "Security status based on regular polling");
   S.declareDNSNameQTypeRing("queries","UDP Queries Received");
index 9d89d15b774294904e8450527ac8a99bb35bb916..3dd5a8de123bf54afd226b7ba78e47014688eac4 100644 (file)
@@ -97,18 +97,25 @@ string StatBag::getDescrip(const string &item)
   return d_keyDescrips[item];
 }
 
+StatType StatBag::getStatType(const string &item)
+{
+  exists(item);
+  return d_statTypes[item];
+}
+
 void StatBag::declare(const string &key, const string &descrip)
 {
   auto i=make_unique<AtomicCounter>(0);
   d_stats[key]=std::move(i);
   d_keyDescrips[key]=descrip;
+  d_statTypes[key]=StatType::counter;
 }
 
-void StatBag::declare(const string &key, const string &descrip, StatBag::func_t func)
+void StatBag::declare(const string &key, const string &descrip, StatBag::func_t func, StatType statType)
 {
-
   d_funcstats[key]=func;
   d_keyDescrips[key]=descrip;
+  d_statTypes[key]=statType;
 }
 
           
@@ -237,8 +244,8 @@ vector<pair<T, unsigned int> >StatRing<T,Comp>::get() const
 
 void StatBag::registerRingStats(const string& name)
 {
-  declare("ring-" + name + "-size", "Number of entries in the " + name + " ring", [this,name](const std::string&) { return static_cast<uint64_t>(getRingEntriesCount(name)); });
-  declare("ring-" + name + "-capacity", "Maximum number of entries in the " + name + " ring", [this,name](const std::string&) { return static_cast<uint64_t>(getRingSize(name)); });
+  declare("ring-" + name + "-size", "Number of entries in the " + name + " ring", [this,name](const std::string&) { return static_cast<uint64_t>(getRingEntriesCount(name)); }, StatType::counter);
+  declare("ring-" + name + "-capacity", "Maximum number of entries in the " + name + " ring", [this,name](const std::string&) { return static_cast<uint64_t>(getRingSize(name)); }, StatType::counter);
 }
 
 void StatBag::declareRing(const string &name, const string &help, unsigned int size)
index 982f739dfbe43b5f0ac6554150486936eb6358df..3026912590734030c653b7a070f32591cd07f2ed 100644 (file)
@@ -62,12 +62,17 @@ private:
   string d_help;
 };
 
+enum class StatType : uint8_t {
+  counter = 1,
+  gauge = 2,
+};
 
 //! use this to gather and query statistics
 class StatBag
 {
   map<string, std::unique_ptr<AtomicCounter>> d_stats;
   map<string, string> d_keyDescrips;
+  map<string, StatType> d_statTypes;
   map<string,StatRing<string, CIStringCompare> >d_rings;
   map<string,StatRing<SComboAddress> >d_comboRings;
   map<string,StatRing<std::tuple<DNSName, QType> > >d_dnsnameqtyperings;
@@ -83,7 +88,7 @@ public:
   StatBag(); //!< Naked constructor. You need to declare keys before this class becomes useful
   ~StatBag();
   void declare(const string &key, const string &descrip=""); //!< Before you can store or access a key, you need to declare it
-  void declare(const string &key, const string &descrip, func_t func); //!< Before you can store or access a key, you need to declare it
+  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
 
   void declareRing(const string &name, const string &title, unsigned int size=10000);
   void declareComboRing(const string &name, const string &help, unsigned int size=10000);
@@ -131,6 +136,7 @@ public:
   string directory(); //!< Returns a list of all data stored
   vector<string> getEntries(); //!< returns a vector with datums (items)
   string getDescrip(const string &item); //!< Returns the description of this datum/item
+  StatType getStatType(const string &item); //!< Returns the stats type for the metrics endpoint
   void exists(const string &key); //!< call this function to throw an exception in case a key does not exist
   inline void deposit(const string &key, int value); //!< increment the statistics behind this key by value amount
   inline void inc(const string &key); //!< increase this key's value by one
index de5fa008405e1a019be87da67208bb0fec535081..864a1b586e34a23986f39a49185bfbc7f415de7b 100644 (file)
@@ -2253,6 +2253,35 @@ static void apiServerCacheFlush(HttpRequest* req, HttpResponse* resp) {
   });
 }
 
+static std::ostream& operator<<(std::ostream& os, StatType statType)
+{
+  switch (statType)
+  {
+    case StatType::counter: return os << "counter";
+    case StatType::gauge: return os << "gauge";
+  };
+  return os << static_cast<uint16_t>(statType);
+}
+
+static void prometheusMetrics(HttpRequest* req, HttpResponse* resp) {
+  if (req->method != "GET")
+    throw HttpMethodNotAllowedException();
+
+  std::ostringstream output;
+  for (const auto &metricName : S.getEntries()) {
+    // Prometheus suggest using '_' instead of '-'
+    std::string prometheusMetricName = "pdns_auth_" + boost::replace_all_copy(metricName, "-", "_");
+
+    output << "# HELP " << prometheusMetricName << " " << S.getDescrip(metricName) << "\n";
+    output << "# TYPE " << prometheusMetricName << " " << S.getStatType(metricName) << "\n";
+    output << prometheusMetricName << " " << S.read(metricName) << "\n";
+  }
+
+  resp->body = output.str();
+  resp->headers["Content-Type"] = "text/plain";
+  resp->status = 200;
+}
+
 void AuthWebServer::cssfunction(HttpRequest* req, HttpResponse* resp)
 {
   resp->headers["Cache-Control"] = "max-age=86400";
@@ -2317,6 +2346,7 @@ void AuthWebServer::webThread()
     if (::arg().mustDo("webserver")) {
       d_ws->registerWebHandler("/style.css", std::bind(&AuthWebServer::cssfunction, this, std::placeholders::_1, std::placeholders::_2));
       d_ws->registerWebHandler("/", std::bind(&AuthWebServer::indexfunction, this, std::placeholders::_1, std::placeholders::_2));
+      d_ws->registerWebHandler("/metrics", prometheusMetrics);
     }
     d_ws->go();
   }