#ifdef LUAJIT_VERSION
#include "dnsdist-lua-ffi.hh"
#endif /* LUAJIT_VERSION */
+#include "dnsdist-metrics.hh"
#include "dnsdist-nghttp2.hh"
#include "dnsdist-proxy-protocol.hh"
#include "dnsdist-rings.hh"
});
luaCtx.writeFunction("declareMetric", [](const std::string& name, const std::string& type, const std::string& description, boost::optional<std::string> customName) {
- if (!std::regex_match(name, std::regex("^[a-z0-9-]+$"))) {
- g_outputBuffer = "Unable to declare metric '" + name + "': invalid name\n";
- errlog("Unable to declare metric '%s': invalid name", name);
- return false;
- }
- if (type == "counter") {
- auto customCounters = g_stats.customCounters.write_lock();
- auto itp = customCounters->insert({name, DNSDistStats::MutableCounter()});
- if (itp.second) {
- g_stats.entries.write_lock()->emplace_back(DNSDistStats::EntryPair{name, &(*customCounters)[name].d_value});
- addMetricDefinition(name, "counter", description, customName ? *customName : "");
- }
- }
- else if (type == "gauge") {
- auto customGauges = g_stats.customGauges.write_lock();
- auto itp = customGauges->insert({name, DNSDistStats::MutableGauge()});
- if (itp.second) {
- g_stats.entries.write_lock()->emplace_back(DNSDistStats::EntryPair{name, &(*customGauges)[name].d_value});
- addMetricDefinition(name, "gauge", description, customName ? *customName : "");
- }
- }
- else {
- g_outputBuffer = "declareMetric unknown type '" + type + "'\n";
- errlog("Unable to declareMetric '%s': no such type '%s'", name, type);
+ auto result = dnsdist::metrics::declareCustomMetric(name, type, description, customName ? std::optional<std::string>(*customName) : std::nullopt);
+ if (result) {
+ g_outputBuffer += *result + "\n";
+ errlog("%s", *result);
return false;
}
return true;
});
luaCtx.writeFunction("incMetric", [](const std::string& name, boost::optional<uint64_t> step) {
- auto customCounters = g_stats.customCounters.read_lock();
- auto metric = customCounters->find(name);
- if (metric != customCounters->end()) {
- if (step) {
- metric->second.d_value += *step;
- return metric->second.d_value.load();
- }
- return ++(metric->second.d_value);
+ auto result = dnsdist::metrics::incrementCustomCounter(name, step ? *step : 1);
+ if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ g_outputBuffer = *errorStr + "'\n";
+ errlog("%s", *errorStr);
+ return static_cast<uint64_t>(0);
}
- g_outputBuffer = "incMetric no such metric '" + name + "'\n";
- errlog("Unable to incMetric: no such name '%s'", name);
- return (uint64_t)0;
+ return std::get<uint64_t>(result);
});
- luaCtx.writeFunction("decMetric", [](const std::string& name) {
- auto customCounters = g_stats.customCounters.read_lock();
- auto metric = customCounters->find(name);
- if (metric != customCounters->end()) {
- return --(metric->second.d_value);
+ luaCtx.writeFunction("decMetric", [](const std::string& name, boost::optional<uint64_t> step) {
+ auto result = dnsdist::metrics::decrementCustomCounter(name, step ? *step : 1);
+ if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ g_outputBuffer = *errorStr + "'\n";
+ errlog("%s", *errorStr);
+ return static_cast<uint64_t>(0);
}
- g_outputBuffer = "decMetric no such metric '" + name + "'\n";
- errlog("Unable to decMetric: no such name '%s'", name);
- return (uint64_t)0;
+ return std::get<uint64_t>(result);
});
luaCtx.writeFunction("setMetric", [](const std::string& name, const double value) -> double {
- {
- auto customGauges = g_stats.customGauges.read_lock();
- auto metric = customGauges->find(name);
- if (metric != customGauges->end()) {
- metric->second.d_value = value;
- return value;
- }
+ auto result = dnsdist::metrics::setCustomGauge(name, value);
+ if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ g_outputBuffer = *errorStr + "'\n";
+ errlog("%s", *errorStr);
+ return 0.;
}
- g_outputBuffer = "setMetric no such metric '" + name + "'\n";
- errlog("Unable to setMetric: no such name '%s'", name);
- return 0.;
+ return std::get<double>(result);
});
luaCtx.writeFunction("getMetric", [](const std::string& name) {
- {
- auto customCounters = g_stats.customCounters.read_lock();
- auto counter = customCounters->find(name);
- if (counter != customCounters->end()) {
- return (double)counter->second.d_value.load();
- }
- }
- {
- auto customGauges = g_stats.customGauges.read_lock();
- auto gauge = customGauges->find(name);
- if (gauge != customGauges->end()) {
- return gauge->second.d_value.load();
- }
+ auto result = dnsdist::metrics::getCustomMetric(name);
+ if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ g_outputBuffer = *errorStr + "'\n";
+ errlog("%s", *errorStr);
+ return 0.;
}
- g_outputBuffer = "getMetric no such metric '" + name + "'\n";
- errlog("Unable to getMetric: no such name '%s'", name);
- return 0.;
+ return std::get<double>(result);
});
}
dnsdist-lua-web.cc \
dnsdist-lua.cc dnsdist-lua.hh \
dnsdist-mac-address.cc dnsdist-mac-address.hh \
+ dnsdist-metrics.cc dnsdist-metrics.hh \
dnsdist-nghttp2.cc dnsdist-nghttp2.hh \
dnsdist-prometheus.hh \
dnsdist-protobuf.cc dnsdist-protobuf.hh \
dnsdist-lua-network.cc dnsdist-lua-network.hh \
dnsdist-lua-vars.cc \
dnsdist-mac-address.cc dnsdist-mac-address.hh \
+ dnsdist-metrics.cc dnsdist-metrics.hh \
dnsdist-nghttp2.cc dnsdist-nghttp2.hh \
dnsdist-protocols.cc dnsdist-protocols.hh \
dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
size_t dnsdist_ffi_dnspacket_get_name_at_offset_raw(const char* packet, size_t packetSize, size_t offset, char* name, size_t nameSize) __attribute__ ((visibility ("default")));
void dnsdist_ffi_dnspacket_free(dnsdist_ffi_dnspacket_t*) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_metric_declare(const char* name, size_t nameLen, const char* type, const char* description, const char* customName) __attribute__ ((visibility ("default")));
void dnsdist_ffi_metric_inc(const char* metricName, size_t metricNameLen) __attribute__ ((visibility ("default")));
void dnsdist_ffi_metric_inc_by(const char* metricName, size_t metricNameLen, uint64_t value) __attribute__ ((visibility ("default")));
void dnsdist_ffi_metric_dec(const char* metricName, size_t metricNameLen) __attribute__ ((visibility ("default")));
#include "dnsdist-ecs.hh"
#include "dnsdist-lua-ffi.hh"
#include "dnsdist-mac-address.hh"
+#include "dnsdist-metrics.hh"
#include "dnsdist-lua-network.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-ecs.hh"
}
}
+bool dnsdist_ffi_metric_declare(const char* name, size_t nameLen, const char* type, const char* description, const char* customName)
+{
+ if (name == nullptr || nameLen == 0 || type == nullptr || description == nullptr) {
+ return false;
+ }
+ auto result = dnsdist::metrics::declareCustomMetric(name, type, description, customName ? std::optional<std::string>(customName) : std::nullopt);
+ if (result) {
+ return false;
+ }
+ return true;
+}
+
void dnsdist_ffi_metric_inc(const char* metricName, size_t metricNameLen)
{
- auto customCounters = g_stats.customCounters.read_lock();
- auto metric = customCounters->find(std::string_view(metricName, metricNameLen));
- if (metric != customCounters->end()) {
- ++metric->second.d_value;
+ auto result = dnsdist::metrics::incrementCustomCounter(std::string_view(metricName, metricNameLen), 1U);
+ if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ return;
}
}
void dnsdist_ffi_metric_inc_by(const char* metricName, size_t metricNameLen, uint64_t value)
{
- auto customCounters = g_stats.customCounters.write_lock();
- auto metric = customCounters->find(std::string_view(metricName, metricNameLen));
- if (metric != customCounters->end()) {
- metric->second.d_value += value;
+ auto result = dnsdist::metrics::incrementCustomCounter(std::string_view(metricName, metricNameLen), value);
+ if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ return;
}
}
void dnsdist_ffi_metric_dec(const char* metricName, size_t metricNameLen)
{
- auto customCounters = g_stats.customCounters.read_lock();
- auto metric = customCounters->find(std::string_view(metricName, metricNameLen));
- if (metric != customCounters->end()) {
- --metric->second.d_value;
+ auto result = dnsdist::metrics::decrementCustomCounter(std::string_view(metricName, metricNameLen), 1U);
+ if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ return;
}
}
void dnsdist_ffi_metric_set(const char* metricName, size_t metricNameLen, double value)
{
- auto customGauges = g_stats.customGauges.read_lock();
- auto metric = customGauges->find(std::string_view(metricName, metricNameLen));
- if (metric != customGauges->end()) {
- metric->second.d_value = value;
+ auto result = dnsdist::metrics::setCustomGauge(std::string_view(metricName, metricNameLen), value);
+ if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ return;
}
}
double dnsdist_ffi_metric_get(const char* metricName, size_t metricNameLen, bool isCounter)
{
- auto name = std::string_view(metricName, metricNameLen);
- if (isCounter) {
- auto customCounters = g_stats.customCounters.read_lock();
- auto counter = customCounters->find(name);
- if (counter != customCounters->end()) {
- return (double)counter->second.d_value.load();
- }
- }
- else {
- auto customGauges = g_stats.customGauges.read_lock();
- auto gauge = customGauges->find(name);
- if (gauge != customGauges->end()) {
- return gauge->second.d_value.load();
- }
+ auto result = dnsdist::metrics::getCustomMetric(std::string_view(metricName, metricNameLen));
+ if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ return 0.;
}
- return 0.;
+ return std::get<double>(result);
}
const char* dnsdist_ffi_network_message_get_payload(const dnsdist_ffi_network_message_t* msg)
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <regex>
+
+#include "dnsdist-metrics.hh"
+#include "dnsdist.hh"
+#include "dnsdist-web.hh"
+
+namespace dnsdist::metrics {
+
+std::optional<std::string> declareCustomMetric(const std::string& name, const std::string& type, const std::string& description, std::optional<std::string> customName)
+{
+ if (!std::regex_match(name, std::regex("^[a-z0-9-]+$"))) {
+ return std::string("Unable to declare metric '") + std::string(name) + std::string("': invalid name\n");
+ }
+
+ if (type == "counter") {
+ auto customCounters = g_stats.customCounters.write_lock();
+ auto itp = customCounters->insert({name, DNSDistStats::MutableCounter()});
+ if (itp.second) {
+ g_stats.entries.write_lock()->emplace_back(DNSDistStats::EntryPair{name, &(*customCounters)[name].d_value});
+ addMetricDefinition(name, "counter", description, customName ? *customName : "");
+ }
+ }
+ else if (type == "gauge") {
+ auto customGauges = g_stats.customGauges.write_lock();
+ auto itp = customGauges->insert({name, DNSDistStats::MutableGauge()});
+ if (itp.second) {
+ g_stats.entries.write_lock()->emplace_back(DNSDistStats::EntryPair{name, &(*customGauges)[name].d_value});
+ addMetricDefinition(name, "gauge", description, customName ? *customName : "");
+ }
+ }
+ else {
+ return std::string("Unable to declare metric: unknown type '") + type + "'";
+ }
+ return std::nullopt;
+}
+
+std::variant<uint64_t, Error> incrementCustomCounter(const std::string_view& name, uint64_t step)
+{
+ auto customCounters = g_stats.customCounters.read_lock();
+ auto metric = customCounters->find(name);
+ if (metric != customCounters->end()) {
+ if (step) {
+ metric->second.d_value += step;
+ return metric->second.d_value.load();
+ }
+ return ++(metric->second.d_value);
+ }
+ return std::string("Unable to increment custom metric '") + std::string(name) + "': no such metric";
+}
+
+std::variant<uint64_t, Error> decrementCustomCounter(const std::string_view& name, uint64_t step)
+{
+ auto customCounters = g_stats.customCounters.read_lock();
+ auto metric = customCounters->find(name);
+ if (metric != customCounters->end()) {
+ if (step) {
+ metric->second.d_value -= step;
+ return metric->second.d_value.load();
+ }
+ return --(metric->second.d_value);
+ }
+ return std::string("Unable to decrement custom metric '") + std::string(name) + "': no such metric";
+}
+
+std::variant<double, Error> setCustomGauge(const std::string_view& name, const double value)
+{
+ auto customGauges = g_stats.customGauges.read_lock();
+ auto metric = customGauges->find(name);
+ if (metric != customGauges->end()) {
+ metric->second.d_value = value;
+ return value;
+ }
+
+ return std::string("Unable to set metric '") + std::string(name) + "': no such metric";
+}
+
+std::variant<double, Error> getCustomMetric(const std::string_view& name)
+{
+ {
+ auto customCounters = g_stats.customCounters.read_lock();
+ auto counter = customCounters->find(name);
+ if (counter != customCounters->end()) {
+ return static_cast<double>(counter->second.d_value.load());
+ }
+ }
+ {
+ auto customGauges = g_stats.customGauges.read_lock();
+ auto gauge = customGauges->find(name);
+ if (gauge != customGauges->end()) {
+ return gauge->second.d_value.load();
+ }
+ }
+ return std::string("Unable to get metric '") + std::string(name) + "': no such metric";
+}
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include <cinttypes>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <variant>
+
+namespace dnsdist::metrics
+{
+ using Error = std::string;
+
+ [[nodiscard]] std::optional<Error> declareCustomMetric(const std::string& name, const std::string& type, const std::string& description, std::optional<std::string> customName);
+ [[nodiscard]] std::variant<uint64_t, Error> incrementCustomCounter(const std::string_view& name, uint64_t step);
+ [[nodiscard]] std::variant<uint64_t, Error> decrementCustomCounter(const std::string_view& name, uint64_t step);
+ [[nodiscard]] std::variant<double, Error> setCustomGauge(const std::string_view& name, const double value);
+ [[nodiscard]] std::variant<double, Error> getCustomMetric(const std::string_view& name);
+}
.. versionadded:: 1.8.0
- Decrement counter by one, will issue an error if the metric is not declared or not a ``counter``
+ .. versionchanged:: 1.8.1
+ Optional ``step`` parameter added.
+
+ Decrement counter by one (or more, see the ``step`` parameter), will issue an error if the metric is not declared or not a ``counter``
Return the new value
:param str name: The name of the metric
+ :param int step: By how much the counter should be decremented, default to 1.
.. function:: getMetric(name) -> double
#include "dnsparser.hh"
#include "dnswriter.hh"
+bool addMetricDefinition(const std::string& name, const std::string& type, const std::string& description, const std::string& customPrometheusName)
+{
+ return true;
+}
+
BOOST_AUTO_TEST_SUITE(test_dnsdist_lua_ffi)
BOOST_AUTO_TEST_CASE(test_Query)