Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions examples/example_logit_prometheus_server.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#include <logit.hpp>

#ifdef LOGIT_WITH_PROMETHEUS_SERVER
#include <logit/loggers/prometheus/PrometheusMetricBuilders.hpp>
#endif

int main() {
#ifndef LOGIT_WITH_PROMETHEUS_SERVER
LOGIT_ADD_CONSOLE_DEFAULT();
Expand All @@ -15,15 +19,11 @@ int main() {

// Optional: add custom metrics on each scrape
config.on_collect = [](std::vector<logit::PrometheusMetricFamily>& families) {
logit::PrometheusMetricFamily mf;
mf.name = "myapp_uptime_seconds";
mf.help = "Application uptime in seconds";
mf.type = logit::PrometheusMetricType::Gauge;
logit::PrometheusSample s;
s.name = "myapp_uptime_seconds";
s.value = 42.0;
mf.samples.push_back(s);
families.push_back(mf);
logit::add_prometheus_gauge(
families,
"myapp_uptime_seconds",
"Application uptime in seconds",
42.0);
};

LOGIT_ADD_LOGGER(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#pragma once
#ifndef _LOGIT_PROMETHEUS_METRIC_BUILDERS_HPP_INCLUDED
#define _LOGIT_PROMETHEUS_METRIC_BUILDERS_HPP_INCLUDED

/// \file PrometheusMetricBuilders.hpp
/// \brief Convenience helpers for constructing Prometheus metric families and samples.

#include "PrometheusTextFormatConfig.hpp"

#include <string>
#include <utility>
#include <vector>

namespace logit {

/// \brief Create a single label pair.
inline PrometheusLabel make_prometheus_label(
const std::string& name,
const std::string& value) {
PrometheusLabel label;
label.name = name;
label.value = value;
return label;
}

/// \brief Create a sample for a Prometheus metric family.
inline PrometheusSample make_prometheus_sample(
const std::string& name,
double value,
std::vector<PrometheusLabel> labels = {},
int64_t timestamp_ms = 0) {
PrometheusSample s;
s.name = name;
s.value = value;
s.labels = std::move(labels);
s.timestamp_ms = timestamp_ms;
return s;
}

/// \brief Create a Counter metric family with one unlabeled sample.
inline PrometheusMetricFamily make_prometheus_counter(
const std::string& name,
const std::string& help,
double value) {
PrometheusMetricFamily mf;
mf.name = name;
mf.help = help;
mf.type = PrometheusMetricType::Counter;
mf.samples.push_back(make_prometheus_sample(name, value));
return mf;
}

/// \brief Create a Counter metric family with one labeled sample.
inline PrometheusMetricFamily make_prometheus_counter(
const std::string& name,
const std::string& help,
double value,
std::vector<PrometheusLabel> labels) {
PrometheusMetricFamily mf;
mf.name = name;
mf.help = help;
mf.type = PrometheusMetricType::Counter;
mf.samples.push_back(make_prometheus_sample(name, value, std::move(labels)));
return mf;
}

/// \brief Create a Gauge metric family with one unlabeled sample.
inline PrometheusMetricFamily make_prometheus_gauge(
const std::string& name,
const std::string& help,
double value) {
PrometheusMetricFamily mf;
mf.name = name;
mf.help = help;
mf.type = PrometheusMetricType::Gauge;
mf.samples.push_back(make_prometheus_sample(name, value));
return mf;
}

/// \brief Create a Gauge metric family with one labeled sample.
inline PrometheusMetricFamily make_prometheus_gauge(
const std::string& name,
const std::string& help,
double value,
std::vector<PrometheusLabel> labels) {
PrometheusMetricFamily mf;
mf.name = name;
mf.help = help;
mf.type = PrometheusMetricType::Gauge;
mf.samples.push_back(make_prometheus_sample(name, value, std::move(labels)));
return mf;
}

/// \brief Create an Untyped metric family with one unlabeled sample.
inline PrometheusMetricFamily make_prometheus_untyped(
const std::string& name,
const std::string& help,
double value) {
PrometheusMetricFamily mf;
mf.name = name;
mf.help = help;
mf.type = PrometheusMetricType::Untyped;
mf.samples.push_back(make_prometheus_sample(name, value));
return mf;
}

/// \brief Create an Untyped metric family with one labeled sample.
inline PrometheusMetricFamily make_prometheus_untyped(
const std::string& name,
const std::string& help,
double value,
std::vector<PrometheusLabel> labels) {
PrometheusMetricFamily mf;
mf.name = name;
mf.help = help;
mf.type = PrometheusMetricType::Untyped;
mf.samples.push_back(make_prometheus_sample(name, value, std::move(labels)));
return mf;
}

/// \brief Append a Counter metric family to the families vector (convenience for on_collect).
inline void add_prometheus_counter(
std::vector<PrometheusMetricFamily>& families,
const std::string& name,
const std::string& help,
double value,
std::vector<PrometheusLabel> labels = {}) {
families.push_back(make_prometheus_counter(name, help, value, std::move(labels)));
}

/// \brief Append a Gauge metric family to the families vector (convenience for on_collect).
inline void add_prometheus_gauge(
std::vector<PrometheusMetricFamily>& families,
const std::string& name,
const std::string& help,
double value,
std::vector<PrometheusLabel> labels = {}) {
families.push_back(make_prometheus_gauge(name, help, value, std::move(labels)));
}

/// \brief Append an Untyped metric family to the families vector (convenience for on_collect).
inline void add_prometheus_untyped(
std::vector<PrometheusMetricFamily>& families,
const std::string& name,
const std::string& help,
double value,
std::vector<PrometheusLabel> labels = {}) {
families.push_back(make_prometheus_untyped(name, help, value, std::move(labels)));
}

} // namespace logit

#endif // _LOGIT_PROMETHEUS_METRIC_BUILDERS_HPP_INCLUDED
2 changes: 2 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ else()
prometheus_text_serializer_test.cpp
prometheus_payload_logger_test.cpp
prometheus_http_server_logger_test.cpp
prometheus_metric_builders_test.cpp
per_logger_isolation_test.cpp
per_logger_mixed_mode_test.cpp
printf_format_macros_test.cpp
Expand Down Expand Up @@ -92,6 +93,7 @@ else()
list(REMOVE_ITEM TEST_SOURCES prometheus_text_serializer_test.cpp)
list(REMOVE_ITEM TEST_SOURCES prometheus_payload_logger_test.cpp)
list(REMOVE_ITEM TEST_SOURCES prometheus_http_server_logger_test.cpp)
list(REMOVE_ITEM TEST_SOURCES prometheus_metric_builders_test.cpp)
endif()
if(LOGIT_WITH_PROMETHEUS AND NOT LOGIT_WITH_PROMETHEUS_SERVER)
list(REMOVE_ITEM TEST_SOURCES prometheus_http_server_logger_test.cpp)
Expand Down
11 changes: 2 additions & 9 deletions tests/prometheus_http_server_logger_test.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <logit/utils.hpp>
#include <logit/loggers/PrometheusHttpServerLogger.hpp>
#include <logit/loggers/prometheus/PrometheusMetricBuilders.hpp>

#if defined(LOGIT_WITH_PROMETHEUS_SERVER)

Expand Down Expand Up @@ -93,15 +94,7 @@ int main() {
logit::PrometheusHttpServerLogger::Config config;
config.port = 43194;
config.on_collect = [](std::vector<logit::PrometheusMetricFamily>& families) {
logit::PrometheusMetricFamily mf;
mf.name = "custom_metric";
mf.help = "A custom metric";
mf.type = logit::PrometheusMetricType::Gauge;
logit::PrometheusSample s;
s.name = "custom_metric";
s.value = 77.0;
mf.samples.push_back(s);
families.push_back(mf);
logit::add_prometheus_gauge(families, "custom_metric", "A custom metric", 77.0);
};
config.start_immediately = false;

Expand Down
120 changes: 120 additions & 0 deletions tests/prometheus_metric_builders_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#include <logit/loggers/prometheus/PrometheusMetricBuilders.hpp>

#ifdef LOGIT_WITH_PROMETHEUS

#include <cassert>
#include <vector>

int main() {
// Test 1: make_prometheus_label
{
auto label = logit::make_prometheus_label("env", "production");
assert(label.name == "env");
assert(label.value == "production");
}

// Test 2: make_prometheus_sample (unlabeled)
{
auto sample = logit::make_prometheus_sample("cpu_seconds_total", 123.45);
assert(sample.name == "cpu_seconds_total");
assert(sample.value == 123.45);
assert(sample.labels.empty());
assert(sample.timestamp_ms == 0);
}

// Test 3: make_prometheus_sample (with labels and timestamp)
{
auto sample = logit::make_prometheus_sample(
"cpu_seconds_total", 67.89,
{logit::make_prometheus_label("cpu", "0")},
1710000000123LL);
assert(sample.name == "cpu_seconds_total");
assert(sample.value == 67.89);
assert(sample.labels.size() == 1);
assert(sample.labels[0].name == "cpu");
assert(sample.labels[0].value == "0");
assert(sample.timestamp_ms == 1710000000123LL);
}

// Test 4: make_prometheus_counter (unlabeled)
{
auto mf = logit::make_prometheus_counter("requests_total", "Total requests", 42.0);
assert(mf.name == "requests_total");
assert(mf.help == "Total requests");
assert(mf.type == logit::PrometheusMetricType::Counter);
assert(mf.samples.size() == 1);
assert(mf.samples[0].name == "requests_total");
assert(mf.samples[0].value == 42.0);
assert(mf.samples[0].labels.empty());
}

// Test 5: make_prometheus_counter (labeled)
{
auto mf = logit::make_prometheus_counter(
"requests_total", "Total requests", 7.0,
{logit::make_prometheus_label("method", "GET")});
assert(mf.samples[0].labels.size() == 1);
assert(mf.samples[0].labels[0].name == "method");
assert(mf.samples[0].labels[0].value == "GET");
}

// Test 6: make_prometheus_gauge (unlabeled)
{
auto mf = logit::make_prometheus_gauge("queue_size", "Current queue size", 3.0);
assert(mf.name == "queue_size");
assert(mf.help == "Current queue size");
assert(mf.type == logit::PrometheusMetricType::Gauge);
assert(mf.samples[0].value == 3.0);
}

// Test 7: make_prometheus_gauge (labeled)
{
auto mf = logit::make_prometheus_gauge(
"temperature_celsius", "Room temperature", 22.5,
{logit::make_prometheus_label("room", "server_room_a")});
assert(mf.type == logit::PrometheusMetricType::Gauge);
assert(mf.samples[0].labels[0].value == "server_room_a");
}

// Test 8: make_prometheus_untyped (unlabeled)
{
auto mf = logit::make_prometheus_untyped("raw_value", "Some raw value", 99.0);
assert(mf.name == "raw_value");
assert(mf.type == logit::PrometheusMetricType::Untyped);
assert(mf.samples[0].value == 99.0);
}

// Test 9: add_prometheus_counter via vector
{
std::vector<logit::PrometheusMetricFamily> families;
logit::add_prometheus_counter(families, "errors_total", "Total errors", 5.0);
assert(families.size() == 1);
assert(families[0].name == "errors_total");
assert(families[0].type == logit::PrometheusMetricType::Counter);

logit::add_prometheus_gauge(
families, "active_sessions", "Active sessions", 12.0,
{logit::make_prometheus_label("region", "eu-west")});
assert(families.size() == 2);
assert(families[1].name == "active_sessions");
assert(families[1].samples[0].labels[0].value == "eu-west");
}

// Test 10: add_prometheus_untyped via vector
{
std::vector<logit::PrometheusMetricFamily> families;
logit::add_prometheus_untyped(families, "misc", "Misc value", 0.0);
assert(families.size() == 1);
assert(families[0].type == logit::PrometheusMetricType::Untyped);
}

return 0;
}

#else

int main() {
return 0;
}

#endif
11 changes: 2 additions & 9 deletions tests/prometheus_payload_logger_test.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <logit/utils.hpp>
#include <logit/loggers/PrometheusPayloadLogger.hpp>
#include <logit/loggers/prometheus/PrometheusMetricBuilders.hpp>

#ifdef LOGIT_WITH_PROMETHEUS

Expand Down Expand Up @@ -111,15 +112,7 @@ int main() {
{
logit::PrometheusPayloadLogger::Config config;
config.on_collect = [](std::vector<logit::PrometheusMetricFamily>& families) {
logit::PrometheusMetricFamily mf;
mf.name = "custom_metric";
mf.help = "A custom metric";
mf.type = logit::PrometheusMetricType::Gauge;
logit::PrometheusSample s;
s.name = "custom_metric";
s.value = 99.0;
mf.samples.push_back(s);
families.push_back(mf);
logit::add_prometheus_gauge(families, "custom_metric", "A custom metric", 99.0);
};

auto logger = std::unique_ptr<logit::PrometheusPayloadLogger>(new logit::PrometheusPayloadLogger(config));
Expand Down
Loading