diff --git a/src/core/core.pri b/src/core/core.pri index 556980cb..8946a0de 100644 --- a/src/core/core.pri +++ b/src/core/core.pri @@ -96,6 +96,7 @@ HEADERS += \ $$PWD/inspectdata.h \ $$PWD/cors.h \ $$PWD/simplehttpserver.h \ + $$PWD/prometheus.h \ $$PWD/stats.h \ $$PWD/statsmanager.h \ $$PWD/settings.h @@ -128,6 +129,7 @@ SOURCES += \ $$PWD/statusreasons.cpp \ $$PWD/cors.cpp \ $$PWD/simplehttpserver.cpp \ + $$PWD/prometheus.cpp \ $$PWD/stats.cpp \ $$PWD/statsmanager.cpp \ $$PWD/settings.cpp diff --git a/src/core/prometheus.cpp b/src/core/prometheus.cpp new file mode 100644 index 00000000..1ac3015a --- /dev/null +++ b/src/core/prometheus.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2026 Fastly, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "prometheus.h" + +PrometheusServer::PrometheusServer(ffi::PrometheusServer *handle) : inner_(handle) {} + +PrometheusServer::~PrometheusServer() { ffi::prometheus_server_destroy(inner_); } + +// static +std::unique_ptr PrometheusServer::create(const QString &addr, + const ffi::PrometheusRegistry *registry, + QString *error) { + const char *errStr = nullptr; + ffi::PrometheusServer *handle = + ffi::prometheus_server_create(addr.toUtf8().data(), registry, &errStr); + if (!handle) { + if (error && errStr) + *error = QString::fromUtf8(errStr); + ffi::prometheus_server_error_destroy(errStr); + return nullptr; + } + return std::unique_ptr(new PrometheusServer(handle)); +} diff --git a/src/core/prometheus.h b/src/core/prometheus.h new file mode 100644 index 00000000..cbece8ac --- /dev/null +++ b/src/core/prometheus.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2026 Fastly, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PROMETHEUS_H +#define PROMETHEUS_H + +#include "rust/bindings.h" +#include +#include + +/// RAII wrapper around the Rust-backed prometheus HTTP server. Destroying this object blocks +/// until the server thread stops. +class PrometheusServer { +public: + ~PrometheusServer(); + + PrometheusServer(const PrometheusServer &) = delete; + PrometheusServer &operator=(const PrometheusServer &) = delete; + + /// Create and start a prometheus HTTP server listening on `addr`. The registry is cloned + /// internally so the server is independent of the registry's lifetime. On failure returns + /// nullptr and writes a description to `*error` if `error` is non-null. + static std::unique_ptr + create(const QString &addr, const ffi::PrometheusRegistry *registry, QString *error = nullptr); + +private: + explicit PrometheusServer(ffi::PrometheusServer *handle); + ffi::PrometheusServer *inner_; +}; + +#endif diff --git a/src/core/statsmanager.cpp b/src/core/statsmanager.cpp index d2ba464e..fbf72dcc 100644 --- a/src/core/statsmanager.cpp +++ b/src/core/statsmanager.cpp @@ -1322,6 +1322,30 @@ class StatsManager::Private { } }; +StatsManager::CommonMetrics::CommonMetrics(ffi::CommonMetrics *handle) : inner_(handle) {} + +StatsManager::CommonMetrics::~CommonMetrics() { ffi::statsmanager_commonmetrics_destroy(inner_); } + +// static +std::unique_ptr +StatsManager::CommonMetrics::create(const QString &prefix) { + ffi::CommonMetrics *handle = ffi::statsmanager_commonmetrics_create(prefix.toUtf8().data()); + if (!handle) + return nullptr; + return std::unique_ptr(new StatsManager::CommonMetrics(handle)); +} + +const ffi::PrometheusRegistry *StatsManager::CommonMetrics::registry() const { + return ffi::statsmanager_commonmetrics_registry(inner_); +} + +void StatsManager::CommonMetrics::update(uint32_t requestReceived, uint32_t connectionConnected, + uint32_t connectionMinute, uint32_t messageReceived, + uint32_t messageSent) { + ffi::statsmanager_commonmetrics_update(inner_, requestReceived, connectionConnected, + connectionMinute, messageReceived, messageSent); +} + StatsManager::StatsManager(int connectionsMax, int subscriptionsMax) { d = new Private(this, connectionsMax, subscriptionsMax); } diff --git a/src/core/statsmanager.h b/src/core/statsmanager.h index 26d35b30..efcee7da 100644 --- a/src/core/statsmanager.h +++ b/src/core/statsmanager.h @@ -25,6 +25,7 @@ #define STATSMANAGER_H #include "packet/statspacket.h" +#include "rust/bindings.h" #include "stats.h" #include @@ -40,6 +41,26 @@ class StatsManager { enum Format { TnetStringFormat, JsonFormat }; + /// RAII wrapper around the Rust-backed CommonMetrics object, which holds the prometheus + /// registry and all metric handles. + class CommonMetrics { + public: + ~CommonMetrics(); + + CommonMetrics(const CommonMetrics &) = delete; + CommonMetrics &operator=(const CommonMetrics &) = delete; + + static std::unique_ptr create(const QString &prefix); + + const ffi::PrometheusRegistry *registry() const; + void update(uint32_t requestReceived, uint32_t connectionConnected, + uint32_t connectionMinute, uint32_t messageReceived, uint32_t messageSent); + + private: + explicit CommonMetrics(ffi::CommonMetrics *handle); + ffi::CommonMetrics *inner_; + }; + StatsManager(int connectionsMax, int subscriptionsMax); ~StatsManager();