2019-11-24 15:43:53 +00:00
|
|
|
#include "PrometheusMetricsWriter.h"
|
|
|
|
|
|
|
|
#include <IO/WriteHelpers.h>
|
2020-03-16 10:32:23 +00:00
|
|
|
#include <Common/StatusInfo.h>
|
2022-08-27 20:27:47 +00:00
|
|
|
#include <regex> /// TODO: this library is harmful.
|
|
|
|
#include <algorithm>
|
|
|
|
|
2019-11-24 15:43:53 +00:00
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
2019-11-24 20:03:09 +00:00
|
|
|
template <typename T>
|
2019-11-24 15:43:53 +00:00
|
|
|
void writeOutLine(DB::WriteBuffer & wb, T && val)
|
|
|
|
{
|
|
|
|
DB::writeText(std::forward<T>(val), wb);
|
|
|
|
DB::writeChar('\n', wb);
|
|
|
|
}
|
|
|
|
|
2019-11-24 20:03:09 +00:00
|
|
|
template <typename T, typename... TArgs>
|
2019-11-24 15:43:53 +00:00
|
|
|
void writeOutLine(DB::WriteBuffer & wb, T && val, TArgs &&... args)
|
|
|
|
{
|
|
|
|
DB::writeText(std::forward<T>(val), wb);
|
|
|
|
DB::writeChar(' ', wb);
|
|
|
|
writeOutLine(wb, std::forward<TArgs>(args)...);
|
|
|
|
}
|
|
|
|
|
2021-07-09 16:12:26 +00:00
|
|
|
/// Returns false if name is not valid
|
|
|
|
bool replaceInvalidChars(std::string & metric_name)
|
2019-12-21 17:47:44 +00:00
|
|
|
{
|
2021-07-09 16:12:26 +00:00
|
|
|
/// dirty solution
|
|
|
|
metric_name = std::regex_replace(metric_name, std::regex("[^a-zA-Z0-9_:]"), "_");
|
|
|
|
metric_name = std::regex_replace(metric_name, std::regex("^[^a-zA-Z]*"), "");
|
|
|
|
return !metric_name.empty();
|
2019-12-21 17:47:44 +00:00
|
|
|
}
|
|
|
|
|
2022-08-27 20:27:47 +00:00
|
|
|
void convertHelpToSingleLine(std::string & help)
|
|
|
|
{
|
|
|
|
std::replace(help.begin(), help.end(), '\n', ' ');
|
|
|
|
}
|
|
|
|
|
2019-11-24 15:43:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
PrometheusMetricsWriter::PrometheusMetricsWriter(
|
2019-11-26 20:27:24 +00:00
|
|
|
const Poco::Util::AbstractConfiguration & config, const std::string & config_name,
|
|
|
|
const AsynchronousMetrics & async_metrics_)
|
|
|
|
: async_metrics(async_metrics_)
|
|
|
|
, send_events(config.getBool(config_name + ".events", true))
|
2019-11-24 15:43:53 +00:00
|
|
|
, send_metrics(config.getBool(config_name + ".metrics", true))
|
2019-11-26 20:27:24 +00:00
|
|
|
, send_asynchronous_metrics(config.getBool(config_name + ".asynchronous_metrics", true))
|
2020-03-11 15:30:02 +00:00
|
|
|
, send_status_info(config.getBool(config_name + ".status_info", true))
|
2019-11-24 15:43:53 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-11-24 20:03:09 +00:00
|
|
|
void PrometheusMetricsWriter::write(WriteBuffer & wb) const
|
2019-11-24 15:43:53 +00:00
|
|
|
{
|
|
|
|
if (send_events)
|
|
|
|
{
|
|
|
|
for (size_t i = 0, end = ProfileEvents::end(); i < end; ++i)
|
|
|
|
{
|
|
|
|
const auto counter = ProfileEvents::global_counters[i].load(std::memory_order_relaxed);
|
|
|
|
|
2019-12-04 07:54:09 +00:00
|
|
|
std::string metric_name{ProfileEvents::getName(static_cast<ProfileEvents::Event>(i))};
|
2019-11-24 15:43:53 +00:00
|
|
|
std::string metric_doc{ProfileEvents::getDocumentation(static_cast<ProfileEvents::Event>(i))};
|
|
|
|
|
2022-08-27 20:27:47 +00:00
|
|
|
convertHelpToSingleLine(metric_doc);
|
|
|
|
|
2021-07-09 16:12:26 +00:00
|
|
|
if (!replaceInvalidChars(metric_name))
|
|
|
|
continue;
|
2019-11-24 15:43:53 +00:00
|
|
|
std::string key{profile_events_prefix + metric_name};
|
|
|
|
|
|
|
|
writeOutLine(wb, "# HELP", key, metric_doc);
|
|
|
|
writeOutLine(wb, "# TYPE", key, "counter");
|
|
|
|
writeOutLine(wb, key, counter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (send_metrics)
|
|
|
|
{
|
|
|
|
for (size_t i = 0, end = CurrentMetrics::end(); i < end; ++i)
|
|
|
|
{
|
|
|
|
const auto value = CurrentMetrics::values[i].load(std::memory_order_relaxed);
|
|
|
|
|
2019-12-04 07:54:09 +00:00
|
|
|
std::string metric_name{CurrentMetrics::getName(static_cast<CurrentMetrics::Metric>(i))};
|
2019-11-24 15:43:53 +00:00
|
|
|
std::string metric_doc{CurrentMetrics::getDocumentation(static_cast<CurrentMetrics::Metric>(i))};
|
|
|
|
|
2022-08-27 20:27:47 +00:00
|
|
|
convertHelpToSingleLine(metric_doc);
|
|
|
|
|
2021-07-09 16:12:26 +00:00
|
|
|
if (!replaceInvalidChars(metric_name))
|
|
|
|
continue;
|
2019-11-24 15:43:53 +00:00
|
|
|
std::string key{current_metrics_prefix + metric_name};
|
|
|
|
|
|
|
|
writeOutLine(wb, "# HELP", key, metric_doc);
|
|
|
|
writeOutLine(wb, "# TYPE", key, "gauge");
|
|
|
|
writeOutLine(wb, key, value);
|
|
|
|
}
|
|
|
|
}
|
2019-11-26 20:27:24 +00:00
|
|
|
|
|
|
|
if (send_asynchronous_metrics)
|
|
|
|
{
|
|
|
|
auto async_metrics_values = async_metrics.getValues();
|
|
|
|
for (const auto & name_value : async_metrics_values)
|
|
|
|
{
|
2020-03-11 15:34:12 +00:00
|
|
|
std::string key{asynchronous_metrics_prefix + name_value.first};
|
2019-12-21 17:47:44 +00:00
|
|
|
|
2021-07-09 16:12:26 +00:00
|
|
|
if (!replaceInvalidChars(key))
|
|
|
|
continue;
|
2022-11-13 02:36:20 +00:00
|
|
|
|
2019-11-26 20:27:24 +00:00
|
|
|
auto value = name_value.second;
|
|
|
|
|
2022-11-13 02:36:20 +00:00
|
|
|
std::string metric_doc{value.documentation};
|
|
|
|
convertHelpToSingleLine(metric_doc);
|
|
|
|
|
2019-11-26 20:27:24 +00:00
|
|
|
// TODO: add HELP section? asynchronous_metrics contains only key and value
|
2022-11-13 02:36:20 +00:00
|
|
|
writeOutLine(wb, "# HELP", key, metric_doc);
|
2019-11-26 20:27:24 +00:00
|
|
|
writeOutLine(wb, "# TYPE", key, "gauge");
|
2022-11-13 02:36:20 +00:00
|
|
|
writeOutLine(wb, key, value.value);
|
2019-11-26 20:27:24 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-11 15:30:02 +00:00
|
|
|
|
|
|
|
if (send_status_info)
|
|
|
|
{
|
|
|
|
for (size_t i = 0, end = CurrentStatusInfo::end(); i < end; ++i)
|
|
|
|
{
|
2023-03-02 13:36:47 +00:00
|
|
|
std::lock_guard lock(CurrentStatusInfo::locks[static_cast<CurrentStatusInfo::Status>(i)]);
|
2020-03-12 12:29:28 +00:00
|
|
|
std::string metric_name{CurrentStatusInfo::getName(static_cast<CurrentStatusInfo::Status>(i))};
|
|
|
|
std::string metric_doc{CurrentStatusInfo::getDocumentation(static_cast<CurrentStatusInfo::Status>(i))};
|
2020-03-11 15:30:02 +00:00
|
|
|
|
2022-08-27 20:27:47 +00:00
|
|
|
convertHelpToSingleLine(metric_doc);
|
|
|
|
|
2021-07-09 16:12:26 +00:00
|
|
|
if (!replaceInvalidChars(metric_name))
|
|
|
|
continue;
|
2020-03-11 15:30:02 +00:00
|
|
|
std::string key{current_status_prefix + metric_name};
|
|
|
|
|
|
|
|
writeOutLine(wb, "# HELP", key, metric_doc);
|
|
|
|
writeOutLine(wb, "# TYPE", key, "gauge");
|
|
|
|
|
|
|
|
for (const auto & value: CurrentStatusInfo::values[i])
|
|
|
|
{
|
2020-03-12 12:29:28 +00:00
|
|
|
for (const auto & enum_value: CurrentStatusInfo::getAllPossibleValues(static_cast<CurrentStatusInfo::Status>(i)))
|
2020-03-11 15:30:02 +00:00
|
|
|
{
|
|
|
|
DB::writeText(key, wb);
|
|
|
|
DB::writeChar('{', wb);
|
|
|
|
DB::writeText(key, wb);
|
2020-03-17 13:27:05 +00:00
|
|
|
DB::writeChar('=', wb);
|
2020-03-16 10:00:51 +00:00
|
|
|
writeDoubleQuotedString(enum_value.first, wb);
|
2020-03-17 13:27:05 +00:00
|
|
|
DB::writeText(",name=", wb);
|
2020-03-16 10:00:51 +00:00
|
|
|
writeDoubleQuotedString(value.first, wb);
|
2020-03-17 13:27:05 +00:00
|
|
|
DB::writeText("} ", wb);
|
2020-03-11 16:20:30 +00:00
|
|
|
DB::writeText(value.second == enum_value.second, wb);
|
2020-03-11 15:30:02 +00:00
|
|
|
DB::writeChar('\n', wb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-24 15:43:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|