mirror of https://github.com/sysown/proxysql
Second half of Step 2 from the GenAI plugin carve-out design. Lets plugins register their counters / gauges / histograms against the same prometheus::Registry core uses; their metrics surface alongside core's at the same /metrics endpoint scrapers already poll. ABI extension (include/ProxySQL_Plugin.h): - Forward-declare prometheus::Registry to avoid pulling prometheus-cpp into the plugin ABI header. - proxysql_plugin_get_prometheus_registry_cb typedef. - New field on ProxySQL_PluginServices: get_prometheus_registry, added at the end of the struct (additive -- older plugins stop reading at the previous member). Manager (lib/ProxySQL_PluginManager.cpp): - get_prometheus_registry_service() returns GloVars.prometheus_registry.get(). - Wired into services_ at construction. Lifetime is simpler than initially documented: GloVars (and its prometheus_registry shared_ptr, allocated in its constructor) exists before any plugin is loaded, so the service returns non-null for every callback the plugin will see (init, start, admin command callback, query hook). ABI-header docs updated to reflect this -- plugins MAY register metrics in init() if they want them visible from first scrape. New unit test: plugin_prometheus_unit-t (10 assertions) - after test_init_minimal, GloVars.prometheus_registry is non-null. - A counter registered through prometheus-cpp directly (BuildCounter + Register(*reg)) is visible in the registry's text serialisation by name; the counter's Value() reflects increments through the same prometheus-cpp API plugins will use. - The registry pointer captured BEFORE plugin load equals the pointer observed during init/start AND after stop -- the loader does not swap, replace, or null out the registry; it only installs a service callback that points at it. All 60 unit-test binaries pass. Note: this finishes the Step 2 ABI surface (query hook + Prometheus registry). Step 3 starts moving real GenAI subsystems -- Anomaly_Detector first -- which will be the first consumer of the query hook from inside the plugin and the first plugin to register a metric against the shared Prometheus registry.ProtocolX
parent
55556979e0
commit
398b833aeb
@ -0,0 +1,110 @@
|
||||
// Step 2 ABI extension test: shared Prometheus registry access.
|
||||
//
|
||||
// What we assert deterministically:
|
||||
// * GloVars.prometheus_registry is the registry plugins receive via the
|
||||
// get_prometheus_registry service callback (same pointer);
|
||||
// * a counter registered against that registry is collected by the
|
||||
// same registry (i.e. it's a single shared instance, not two);
|
||||
// * the counter's value reflects increments through the prometheus-cpp
|
||||
// API the plugins will use.
|
||||
|
||||
#include "ProxySQL_PluginManager.h"
|
||||
#include "ProxySQL_Plugin.h"
|
||||
#include "proxysql_glovars.hpp"
|
||||
#include "tap.h"
|
||||
#include "test_globals.h"
|
||||
#include "test_init.h"
|
||||
|
||||
#include "prometheus/registry.h"
|
||||
#include "prometheus/counter.h"
|
||||
#include "prometheus/family.h"
|
||||
#include "prometheus/text_serializer.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifndef PROXYSQL_FAKE_PLUGIN_PATH
|
||||
#error "PROXYSQL_FAKE_PLUGIN_PATH must be defined"
|
||||
#endif
|
||||
|
||||
extern ProxySQL_GlobalVariables GloVars;
|
||||
|
||||
namespace {
|
||||
|
||||
char g_fake_admin_db = '\0';
|
||||
char g_fake_config_db = '\0';
|
||||
char g_fake_stats_db = '\0';
|
||||
|
||||
bool registry_contains_metric(prometheus::Registry* reg, const std::string& name) {
|
||||
if (reg == nullptr) return false;
|
||||
prometheus::TextSerializer ts;
|
||||
const std::string dump = ts.Serialize(reg->Collect());
|
||||
return dump.find(name) != std::string::npos;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SQLite3DB* proxysql_plugin_get_admindb() { return reinterpret_cast<SQLite3DB*>(&g_fake_admin_db); }
|
||||
SQLite3DB* proxysql_plugin_get_configdb() { return reinterpret_cast<SQLite3DB*>(&g_fake_config_db); }
|
||||
SQLite3DB* proxysql_plugin_get_statsdb() { return reinterpret_cast<SQLite3DB*>(&g_fake_stats_db); }
|
||||
|
||||
static void test_glovars_registry_exists() {
|
||||
ok(GloVars.prometheus_registry != nullptr,
|
||||
"GloVars.prometheus_registry is non-null after test_init_minimal");
|
||||
}
|
||||
|
||||
static void test_counter_round_trip_through_shared_registry() {
|
||||
prometheus::Registry* reg = GloVars.prometheus_registry.get();
|
||||
|
||||
auto& family = prometheus::BuildCounter()
|
||||
.Name("proxysql_plugin_unit_test_counter")
|
||||
.Help("Plugin unit test: counter registered against the shared registry")
|
||||
.Register(*reg);
|
||||
auto& counter = family.Add({});
|
||||
counter.Increment();
|
||||
counter.Increment();
|
||||
counter.Increment();
|
||||
ok(counter.Value() == 3.0,
|
||||
"counter value reflects the three increments");
|
||||
|
||||
ok(registry_contains_metric(reg, "proxysql_plugin_unit_test_counter"),
|
||||
"metric name appears in the shared registry's text serialisation");
|
||||
}
|
||||
|
||||
static void test_loader_does_not_disturb_registry() {
|
||||
// Loading a plugin must not replace, swap, or null out the registry --
|
||||
// just install a service callback that points at it. Verify the
|
||||
// registry pointer survives the lifecycle.
|
||||
prometheus::Registry* before = GloVars.prometheus_registry.get();
|
||||
ok(before != nullptr, "registry pointer captured before load");
|
||||
|
||||
ProxySQL_PluginManager mgr;
|
||||
std::string err;
|
||||
ok(mgr.load(PROXYSQL_FAKE_PLUGIN_PATH, err), "fake plugin loads");
|
||||
ok(mgr.init_all(err), "init_all succeeds");
|
||||
ok(mgr.start_all(err), "start_all succeeds");
|
||||
|
||||
prometheus::Registry* during = GloVars.prometheus_registry.get();
|
||||
ok(during == before,
|
||||
"registry pointer unchanged across plugin load+init+start");
|
||||
|
||||
ok(mgr.stop_all(), "stop_all succeeds");
|
||||
ok(GloVars.prometheus_registry.get() == before,
|
||||
"registry pointer unchanged after plugin stop");
|
||||
}
|
||||
|
||||
int main() {
|
||||
plan(10);
|
||||
|
||||
// Bring up the minimum core state needed for GloVars.prometheus_registry
|
||||
// to exist (test_helpers/test_init.cpp allocates the shared_ptr).
|
||||
test_init_minimal();
|
||||
|
||||
test_glovars_registry_exists();
|
||||
test_counter_round_trip_through_shared_registry();
|
||||
test_loader_does_not_disturb_registry();
|
||||
|
||||
test_cleanup_minimal();
|
||||
return exit_status();
|
||||
}
|
||||
Loading…
Reference in new issue