From 4b9ae318d1492ecdae3ede32154c12599b9c4f8b Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Fri, 22 May 2026 03:44:39 +0300 Subject: [PATCH 1/2] refactor(prometheus): extract shared PrometheusLoggerMetrics helper Move duplicated built-in metrics state, build_builtin_metrics(), and add_common_labels() from PrometheusPayloadLogger and PrometheusHttpServerLogger into a single helper class. This prevents the two backends from diverging as more metrics are added, and unifies the counter naming (m_failed_collects vs m_failed_exports) to a single m_failed_exports. Scope-risk: narrow Co-Authored-By: Claude Opus 4.7 --- .../loggers/PrometheusHttpServerLogger.hpp | 175 ++------------- .../logit/loggers/PrometheusPayloadLogger.hpp | 189 ++-------------- .../prometheus/PrometheusLoggerMetrics.hpp | 208 ++++++++++++++++++ 3 files changed, 248 insertions(+), 324 deletions(-) create mode 100644 include/logit_cpp/logit/loggers/prometheus/PrometheusLoggerMetrics.hpp diff --git a/include/logit_cpp/logit/loggers/PrometheusHttpServerLogger.hpp b/include/logit_cpp/logit/loggers/PrometheusHttpServerLogger.hpp index 985d9b0..61aaf02 100644 --- a/include/logit_cpp/logit/loggers/PrometheusHttpServerLogger.hpp +++ b/include/logit_cpp/logit/loggers/PrometheusHttpServerLogger.hpp @@ -10,16 +10,14 @@ #endif #include "ILogger.hpp" -#include "prometheus/PrometheusTextFormatConfig.hpp" +#include "prometheus/PrometheusLoggerMetrics.hpp" #include "prometheus/PrometheusTextSerializer.hpp" #include #include -#include #include #include -#include #include #include #include @@ -122,8 +120,7 @@ namespace logit { /// \param message Formatted log message (unused by Prometheus metrics). void log(const LogRecord& record, const std::string& message) override { (void)message; - m_last_log_ts.store(record.timestamp_ms); - ++m_log_records_total; + m_metrics.on_log(record.timestamp_ms); } /// \brief No-op; server is independently serving metrics. @@ -140,12 +137,12 @@ namespace logit { std::vector families; { std::lock_guard lock(m_collect_mutex); - build_builtin_metrics(families); + m_metrics.build_builtin_metrics(families, m_config.format, "prometheus_http_server"); if (m_config.on_collect) { try { m_config.on_collect(families); } catch (...) { - ++m_failed_exports; + m_metrics.add_failed_export(); } } } @@ -157,10 +154,10 @@ namespace logit { /// \return Parameter value, or empty string when unsupported. std::string get_string_param(const LoggerParam& param) const override { switch (param) { - case LoggerParam::LastLogTimestamp: return std::to_string(get_last_log_ts()); - case LoggerParam::TimeSinceLastLog: return std::to_string(get_time_since_last_log()); - case LoggerParam::DroppedLogCount: return std::to_string(dropped_count()); - case LoggerParam::FailedExportCount: return std::to_string(failed_export_count()); + case LoggerParam::LastLogTimestamp: return std::to_string(m_metrics.last_log_ts()); + case LoggerParam::TimeSinceLastLog: return std::to_string(m_metrics.time_since_last_log_ms()); + case LoggerParam::DroppedLogCount: return std::to_string(m_metrics.dropped_count()); + case LoggerParam::FailedExportCount: return std::to_string(m_metrics.failed_export_count()); default: break; } @@ -172,10 +169,10 @@ namespace logit { /// \return Parameter value, or 0 when unsupported. int64_t get_int_param(const LoggerParam& param) const override { switch (param) { - case LoggerParam::LastLogTimestamp: return get_last_log_ts(); - case LoggerParam::TimeSinceLastLog: return get_time_since_last_log(); - case LoggerParam::DroppedLogCount: return counter_to_int64(dropped_count()); - case LoggerParam::FailedExportCount: return counter_to_int64(failed_export_count()); + case LoggerParam::LastLogTimestamp: return m_metrics.last_log_ts(); + case LoggerParam::TimeSinceLastLog: return m_metrics.time_since_last_log_ms(); + case LoggerParam::DroppedLogCount: return PrometheusLoggerMetrics::counter_to_int64(m_metrics.dropped_count()); + case LoggerParam::FailedExportCount: return PrometheusLoggerMetrics::counter_to_int64(m_metrics.failed_export_count()); default: break; } @@ -188,13 +185,13 @@ namespace logit { double get_float_param(const LoggerParam& param) const override { switch (param) { case LoggerParam::LastLogTimestamp: - return static_cast(get_last_log_ts()) / 1000.0; + return static_cast(m_metrics.last_log_ts()) / 1000.0; case LoggerParam::TimeSinceLastLog: - return static_cast(get_time_since_last_log()) / 1000.0; + return static_cast(m_metrics.time_since_last_log_ms()) / 1000.0; case LoggerParam::DroppedLogCount: - return static_cast(dropped_count()); + return static_cast(m_metrics.dropped_count()); case LoggerParam::FailedExportCount: - return static_cast(failed_export_count()); + return static_cast(m_metrics.failed_export_count()); default: break; } @@ -215,12 +212,12 @@ namespace logit { /// \brief Returns number of dropped records. uint64_t dropped_count() const { - return m_dropped.load(); + return m_metrics.dropped_count(); } /// \brief Returns number of failed export attempts. uint64_t failed_export_count() const { - return m_failed_exports.load(); + return m_metrics.failed_export_count(); } private: @@ -229,12 +226,9 @@ namespace logit { std::thread m_server_thread; std::mutex m_collect_mutex; std::atomic m_running = ATOMIC_VAR_INIT(false); + PrometheusLoggerMetrics m_metrics; std::atomic m_log_level = ATOMIC_VAR_INIT(static_cast(LogLevel::LOG_LVL_TRACE)); - std::atomic m_last_log_ts = ATOMIC_VAR_INIT(0); - std::atomic m_log_records_total = ATOMIC_VAR_INIT(0); - std::atomic m_dropped = ATOMIC_VAR_INIT(0); - std::atomic m_failed_exports = ATOMIC_VAR_INIT(0); void stop() { if (!m_running.exchange(false)) { @@ -245,137 +239,6 @@ namespace logit { m_server_thread.join(); } } - - int64_t get_last_log_ts() const { - return m_last_log_ts.load(); - } - - int64_t get_time_since_last_log() const { - const int64_t last = get_last_log_ts(); - if (last <= 0) { - return 0; - } - const int64_t now = LOGIT_CURRENT_TIMESTAMP_MS(); - return now > last ? now - last : 0; - } - - static int64_t counter_to_int64(uint64_t value) { - const uint64_t max_value = static_cast((std::numeric_limits::max)()); - return value > max_value ? (std::numeric_limits::max)() : static_cast(value); - } - - void build_builtin_metrics(std::vector& families) const { - const std::string& prefix = m_config.format.metric_prefix; - - // logit_log_records_total (counter) - { - PrometheusMetricFamily mf; - mf.name = prefix + "log_records_total"; - mf.help = "Total number of log records processed"; - mf.type = PrometheusMetricType::Counter; - PrometheusSample s; - s.name = prefix + "log_records_total"; - s.value = static_cast(m_log_records_total.load()); - add_common_labels(s); - mf.samples.push_back(s); - families.push_back(mf); - } - - // logit_dropped_logs_total (counter) - { - PrometheusMetricFamily mf; - mf.name = prefix + "dropped_logs_total"; - mf.help = "Total number of dropped log records"; - mf.type = PrometheusMetricType::Counter; - PrometheusSample s; - s.name = prefix + "dropped_logs_total"; - s.value = static_cast(m_dropped.load()); - add_common_labels(s); - mf.samples.push_back(s); - families.push_back(mf); - } - - // logit_failed_exports_total (counter) - { - PrometheusMetricFamily mf; - mf.name = prefix + "failed_exports_total"; - mf.help = "Total number of failed export attempts"; - mf.type = PrometheusMetricType::Counter; - PrometheusSample s; - s.name = prefix + "failed_exports_total"; - s.value = static_cast(m_failed_exports.load()); - add_common_labels(s); - mf.samples.push_back(s); - families.push_back(mf); - } - - // logit_last_log_timestamp_ms (gauge) - { - PrometheusMetricFamily mf; - mf.name = prefix + "last_log_timestamp_ms"; - mf.help = "Timestamp of the last log record in milliseconds"; - mf.type = PrometheusMetricType::Gauge; - PrometheusSample s; - s.name = prefix + "last_log_timestamp_ms"; - s.value = static_cast(m_last_log_ts.load()); - add_common_labels(s); - mf.samples.push_back(s); - families.push_back(mf); - } - - // logit_time_since_last_log_ms (gauge) - { - PrometheusMetricFamily mf; - mf.name = prefix + "time_since_last_log_ms"; - mf.help = "Milliseconds since the last log record"; - mf.type = PrometheusMetricType::Gauge; - PrometheusSample s; - s.name = prefix + "time_since_last_log_ms"; - s.value = static_cast(get_time_since_last_log()); - add_common_labels(s); - mf.samples.push_back(s); - families.push_back(mf); - } - - // logit_build_info (gauge, value=1) - if (m_config.format.include_build_info) { - PrometheusMetricFamily mf; - mf.name = prefix + "build_info"; - mf.help = "Build information for logit-cpp"; - mf.type = PrometheusMetricType::Gauge; - PrometheusSample s; - s.name = prefix + "build_info"; - s.value = 1.0; -#ifdef LOGIT_VERSION - s.labels.push_back({"version", LOGIT_VERSION}); -#else - s.labels.push_back({"version", "1.0.2"}); -#endif -#if defined(__GNUC__) && !defined(__clang__) - s.labels.push_back({"compiler", "gcc"}); -#elif defined(__clang__) - s.labels.push_back({"compiler", "clang"}); -#elif defined(_MSC_VER) - s.labels.push_back({"compiler", "msvc"}); -#else - s.labels.push_back({"compiler", "unknown"}); -#endif - add_common_labels(s); - mf.samples.push_back(s); - families.push_back(mf); - } - } - - void add_common_labels(PrometheusSample& sample) const { - if (m_config.format.include_logger_label) { - sample.labels.push_back( - {m_config.format.logger_label_name, "prometheus_http_server"}); - } - if (m_config.format.include_instance_label) { - sample.labels.push_back( - {m_config.format.instance_label_name, m_config.format.instance_label_value}); - } - } }; } // namespace logit diff --git a/include/logit_cpp/logit/loggers/PrometheusPayloadLogger.hpp b/include/logit_cpp/logit/loggers/PrometheusPayloadLogger.hpp index 8fdcbe5..f6e9410 100644 --- a/include/logit_cpp/logit/loggers/PrometheusPayloadLogger.hpp +++ b/include/logit_cpp/logit/loggers/PrometheusPayloadLogger.hpp @@ -10,14 +10,12 @@ #endif #include "ILogger.hpp" -#include "prometheus/PrometheusTextFormatConfig.hpp" +#include "prometheus/PrometheusLoggerMetrics.hpp" #include "prometheus/PrometheusTextSerializer.hpp" #include -#include #include #include -#include #include #include #include @@ -50,9 +48,7 @@ namespace logit { explicit PrometheusPayloadLogger(const Config& config) : m_config(config) {} - ~PrometheusPayloadLogger() override { - stop(); - } + ~PrometheusPayloadLogger() override = default; PrometheusPayloadLogger(const PrometheusPayloadLogger&) = delete; PrometheusPayloadLogger& operator=(const PrometheusPayloadLogger&) = delete; @@ -62,15 +58,14 @@ namespace logit { /// \param message Formatted log message (unused by Prometheus metrics). void log(const LogRecord& record, const std::string& message) override { (void)message; - m_last_log_ts.store(record.timestamp_ms); - ++m_log_records_total; + m_metrics.on_log(record.timestamp_ms); if (m_config.emit_on_log && m_config.on_payload) { try { std::string payload = collect_payload(); m_config.on_payload(std::move(payload)); } catch (...) { - ++m_failed_collects; + m_metrics.add_failed_export(); } } } @@ -82,15 +77,13 @@ namespace logit { std::string payload = collect_payload(); m_config.on_payload(std::move(payload)); } catch (...) { - ++m_failed_collects; + m_metrics.add_failed_export(); } } } /// \brief Stops the logger (no worker thread to drain for payload logger). - void shutdown() override { - stop(); - } + void shutdown() override {} /// \brief Collects current metrics and returns serialized Prometheus text payload. /// \return Complete Prometheus text exposition format string. @@ -98,12 +91,12 @@ namespace logit { std::vector families; { std::lock_guard lock(m_collect_mutex); - build_builtin_metrics(families); + m_metrics.build_builtin_metrics(families, m_config.format, "prometheus_payload"); if (m_config.on_collect) { try { m_config.on_collect(families); } catch (...) { - ++m_failed_collects; + m_metrics.add_failed_export(); } } } @@ -115,10 +108,10 @@ namespace logit { /// \return Parameter value, or empty string when unsupported. std::string get_string_param(const LoggerParam& param) const override { switch (param) { - case LoggerParam::LastLogTimestamp: return std::to_string(get_last_log_ts()); - case LoggerParam::TimeSinceLastLog: return std::to_string(get_time_since_last_log()); - case LoggerParam::DroppedLogCount: return std::to_string(m_dropped.load()); - case LoggerParam::FailedExportCount: return std::to_string(m_failed_collects.load()); + case LoggerParam::LastLogTimestamp: return std::to_string(m_metrics.last_log_ts()); + case LoggerParam::TimeSinceLastLog: return std::to_string(m_metrics.time_since_last_log_ms()); + case LoggerParam::DroppedLogCount: return std::to_string(m_metrics.dropped_count()); + case LoggerParam::FailedExportCount: return std::to_string(m_metrics.failed_export_count()); default: break; } @@ -130,10 +123,10 @@ namespace logit { /// \return Parameter value, or 0 when unsupported. int64_t get_int_param(const LoggerParam& param) const override { switch (param) { - case LoggerParam::LastLogTimestamp: return get_last_log_ts(); - case LoggerParam::TimeSinceLastLog: return get_time_since_last_log(); - case LoggerParam::DroppedLogCount: return counter_to_int64(m_dropped.load()); - case LoggerParam::FailedExportCount: return counter_to_int64(m_failed_collects.load()); + case LoggerParam::LastLogTimestamp: return m_metrics.last_log_ts(); + case LoggerParam::TimeSinceLastLog: return m_metrics.time_since_last_log_ms(); + case LoggerParam::DroppedLogCount: return PrometheusLoggerMetrics::counter_to_int64(m_metrics.dropped_count()); + case LoggerParam::FailedExportCount: return PrometheusLoggerMetrics::counter_to_int64(m_metrics.failed_export_count()); default: break; } @@ -146,13 +139,13 @@ namespace logit { double get_float_param(const LoggerParam& param) const override { switch (param) { case LoggerParam::LastLogTimestamp: - return static_cast(get_last_log_ts()) / 1000.0; + return static_cast(m_metrics.last_log_ts()) / 1000.0; case LoggerParam::TimeSinceLastLog: - return static_cast(get_time_since_last_log()) / 1000.0; + return static_cast(m_metrics.time_since_last_log_ms()) / 1000.0; case LoggerParam::DroppedLogCount: - return static_cast(m_dropped.load()); + return static_cast(m_metrics.dropped_count()); case LoggerParam::FailedExportCount: - return static_cast(m_failed_collects.load()); + return static_cast(m_metrics.failed_export_count()); default: break; } @@ -174,149 +167,9 @@ namespace logit { private: Config m_config; std::mutex m_collect_mutex; - bool m_stopped = false; + PrometheusLoggerMetrics m_metrics; std::atomic m_log_level = ATOMIC_VAR_INIT(static_cast(LogLevel::LOG_LVL_TRACE)); - std::atomic m_last_log_ts = ATOMIC_VAR_INIT(0); - std::atomic m_log_records_total = ATOMIC_VAR_INIT(0); - std::atomic m_dropped = ATOMIC_VAR_INIT(0); - std::atomic m_failed_collects = ATOMIC_VAR_INIT(0); - - void stop() { - std::lock_guard lock(m_collect_mutex); - m_stopped = true; - } - - int64_t get_last_log_ts() const { - return m_last_log_ts.load(); - } - - int64_t get_time_since_last_log() const { - const int64_t last = get_last_log_ts(); - if (last <= 0) { - return 0; - } - const int64_t now = LOGIT_CURRENT_TIMESTAMP_MS(); - return now > last ? now - last : 0; - } - - static int64_t counter_to_int64(uint64_t value) { - const uint64_t max_value = static_cast((std::numeric_limits::max)()); - return value > max_value ? (std::numeric_limits::max)() : static_cast(value); - } - - void build_builtin_metrics(std::vector& families) const { - const std::string& prefix = m_config.format.metric_prefix; - - // logit_log_records_total (counter) - { - PrometheusMetricFamily mf; - mf.name = prefix + "log_records_total"; - mf.help = "Total number of log records processed"; - mf.type = PrometheusMetricType::Counter; - PrometheusSample s; - s.name = prefix + "log_records_total"; - s.value = static_cast(m_log_records_total.load()); - add_common_labels(s); - mf.samples.push_back(s); - families.push_back(mf); - } - - // logit_dropped_logs_total (counter) - { - PrometheusMetricFamily mf; - mf.name = prefix + "dropped_logs_total"; - mf.help = "Total number of dropped log records"; - mf.type = PrometheusMetricType::Counter; - PrometheusSample s; - s.name = prefix + "dropped_logs_total"; - s.value = static_cast(m_dropped.load()); - add_common_labels(s); - mf.samples.push_back(s); - families.push_back(mf); - } - - // logit_failed_exports_total (counter) - { - PrometheusMetricFamily mf; - mf.name = prefix + "failed_exports_total"; - mf.help = "Total number of failed export attempts"; - mf.type = PrometheusMetricType::Counter; - PrometheusSample s; - s.name = prefix + "failed_exports_total"; - s.value = static_cast(m_failed_collects.load()); - add_common_labels(s); - mf.samples.push_back(s); - families.push_back(mf); - } - - // logit_last_log_timestamp_ms (gauge) - { - PrometheusMetricFamily mf; - mf.name = prefix + "last_log_timestamp_ms"; - mf.help = "Timestamp of the last log record in milliseconds"; - mf.type = PrometheusMetricType::Gauge; - PrometheusSample s; - s.name = prefix + "last_log_timestamp_ms"; - s.value = static_cast(m_last_log_ts.load()); - add_common_labels(s); - mf.samples.push_back(s); - families.push_back(mf); - } - - // logit_time_since_last_log_ms (gauge) - { - PrometheusMetricFamily mf; - mf.name = prefix + "time_since_last_log_ms"; - mf.help = "Milliseconds since the last log record"; - mf.type = PrometheusMetricType::Gauge; - PrometheusSample s; - s.name = prefix + "time_since_last_log_ms"; - s.value = static_cast(get_time_since_last_log()); - add_common_labels(s); - mf.samples.push_back(s); - families.push_back(mf); - } - - // logit_build_info (gauge, value=1) with version/compiler labels - if (m_config.format.include_build_info) { - PrometheusMetricFamily mf; - mf.name = prefix + "build_info"; - mf.help = "Build information for logit-cpp"; - mf.type = PrometheusMetricType::Gauge; - PrometheusSample s; - s.name = prefix + "build_info"; - s.value = 1.0; -#ifdef LOGIT_VERSION - s.labels.push_back({"version", LOGIT_VERSION}); -#else - s.labels.push_back({"version", "1.0.2"}); -#endif -#if defined(__GNUC__) && !defined(__clang__) - s.labels.push_back({"compiler", "gcc"}); -#elif defined(__clang__) - s.labels.push_back({"compiler", "clang"}); -#elif defined(_MSC_VER) - s.labels.push_back({"compiler", "msvc"}); -#else - s.labels.push_back({"compiler", "unknown"}); -#endif - add_common_labels(s); - mf.samples.push_back(s); - families.push_back(mf); - } - } - - void add_common_labels(PrometheusSample& sample) const { - if (m_config.format.include_logger_label) { - sample.labels.push_back( - {m_config.format.logger_label_name, "prometheus_payload"}); - } - if (m_config.format.include_instance_label) { - sample.labels.push_back( - {m_config.format.instance_label_name, m_config.format.instance_label_value}); - } - } }; } // namespace logit diff --git a/include/logit_cpp/logit/loggers/prometheus/PrometheusLoggerMetrics.hpp b/include/logit_cpp/logit/loggers/prometheus/PrometheusLoggerMetrics.hpp new file mode 100644 index 0000000..2225f45 --- /dev/null +++ b/include/logit_cpp/logit/loggers/prometheus/PrometheusLoggerMetrics.hpp @@ -0,0 +1,208 @@ +#pragma once +#ifndef _LOGIT_PROMETHEUS_LOGGER_METRICS_HPP_INCLUDED +#define _LOGIT_PROMETHEUS_LOGGER_METRICS_HPP_INCLUDED + +/// \file PrometheusLoggerMetrics.hpp +/// \brief Shared built-in metrics state and serialization for Prometheus loggers. + +#include "PrometheusTextFormatConfig.hpp" +#include "../../config.hpp" + +#include +#include +#include +#include +#include + +namespace logit { + + /// \class PrometheusLoggerMetrics + /// \brief Tracks log-record counters and builds built-in Prometheus metric families. + class PrometheusLoggerMetrics { + public: + /// \brief Update metrics when a log record is processed. + void on_log(int64_t timestamp_ms) { + m_last_log_ts.store(timestamp_ms); + ++m_log_records_total; + } + + /// \brief Increment dropped log counter. + void add_dropped(uint64_t count = 1) { + m_dropped.fetch_add(count); + } + + /// \brief Increment failed export/collect counter. + void add_failed_export(uint64_t count = 1) { + m_failed_exports.fetch_add(count); + } + + /// \brief Total log records processed. + uint64_t log_records_total() const { + return m_log_records_total.load(); + } + + /// \brief Total dropped log records. + uint64_t dropped_count() const { + return m_dropped.load(); + } + + /// \brief Total failed export/collect attempts. + uint64_t failed_export_count() const { + return m_failed_exports.load(); + } + + /// \brief Last log timestamp (ms). + int64_t last_log_ts() const { + return m_last_log_ts.load(); + } + + /// \brief Milliseconds since last log record (0 if none). + int64_t time_since_last_log_ms() const { + const int64_t last = last_log_ts(); + if (last <= 0) { + return 0; + } + const int64_t now = LOGIT_CURRENT_TIMESTAMP_MS(); + return now > last ? now - last : 0; + } + + /// \brief Append the six built-in metric families to \p families. + /// \param families Destination vector. + /// \param config Format configuration (prefix, labels, build-info flag). + /// \param logger_name Value for the logger label (e.g. "prometheus_payload"). + void build_builtin_metrics( + std::vector& families, + const PrometheusTextFormatConfig& config, + const std::string& logger_name) const { + + const std::string& prefix = config.metric_prefix; + + // logit_log_records_total (counter) + { + PrometheusMetricFamily mf; + mf.name = prefix + "log_records_total"; + mf.help = "Total number of log records processed"; + mf.type = PrometheusMetricType::Counter; + PrometheusSample s; + s.name = prefix + "log_records_total"; + s.value = static_cast(m_log_records_total.load()); + add_common_labels(s, config, logger_name); + mf.samples.push_back(s); + families.push_back(mf); + } + + // logit_dropped_logs_total (counter) + { + PrometheusMetricFamily mf; + mf.name = prefix + "dropped_logs_total"; + mf.help = "Total number of dropped log records"; + mf.type = PrometheusMetricType::Counter; + PrometheusSample s; + s.name = prefix + "dropped_logs_total"; + s.value = static_cast(m_dropped.load()); + add_common_labels(s, config, logger_name); + mf.samples.push_back(s); + families.push_back(mf); + } + + // logit_failed_exports_total (counter) + { + PrometheusMetricFamily mf; + mf.name = prefix + "failed_exports_total"; + mf.help = "Total number of failed export attempts"; + mf.type = PrometheusMetricType::Counter; + PrometheusSample s; + s.name = prefix + "failed_exports_total"; + s.value = static_cast(m_failed_exports.load()); + add_common_labels(s, config, logger_name); + mf.samples.push_back(s); + families.push_back(mf); + } + + // logit_last_log_timestamp_ms (gauge) + { + PrometheusMetricFamily mf; + mf.name = prefix + "last_log_timestamp_ms"; + mf.help = "Timestamp of the last log record in milliseconds"; + mf.type = PrometheusMetricType::Gauge; + PrometheusSample s; + s.name = prefix + "last_log_timestamp_ms"; + s.value = static_cast(m_last_log_ts.load()); + add_common_labels(s, config, logger_name); + mf.samples.push_back(s); + families.push_back(mf); + } + + // logit_time_since_last_log_ms (gauge) + { + PrometheusMetricFamily mf; + mf.name = prefix + "time_since_last_log_ms"; + mf.help = "Milliseconds since the last log record"; + mf.type = PrometheusMetricType::Gauge; + PrometheusSample s; + s.name = prefix + "time_since_last_log_ms"; + s.value = static_cast(time_since_last_log_ms()); + add_common_labels(s, config, logger_name); + mf.samples.push_back(s); + families.push_back(mf); + } + + // logit_build_info (gauge, value=1) with version/compiler labels + if (config.include_build_info) { + PrometheusMetricFamily mf; + mf.name = prefix + "build_info"; + mf.help = "Build information for logit-cpp"; + mf.type = PrometheusMetricType::Gauge; + PrometheusSample s; + s.name = prefix + "build_info"; + s.value = 1.0; +#ifdef LOGIT_VERSION + s.labels.push_back({"version", LOGIT_VERSION}); +#else + s.labels.push_back({"version", "1.0.2"}); +#endif +#if defined(__GNUC__) && !defined(__clang__) + s.labels.push_back({"compiler", "gcc"}); +#elif defined(__clang__) + s.labels.push_back({"compiler", "clang"}); +#elif defined(_MSC_VER) + s.labels.push_back({"compiler", "msvc"}); +#else + s.labels.push_back({"compiler", "unknown"}); +#endif + add_common_labels(s, config, logger_name); + mf.samples.push_back(s); + families.push_back(mf); + } + } + + /// \brief Safely convert uint64_t counter to int64_t (clamping on overflow). + static int64_t counter_to_int64(uint64_t value) { + const uint64_t max_value = static_cast((std::numeric_limits::max)()); + return value > max_value ? (std::numeric_limits::max)() : static_cast(value); + } + + private: + std::atomic m_log_records_total{0}; + std::atomic m_dropped{0}; + std::atomic m_failed_exports{0}; + std::atomic m_last_log_ts{0}; + + static void add_common_labels( + PrometheusSample& sample, + const PrometheusTextFormatConfig& config, + const std::string& logger_name) { + if (config.include_logger_label) { + sample.labels.push_back( + {config.logger_label_name, logger_name}); + } + if (config.include_instance_label) { + sample.labels.push_back( + {config.instance_label_name, config.instance_label_value}); + } + } + }; + +} // namespace logit + +#endif // _LOGIT_PROMETHEUS_LOGGER_METRICS_HPP_INCLUDED From 8a5ade44cd3318f54b8dc7dc3fea297524dc82bb Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Fri, 22 May 2026 03:53:38 +0300 Subject: [PATCH 2/2] refactor(prometheus): remove config.hpp dependency from PrometheusLoggerMetrics PrometheusLoggerMetrics no longer depends on LOGIT_CURRENT_TIMESTAMP_MS() or config.hpp. Callers pass current timestamp explicitly: - time_since_last_log_ms(int64_t now_ms) - build_builtin_metrics(..., int64_t now_ms) This keeps the helper self-contained and usable without pulling in the full LogIt configuration header. Co-Authored-By: Claude Opus 4.7 --- .../logit/loggers/PrometheusHttpServerLogger.hpp | 10 ++++++---- .../logit/loggers/PrometheusPayloadLogger.hpp | 10 ++++++---- .../loggers/prometheus/PrometheusLoggerMetrics.hpp | 13 +++++++------ 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/include/logit_cpp/logit/loggers/PrometheusHttpServerLogger.hpp b/include/logit_cpp/logit/loggers/PrometheusHttpServerLogger.hpp index 61aaf02..8d7cfda 100644 --- a/include/logit_cpp/logit/loggers/PrometheusHttpServerLogger.hpp +++ b/include/logit_cpp/logit/loggers/PrometheusHttpServerLogger.hpp @@ -137,7 +137,9 @@ namespace logit { std::vector families; { std::lock_guard lock(m_collect_mutex); - m_metrics.build_builtin_metrics(families, m_config.format, "prometheus_http_server"); + m_metrics.build_builtin_metrics( + families, m_config.format, "prometheus_http_server", + LOGIT_CURRENT_TIMESTAMP_MS()); if (m_config.on_collect) { try { m_config.on_collect(families); @@ -155,7 +157,7 @@ namespace logit { std::string get_string_param(const LoggerParam& param) const override { switch (param) { case LoggerParam::LastLogTimestamp: return std::to_string(m_metrics.last_log_ts()); - case LoggerParam::TimeSinceLastLog: return std::to_string(m_metrics.time_since_last_log_ms()); + case LoggerParam::TimeSinceLastLog: return std::to_string(m_metrics.time_since_last_log_ms(LOGIT_CURRENT_TIMESTAMP_MS())); case LoggerParam::DroppedLogCount: return std::to_string(m_metrics.dropped_count()); case LoggerParam::FailedExportCount: return std::to_string(m_metrics.failed_export_count()); default: @@ -170,7 +172,7 @@ namespace logit { int64_t get_int_param(const LoggerParam& param) const override { switch (param) { case LoggerParam::LastLogTimestamp: return m_metrics.last_log_ts(); - case LoggerParam::TimeSinceLastLog: return m_metrics.time_since_last_log_ms(); + case LoggerParam::TimeSinceLastLog: return m_metrics.time_since_last_log_ms(LOGIT_CURRENT_TIMESTAMP_MS()); case LoggerParam::DroppedLogCount: return PrometheusLoggerMetrics::counter_to_int64(m_metrics.dropped_count()); case LoggerParam::FailedExportCount: return PrometheusLoggerMetrics::counter_to_int64(m_metrics.failed_export_count()); default: @@ -187,7 +189,7 @@ namespace logit { case LoggerParam::LastLogTimestamp: return static_cast(m_metrics.last_log_ts()) / 1000.0; case LoggerParam::TimeSinceLastLog: - return static_cast(m_metrics.time_since_last_log_ms()) / 1000.0; + return static_cast(m_metrics.time_since_last_log_ms(LOGIT_CURRENT_TIMESTAMP_MS())) / 1000.0; case LoggerParam::DroppedLogCount: return static_cast(m_metrics.dropped_count()); case LoggerParam::FailedExportCount: diff --git a/include/logit_cpp/logit/loggers/PrometheusPayloadLogger.hpp b/include/logit_cpp/logit/loggers/PrometheusPayloadLogger.hpp index f6e9410..b189f4d 100644 --- a/include/logit_cpp/logit/loggers/PrometheusPayloadLogger.hpp +++ b/include/logit_cpp/logit/loggers/PrometheusPayloadLogger.hpp @@ -91,7 +91,9 @@ namespace logit { std::vector families; { std::lock_guard lock(m_collect_mutex); - m_metrics.build_builtin_metrics(families, m_config.format, "prometheus_payload"); + m_metrics.build_builtin_metrics( + families, m_config.format, "prometheus_payload", + LOGIT_CURRENT_TIMESTAMP_MS()); if (m_config.on_collect) { try { m_config.on_collect(families); @@ -109,7 +111,7 @@ namespace logit { std::string get_string_param(const LoggerParam& param) const override { switch (param) { case LoggerParam::LastLogTimestamp: return std::to_string(m_metrics.last_log_ts()); - case LoggerParam::TimeSinceLastLog: return std::to_string(m_metrics.time_since_last_log_ms()); + case LoggerParam::TimeSinceLastLog: return std::to_string(m_metrics.time_since_last_log_ms(LOGIT_CURRENT_TIMESTAMP_MS())); case LoggerParam::DroppedLogCount: return std::to_string(m_metrics.dropped_count()); case LoggerParam::FailedExportCount: return std::to_string(m_metrics.failed_export_count()); default: @@ -124,7 +126,7 @@ namespace logit { int64_t get_int_param(const LoggerParam& param) const override { switch (param) { case LoggerParam::LastLogTimestamp: return m_metrics.last_log_ts(); - case LoggerParam::TimeSinceLastLog: return m_metrics.time_since_last_log_ms(); + case LoggerParam::TimeSinceLastLog: return m_metrics.time_since_last_log_ms(LOGIT_CURRENT_TIMESTAMP_MS()); case LoggerParam::DroppedLogCount: return PrometheusLoggerMetrics::counter_to_int64(m_metrics.dropped_count()); case LoggerParam::FailedExportCount: return PrometheusLoggerMetrics::counter_to_int64(m_metrics.failed_export_count()); default: @@ -141,7 +143,7 @@ namespace logit { case LoggerParam::LastLogTimestamp: return static_cast(m_metrics.last_log_ts()) / 1000.0; case LoggerParam::TimeSinceLastLog: - return static_cast(m_metrics.time_since_last_log_ms()) / 1000.0; + return static_cast(m_metrics.time_since_last_log_ms(LOGIT_CURRENT_TIMESTAMP_MS())) / 1000.0; case LoggerParam::DroppedLogCount: return static_cast(m_metrics.dropped_count()); case LoggerParam::FailedExportCount: diff --git a/include/logit_cpp/logit/loggers/prometheus/PrometheusLoggerMetrics.hpp b/include/logit_cpp/logit/loggers/prometheus/PrometheusLoggerMetrics.hpp index 2225f45..9558916 100644 --- a/include/logit_cpp/logit/loggers/prometheus/PrometheusLoggerMetrics.hpp +++ b/include/logit_cpp/logit/loggers/prometheus/PrometheusLoggerMetrics.hpp @@ -6,7 +6,6 @@ /// \brief Shared built-in metrics state and serialization for Prometheus loggers. #include "PrometheusTextFormatConfig.hpp" -#include "../../config.hpp" #include #include @@ -57,23 +56,25 @@ namespace logit { } /// \brief Milliseconds since last log record (0 if none). - int64_t time_since_last_log_ms() const { + /// \param now_ms Current wall time in milliseconds (from LOGIT_CURRENT_TIMESTAMP_MS()). + int64_t time_since_last_log_ms(int64_t now_ms) const { const int64_t last = last_log_ts(); if (last <= 0) { return 0; } - const int64_t now = LOGIT_CURRENT_TIMESTAMP_MS(); - return now > last ? now - last : 0; + return now_ms > last ? now_ms - last : 0; } /// \brief Append the six built-in metric families to \p families. /// \param families Destination vector. /// \param config Format configuration (prefix, labels, build-info flag). /// \param logger_name Value for the logger label (e.g. "prometheus_payload"). + /// \param now_ms Current wall time in milliseconds (from LOGIT_CURRENT_TIMESTAMP_MS()). void build_builtin_metrics( std::vector& families, const PrometheusTextFormatConfig& config, - const std::string& logger_name) const { + const std::string& logger_name, + int64_t now_ms = 0) const { const std::string& prefix = config.metric_prefix; @@ -141,7 +142,7 @@ namespace logit { mf.type = PrometheusMetricType::Gauge; PrometheusSample s; s.name = prefix + "time_since_last_log_ms"; - s.value = static_cast(time_since_last_log_ms()); + s.value = static_cast(time_since_last_log_ms(now_ms)); add_common_labels(s, config, logger_name); mf.samples.push_back(s); families.push_back(mf);