Skip to content

Commit

Permalink
new(libsinsp): add convert_metric_to_prometheus_text to metrics_colle…
Browse files Browse the repository at this point in the history
…ctor

Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
  • Loading branch information
incertum committed Jan 29, 2024
1 parent 5a4b61f commit 1d4098a
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 3 deletions.
53 changes: 53 additions & 0 deletions userspace/libsinsp/metrics_collector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,22 @@ static const char *const sinsp_stats_v2_resource_utilization_names[] = {
[SINSP_STATS_V2_N_CONTAINERS] = "n_containers",
};

// For simplicity, needs to stay in sync w/ typedef enum metrics_v2_value_unit
static const char *const metrics_unit_name_mappings[] = {
[METRIC_VALUE_UNIT_COUNT] = "COUNT",
[METRIC_VALUE_UNIT_PERC] = "PERC",
[METRIC_VALUE_UNIT_MEMORY_BYTES] = "MEMORY_BYTES",
[METRIC_VALUE_UNIT_MEMORY_KILOBYTES] = "MEMORY_KILOBYTES",
[METRIC_VALUE_UNIT_MEMORY_MEGABYTES] = "MEMORY_MEGABYTES",
[METRIC_VALUE_UNIT_TIME_NS] = "TIME_NS",
};

// For simplicity, needs to stay in sync w/ typedef enum metrics_v2_metric_type
static const char *const metrics_metric_type_name_mappings[] = {
[METRIC_VALUE_MONOTONIC] = "MONOTONIC",
[METRIC_VALUE_NON_MONOTONIC_CURRENT] = "NON_MONOTONIC_CURRENT",
};

namespace libsinsp::metrics {

void metrics_collector::get_rss_vsz_pss_total_memory_and_open_fds(uint32_t &rss, uint32_t &vsz, uint32_t &pss, uint64_t &memory_used_host, uint64_t &open_fds_host)
Expand Down Expand Up @@ -440,6 +456,43 @@ void metrics_collector::snapshot()
}
}

const std::string metrics_collector::convert_metric_to_prometheus_text(std::string metric_name, metrics_v2 metric) const
{
std::string prometheus_text = metric_name;
prometheus_text += "{raw_name=\"" + std::string(metric.name) + "\",unit=\"" + std::string(metrics_unit_name_mappings[metric.unit]) \
+ "\",metric_type=\"" + std::string(metrics_metric_type_name_mappings[metric.metric_type]) + "\"} "; // white space at the end important!
switch (metric.type)
{
case METRIC_VALUE_TYPE_U32:
prometheus_text += std::to_string(metric.value.u32);
break;
case METRIC_VALUE_TYPE_S32:
prometheus_text += std::to_string(metric.value.s32);
break;
case METRIC_VALUE_TYPE_U64:
prometheus_text += std::to_string(metric.value.u64);
break;
case METRIC_VALUE_TYPE_S64:
prometheus_text += std::to_string(metric.value.s64);
break;
case METRIC_VALUE_TYPE_D:
prometheus_text += std::to_string(metric.value.d);
break;
case METRIC_VALUE_TYPE_F:
prometheus_text += std::to_string(metric.value.f);
break;
case METRIC_VALUE_TYPE_I:
prometheus_text += std::to_string(metric.value.i);
break;
default:
break;
}

prometheus_text += " ";
prometheus_text += std::to_string(sinsp_utils::get_current_time_ns());
return prometheus_text;
}

const std::vector<metrics_v2>& metrics_collector::get_metrics() const
{
return m_metrics;
Expand Down
24 changes: 21 additions & 3 deletions userspace/libsinsp/metrics_collector.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,31 @@ class metrics_collector
public:
metrics_collector(sinsp* inspector, uint32_t flags, bool convert_memory_to_mb);

// Method to fill up m_metrics_buffer with metrics; refreshes m_metrics with up-to-date metrics on each call
/*!
\brief Method to fill up m_metrics_buffer with metrics; refreshes m_metrics with up-to-date metrics on each call
*/
void snapshot();

// Method to get a const reference to m_metrics vector
/*!
\brief Method to get a const reference to m_metrics vector
*/
const std::vector<metrics_v2>& get_metrics() const;

// Method to convert memory units; tied to metrics_v2 definitions
/*!
\brief Method to convert a metric to the text-based Prometheus format.
* Reference: https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md
* Note: The design idea is to expose Prometheus metrics by piping text-based formats to new line-delimited fields
* exposed at /metrics in Falco or a similar approach, eliminating the need for implementing a full Prometheus client.
* Example:
* test.memory_used_host{raw_name="memory_used_host", unit="MEMORY_MEGABYTES", metric_type="NON_MONOTONIC_CURRENT"} 15096.000000 1706490801547502000
*
* This method is a work in progress.
*/
const std::string convert_metric_to_prometheus_text(std::string metric_name, metrics_v2 metric) const;

/*!
\brief Method to convert memory units; tied to metrics_v2 definitions
*/
template <typename T>
double convert_memory(metrics_v2_value_unit source_unit, metrics_v2_value_unit dest_unit, T val)
{
Expand Down
14 changes: 14 additions & 0 deletions userspace/libsinsp/test/sinsp_metrics.ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,19 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector)
converted_memory = metrics_collector->convert_memory(METRIC_VALUE_UNIT_MEMORY_MEGABYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, (uint64_t)50);
ASSERT_EQ(converted_memory, 50);

/* Test public convert_metric_to_prometheus_text */
for (const auto& metric: metrics_snapshot)
{
// This resembles the Falco client use case
char metric_name[METRIC_NAME_MAX] = "test.";
strlcat(metric_name, metric.name, sizeof(metric_name));
std::string prometheus_text = metrics_collector->convert_metric_to_prometheus_text(metric_name, metric);
if (strncmp(metric.name, "n_missing_container_images", 17) == 0)
{
std::string prometheus_text_substring = "test.n_missing_container_images{raw_name=\"n_missing_container_images\",unit=\"COUNT\",metric_type=\"NON_MONOTONIC_CURRENT\"} 0";
ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text";
}
ASSERT_GT(prometheus_text.length(), 8);
}
}
#endif

0 comments on commit 1d4098a

Please sign in to comment.