diff --git a/dbms/programs/server/PrometheusMetricsWriter.cpp b/dbms/programs/server/PrometheusMetricsWriter.cpp index 11782710104..17c05d14936 100644 --- a/dbms/programs/server/PrometheusMetricsWriter.cpp +++ b/dbms/programs/server/PrometheusMetricsWriter.cpp @@ -3,6 +3,7 @@ #include #include +#include namespace { @@ -40,6 +41,7 @@ PrometheusMetricsWriter::PrometheusMetricsWriter( , send_events(config.getBool(config_name + ".events", true)) , send_metrics(config.getBool(config_name + ".metrics", true)) , send_asynchronous_metrics(config.getBool(config_name + ".asynchronous_metrics", true)) + , send_status_info(config.getBool(config_name + ".status_info", true)) { } @@ -86,7 +88,7 @@ void PrometheusMetricsWriter::write(WriteBuffer & wb) const auto async_metrics_values = async_metrics.getValues(); for (const auto & name_value : async_metrics_values) { - std::string key{asynchronous_metrics_prefix + name_value.first}; + std::string key{current_status_prefix + name_value.first}; replaceInvalidChars(key); auto value = name_value.second; @@ -96,6 +98,38 @@ void PrometheusMetricsWriter::write(WriteBuffer & wb) const writeOutLine(wb, key, value); } } + + if (send_status_info) + { + for (size_t i = 0, end = CurrentStatusInfo::end(); i < end; ++i) + { + std::string metric_name{CurrentStatusInfo::getName(static_cast(i))}; + std::string metric_doc{CurrentStatusInfo::getDocumentation(static_cast(i))}; + + replaceInvalidChars(metric_name); + 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]) + { + for (const auto & enum_value: CurrentStatusInfo::getAllPossibleValues(static_cast(i))) + { + DB::writeText(key, wb); + DB::writeChar('{', wb); + DB::writeText(key, wb); + DB::writeText("=\"", wb); + DB::writeText(enum_value.first, wb); + DB::writeText("\",name=\"", wb); + DB::writeText(value.first, wb); + DB::writeText("\"} ", wb); + DB::writeText(value.second == enum_value.first, wb); + DB::writeChar('\n', wb); + } + } + } + } } } diff --git a/dbms/programs/server/PrometheusMetricsWriter.h b/dbms/programs/server/PrometheusMetricsWriter.h index ba1f0cde61b..4422ced625e 100644 --- a/dbms/programs/server/PrometheusMetricsWriter.h +++ b/dbms/programs/server/PrometheusMetricsWriter.h @@ -27,10 +27,12 @@ private: const bool send_events; const bool send_metrics; const bool send_asynchronous_metrics; + const bool send_status_info; static inline constexpr auto profile_events_prefix = "ClickHouseProfileEvents_"; static inline constexpr auto current_metrics_prefix = "ClickHouseMetrics_"; static inline constexpr auto asynchronous_metrics_prefix = "ClickHouseAsyncMetrics_"; + static inline constexpr auto current_status_prefix = "ClickHouseStatusInfo_"; }; } diff --git a/dbms/src/Common/CurrentStatusInfo.cpp b/dbms/src/Common/CurrentStatusInfo.cpp new file mode 100644 index 00000000000..693b21080fd --- /dev/null +++ b/dbms/src/Common/CurrentStatusInfo.cpp @@ -0,0 +1,58 @@ +#include +#include + +/// Available status. Add something here as you wish. +#define APPLY_FOR_STATUS(M) \ + M(DictionaryStatus, "Dictionary Status.", DB::ExternalLoader::getStatusEnumAllPossibleValues()) \ + + +namespace CurrentStatusInfo +{ + #define M(NAME, DOCUMENTATION, ENUM) extern const Metric NAME = __COUNTER__; + APPLY_FOR_STATUS(M) + #undef M + constexpr Metric END = __COUNTER__; + + std::mutex locks[END] {}; + std::unordered_map values[END] {}; + + + const char * getName(Metric event) + { + static const char * strings[] = + { + #define M(NAME, DOCUMENTATION, ENUM) #NAME, + APPLY_FOR_STATUS(M) + #undef M + }; + + return strings[event]; + } + + const char * getDocumentation(Metric event) + { + static const char * strings[] = + { + #define M(NAME, DOCUMENTATION, ENUM) DOCUMENTATION, + APPLY_FOR_STATUS(M) + #undef M + }; + + return strings[event]; + } + + const std::vector> & getAllPossibleValues(Metric event) + { + static const std::vector> enum_values [] = + { + #define M(NAME, DOCUMENTATION, ENUM) ENUM, + APPLY_FOR_STATUS(M) + #undef M + }; + return enum_values[event]; + } + + Metric end() { return END; } +} + +#undef APPLY_FOR_STATUS diff --git a/dbms/src/Common/CurrentStatusInfo.h b/dbms/src/Common/CurrentStatusInfo.h new file mode 100644 index 00000000000..646d8fce842 --- /dev/null +++ b/dbms/src/Common/CurrentStatusInfo.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + + +namespace CurrentStatusInfo +{ + /// Metric identifier (index in array). + using Metric = size_t; + using Key = std::string; + + /// Get name of metric by identifier. Returns statically allocated string. + const char * getName(Metric event); + /// Get text description of metric by identifier. Returns statically allocated string. + const char * getDocumentation(Metric event); + const std::vector> & getAllPossibleValues(Metric event); + + extern std::unordered_map values[]; + extern std::mutex locks[]; + + /// Get index just after last metric identifier. + Metric end(); + + /// Set status of specified. + inline void set(Metric metric, Key key, String value) + { + std::lock_guard lock(locks[metric]); + values[metric][key] = value; + } + + inline void unset(Metric metric, Key key) + { + std::lock_guard lock(locks[metric]); + values[metric].erase(key); + } +} diff --git a/dbms/src/Interpreters/ExternalLoader.cpp b/dbms/src/Interpreters/ExternalLoader.cpp index 5a012bfb5a2..6488bf8f1c0 100644 --- a/dbms/src/Interpreters/ExternalLoader.cpp +++ b/dbms/src/Interpreters/ExternalLoader.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,12 @@ #include +namespace CurrentStatusInfo +{ + extern const Metric DictionaryStatus; +} + + namespace DB { namespace ErrorCodes @@ -1035,6 +1042,7 @@ private: it->second.detach(); loading_threads.erase(it); } + CurrentStatusInfo::set(CurrentStatusInfo::DictionaryStatus, name, toString(info->status())); } /// Calculate next update time for loaded_object. Can be called without mutex locking,