diff --git a/include/logit_cpp/logit/loggers/PrometheusHttpServerLogger.hpp b/include/logit_cpp/logit/loggers/PrometheusHttpServerLogger.hpp index 985d9b0..8d7cfda 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,14 @@ 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", + LOGIT_CURRENT_TIMESTAMP_MS()); if (m_config.on_collect) { try { m_config.on_collect(families); } catch (...) { - ++m_failed_exports; + m_metrics.add_failed_export(); } } } @@ -157,10 +156,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(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: break; } @@ -172,10 +171,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(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: break; } @@ -188,13 +187,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(LOGIT_CURRENT_TIMESTAMP_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 +214,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 +228,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 +241,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..b189f4d 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,14 @@ 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", + LOGIT_CURRENT_TIMESTAMP_MS()); if (m_config.on_collect) { try { m_config.on_collect(families); } catch (...) { - ++m_failed_collects; + m_metrics.add_failed_export(); } } } @@ -115,10 +110,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(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: break; } @@ -130,10 +125,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(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: break; } @@ -146,13 +141,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(LOGIT_CURRENT_TIMESTAMP_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 +169,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..9558916 --- /dev/null +++ b/include/logit_cpp/logit/loggers/prometheus/PrometheusLoggerMetrics.hpp @@ -0,0 +1,209 @@ +#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 +#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). + /// \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; + } + 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, + int64_t now_ms = 0) 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(now_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