diff --git a/include/MySQL_Logger.hpp b/include/MySQL_Logger.hpp index deab31ad2..96d028cb4 100644 --- a/include/MySQL_Logger.hpp +++ b/include/MySQL_Logger.hpp @@ -8,6 +8,35 @@ class MySQL_Logger; +struct p_ml_counter { + enum metric { + memory_copy_count = 0, + disk_copy_count, + get_all_events_calls_count, + get_all_events_events_count, + total_memory_copy_time_us, + total_disk_copy_time_us, + total_events_copied_to_memory, + total_events_copied_to_disk, + circular_buffer_events_added_count, + circular_buffer_events_dropped_count, + __size + }; +}; + +struct p_ml_gauge { + enum metric { + circular_buffer_events_size, + __size + }; +}; + +struct ml_metrics_map_idx { + enum index { + counters = 0, + gauges + }; +}; /** * @class MySQL_Event @@ -337,6 +366,13 @@ private: //std::atomic eventsCurrentlyInBufferCount; ///< Number of events currently in the buffer. } metrics; + /** + * @brief Structure holding the exposed Prometheus metrics for MySQL event logger. + */ + struct { + std::array p_counter_array {}; + std::array p_gauge_array {}; + } prom_metrics; // Mutex or rwlock for thread safety #ifdef PROXYSQL_LOGGER_PTHREAD_MUTEX @@ -517,7 +553,13 @@ public: */ std::unordered_map getAllMetrics() const; - + /** + * @brief Implements the prometheus metrics update hook for the module. + * @details Every module exporting prometheus metrics exposes this function, which is meant to be called + * from `ProxySQL_Admin` registered serial exposer. This way the metrics update is performed lazily every + * time the `serial_exposer` requires it. + */ + void p_update_metrics(); }; diff --git a/lib/MySQL_Logger.cpp b/lib/MySQL_Logger.cpp index d8cad1019..1dd07d67a 100644 --- a/lib/MySQL_Logger.cpp +++ b/lib/MySQL_Logger.cpp @@ -23,6 +23,103 @@ using json = nlohmann::json; extern MySQL_Logger *GloMyLogger; +using metric_name = std::string; +using metric_help = std::string; +using metric_tags = std::map; + +using ml_counter_tuple = + std::tuple< + p_ml_counter::metric, + metric_name, + metric_help, + metric_tags + >; + +using ml_gauge_tuple = + std::tuple< + p_ml_gauge::metric, + metric_name, + metric_help, + metric_tags + >; + +using qc_counter_vector = std::vector; +using qc_gauge_vector = std::vector; + +const std::tuple +ml_metrics_map = std::make_tuple( + qc_counter_vector { + std::make_tuple ( + p_ml_counter::memory_copy_count, + "proxysql_mysql_logger_copy_total", + "Number of times events were copied to the in-memory/on-disk databases.", + metric_tags { { "target", "memory" } } + ), + std::make_tuple ( + p_ml_counter::disk_copy_count, + "proxysql_mysql_logger_copy_total", + "Number of times events were copied to the in-memory/on-disk databases.", + metric_tags { { "target", "disk" } } + ), + std::make_tuple ( + p_ml_counter::get_all_events_calls_count, + "proxysql_mysql_logger_get_all_events_calls_total", + "Number of times the 'get_all_events' method was called.", + metric_tags {} + ), + std::make_tuple ( + p_ml_counter::get_all_events_events_count, + "proxysql_mysql_logger_get_all_events_events_total", + "Number of events retrieved by the `get_all_events` method.", + metric_tags {} + ), + std::make_tuple ( + p_ml_counter::total_memory_copy_time_us, + "proxysql_mysql_logger_copy_seconds_total", + "Total time spent copying events to the in-memory/on-disk databases.", + metric_tags { { "target", "memory" } } + ), + std::make_tuple ( + p_ml_counter::total_disk_copy_time_us, + "proxysql_mysql_logger_copy_seconds_total", + "Total time spent copying events to the in-memory/on-disk databases.", + metric_tags { { "target", "disk" } } + ), + std::make_tuple ( + p_ml_counter::total_events_copied_to_memory, + "proxysql_mysql_logger_events_copied_total", + "Total number of events copied to the in-memory/on-disk databases.", + metric_tags { { "target", "memory" } } + ), + std::make_tuple ( + p_ml_counter::total_events_copied_to_disk, + "proxysql_mysql_logger_events_copied_total", + "Total number of events copied to the in-memory/on-disk databases.", + metric_tags { { "target", "disk" } } + ), + std::make_tuple ( + p_ml_counter::circular_buffer_events_added_count, + "proxysql_mysql_logger_circular_buffer_events_total", + "The total number of events added/dropped to/from the circular buffer.", + metric_tags { { "type", "added" } } + ), + std::make_tuple ( + p_ml_counter::circular_buffer_events_dropped_count, + "proxysql_mysql_logger_circular_buffer_events_total", + "The total number of events added/dropped to/from the circular buffer.", + metric_tags { { "type", "dropped" } } + ), + }, + qc_gauge_vector { + std::make_tuple ( + p_ml_gauge::circular_buffer_events_size, + "proxysql_mysql_logger_circular_buffer_events", + "Number of events currently present in the circular buffer.", + metric_tags {} + ), + } +); + static uint8_t mysql_encode_length(uint64_t len, unsigned char *hd) { if (len < 251) return 1; if (len < 65536) { if (hd) { *hd=0xfc; }; return 3; } @@ -576,6 +673,14 @@ MySQL_Logger::MySQL_Logger() : metrics{{0},{0},{0},{0},{0},{0},{0},{0},{0}} { audit.log_file_id=0; audit.max_log_file_size=100*1024*1024; MyLogCB = new MySQL_Logger_CircularBuffer(0); + + // Initialize prometheus metrics + init_prometheus_counter_array( + ml_metrics_map, this->prom_metrics.p_counter_array + ); + init_prometheus_gauge_array( + ml_metrics_map, this->prom_metrics.p_gauge_array + ); }; MySQL_Logger::~MySQL_Logger() { @@ -1399,3 +1504,24 @@ std::unordered_map MySQL_Logger::getAllMetrics( return allMetrics; } + +void MySQL_Logger::p_update_metrics() { + using ml_c = p_ml_counter; + const auto& counters { this->prom_metrics.p_counter_array }; + + p_update_counter(counters[ml_c::memory_copy_count], metrics.memoryCopyCount); + p_update_counter(counters[ml_c::disk_copy_count], metrics.diskCopyCount); + p_update_counter(counters[ml_c::get_all_events_calls_count], metrics.getAllEventsCallsCount); + p_update_counter(counters[ml_c::get_all_events_events_count], metrics.getAllEventsEventsCount); + p_update_counter(counters[ml_c::total_memory_copy_time_us], metrics.totalMemoryCopyTimeMicros / (1000.0 * 1000)); + p_update_counter(counters[ml_c::total_disk_copy_time_us], metrics.totalDiskCopyTimeMicros / (1000.0 * 1000)); + p_update_counter(counters[ml_c::total_events_copied_to_memory], metrics.totalEventsCopiedToMemory); + p_update_counter(counters[ml_c::total_events_copied_to_disk], metrics.totalEventsCopiedToDisk); + + p_update_counter(counters[ml_c::circular_buffer_events_added_count], MyLogCB->getEventsAddedCount()); + p_update_counter(counters[ml_c::circular_buffer_events_dropped_count], MyLogCB->getEventsDroppedCount()); + + using ml_g = p_ml_gauge; + const auto& gauges { this->prom_metrics.p_gauge_array }; + gauges[ml_g::circular_buffer_events_size]->Set(MyLogCB->size()); +} diff --git a/lib/ProxySQL_Admin.cpp b/lib/ProxySQL_Admin.cpp index ce9d09d53..1b3194d92 100644 --- a/lib/ProxySQL_Admin.cpp +++ b/lib/ProxySQL_Admin.cpp @@ -5970,6 +5970,10 @@ void update_modules_metrics() { if (GloProxyCluster) { GloProxyCluster->p_update_metrics(); } + // Update Logger metrics + if (GloMyLogger) { + GloMyLogger->p_update_metrics(); + } // Update admin metrics GloAdmin->p_update_metrics();