From 09f01eac5ca04b6905e49b27e89f44119e3283cf Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Fri, 26 Jan 2024 21:15:00 +0000 Subject: [PATCH 01/22] update(scap): update scap_stats_v2 schema Signed-off-by: Melissa Kilby --- userspace/libscap/scap_stats_v2.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/userspace/libscap/scap_stats_v2.h b/userspace/libscap/scap_stats_v2.h index e587c8def0..4bf6c6c94e 100644 --- a/userspace/libscap/scap_stats_v2.h +++ b/userspace/libscap/scap_stats_v2.h @@ -59,6 +59,18 @@ typedef enum scap_stats_v2_value_type{ STATS_VALUE_TYPE_I, }scap_stats_v2_value_type; +typedef enum scap_stats_v2_value_unit{ + STATS_VALUE_UNIT_COUNT, + STATS_VALUE_UNIT_PERC, + STATS_VALUE_UNIT_MEMORY_BYTES, + STATS_VALUE_UNIT_MEMORY_KILOBYTES, +}scap_stats_v2_value_unit; + +typedef enum scap_stats_v2_metric_type{ + STATS_VALUE_MONOTONIC, + STATS_VALUE_NON_MONOTONIC_CURRENT, +}scap_stats_v2_metric_type; + /*! \brief Statistics about an in progress capture (including counters and libbpf stats, compare to `bpftool prog show` CLI). */ @@ -67,10 +79,11 @@ typedef struct scap_stats_v2 /* Metadata */ char name[STATS_NAME_MAX]; uint32_t flags; + scap_stats_v2_metric_type metric_type; /* Stats values */ scap_stats_v2_value value; scap_stats_v2_value_type type; - // todo: add unit enum + scap_stats_v2_value_unit unit; }scap_stats_v2; #ifdef __cplusplus From 952225430c4aeffac766e363e10a7940ce9817c7 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Fri, 26 Jan 2024 21:55:06 +0000 Subject: [PATCH 02/22] refactor(libsinsp): new light weight metrics_collector class * simplifies consuming metrics; now combines libscap and libsinsp metrics into one vector * type of metrics uniformely gated via pushing flags down (as previously) * easier memory management * use std::vector as data structure for m_metrics for safer management; this also helps reduce the knowledge the client needs about the metrics or the number of possible metrics; client can just loop over metrics and gate actions based on the metrics string name etc * changes do not affect the hot path and performance is not of primary concern * previous metrics preserved; only code refactor Signed-off-by: Melissa Kilby --- userspace/libsinsp/CMakeLists.txt | 2 +- userspace/libsinsp/metrics_collector.cpp | 467 ++++++++++++++++++ .../libsinsp/{stats.h => metrics_collector.h} | 102 +++- userspace/libsinsp/sinsp.cpp | 15 - userspace/libsinsp/sinsp.h | 12 +- userspace/libsinsp/stats.cpp | 423 ---------------- userspace/libsinsp/test/CMakeLists.txt | 2 +- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 116 +++++ userspace/libsinsp/test/sinsp_stats.ut.cpp | 96 ---- 9 files changed, 669 insertions(+), 566 deletions(-) create mode 100644 userspace/libsinsp/metrics_collector.cpp rename userspace/libsinsp/{stats.h => metrics_collector.h} (63%) delete mode 100644 userspace/libsinsp/stats.cpp create mode 100644 userspace/libsinsp/test/sinsp_metrics.ut.cpp delete mode 100644 userspace/libsinsp/test/sinsp_stats.ut.cpp diff --git a/userspace/libsinsp/CMakeLists.txt b/userspace/libsinsp/CMakeLists.txt index 561f10751e..a15a872a34 100644 --- a/userspace/libsinsp/CMakeLists.txt +++ b/userspace/libsinsp/CMakeLists.txt @@ -98,6 +98,7 @@ add_library(sinsp filter_check_list.cpp ifinfo.cpp memmem.cpp + metrics_collector.cpp logger.cpp parsers.cpp ${LIBS_DIR}/userspace/plugin/plugin_loader.c @@ -109,7 +110,6 @@ add_library(sinsp threadinfo.cpp tuples.cpp sinsp.cpp - stats.cpp token_bucket.cpp utils.cpp value_parser.cpp diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp new file mode 100644 index 0000000000..1b0045662a --- /dev/null +++ b/userspace/libsinsp/metrics_collector.cpp @@ -0,0 +1,467 @@ +// SPDX-License-Identifier: Apache-2.0 +/* +Copyright (C) 2024 The Falco Authors. + +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. + +*/ + +#ifdef __linux__ + +#include +#include +#include +#include +#include +#include + +static const char *const sinsp_stats_v2_resource_utilization_names[] = { + [SINSP_RESOURCE_UTILIZATION_CPU_PERC] = "cpu_usage_perc", + [SINSP_RESOURCE_UTILIZATION_MEMORY_RSS] = "memory_rss", + [SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ] = "memory_vsz", + [SINSP_RESOURCE_UTILIZATION_MEMORY_PSS] = "memory_pss", + [SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY] = "container_memory_used", + [SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST] = "cpu_usage_perc_total_host", + [SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST] = "memory_used_host", + [SINSP_RESOURCE_UTILIZATION_PROCS_HOST] = "procs_running_host", + [SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST] = "open_fds_host", + [SINSP_STATS_V2_N_THREADS] = "n_threads", + [SINSP_STATS_V2_N_FDS] = "n_fds", + [SINSP_STATS_V2_NONCACHED_FD_LOOKUPS] = "n_noncached_fd_lookups", + [SINSP_STATS_V2_CACHED_FD_LOOKUPS] = "n_cached_fd_lookups", + [SINSP_STATS_V2_FAILED_FD_LOOKUPS] = "n_failed_fd_lookups", + [SINSP_STATS_V2_ADDED_FDS] = "n_added_fds", + [SINSP_STATS_V2_REMOVED_FDS] = "n_removed_fds", + [SINSP_STATS_V2_STORED_EVTS] = "n_stored_evts", + [SINSP_STATS_V2_STORE_EVTS_DROPS] = "n_store_evts_drops", + [SINSP_STATS_V2_RETRIEVED_EVTS] = "n_retrieved_evts", + [SINSP_STATS_V2_RETRIEVE_EVTS_DROPS] = "n_retrieve_evts_drops", + [SINSP_STATS_V2_NONCACHED_THREAD_LOOKUPS] = "n_noncached_thread_lookups", + [SINSP_STATS_V2_CACHED_THREAD_LOOKUPS] = "n_cached_thread_lookups", + [SINSP_STATS_V2_FAILED_THREAD_LOOKUPS] = "n_failed_thread_lookups", + [SINSP_STATS_V2_ADDED_THREADS] = "n_added_threads", + [SINSP_STATS_V2_REMOVED_THREADS] = "n_removed_threads", + [SINSP_STATS_V2_N_DROPS_FULL_THREADTABLE] = "n_drops_full_threadtable", + [SINSP_STATS_V2_N_MISSING_CONTAINER_IMAGES] = "n_missing_container_images", + [SINSP_STATS_V2_N_CONTAINERS] = "n_containers", +}; + +namespace libsinsp { +namespace 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) +{ + FILE* f; + char filepath[512]; + char line[512]; + + /* + * Get memory usage of the agent itself (referred to as calling process meaning /proc/self/) + */ + + f = fopen("/proc/self/status", "r"); + if(!f) + { + ASSERT(false); + return; + } + + while(fgets(line, sizeof(line), f) != NULL) + { + if(strncmp(line, "VmSize:", 7) == 0) + { + sscanf(line, "VmSize: %" SCNu32, &vsz); /* memory size returned in kb */ + } + else if(strncmp(line, "VmRSS:", 6) == 0) + { + sscanf(line, "VmRSS: %" SCNu32, &rss); /* memory size returned in kb */ + } + } + fclose(f); + + f = fopen("/proc/self/smaps_rollup", "r"); + if(!f) + { + ASSERT(false); + return; + } + + while(fgets(line, sizeof(line), f) != NULL) + { + if(strncmp(line, "Pss:", 4) == 0) + { + sscanf(line, "Pss: %" SCNu32, &pss); /* memory size returned in kb */ + break; + } + } + fclose(f); + + /* + * Get total host memory usage + */ + + snprintf(filepath, sizeof(filepath), "%s/proc/meminfo", scap_get_host_root()); + f = fopen(filepath, "r"); + if(!f) + { + ASSERT(false); + return; + } + + uint64_t mem_total, mem_free, mem_buff, mem_cache = 0; + + while(fgets(line, sizeof(line), f) != NULL) + { + if(strncmp(line, "MemTotal:", 9) == 0) + { + sscanf(line, "MemTotal: %" SCNu64, &mem_total); /* memory size returned in kb */ + } + else if(strncmp(line, "MemFree:", 8) == 0) + { + sscanf(line, "MemFree: %" SCNu64, &mem_free); /* memory size returned in kb */ + } + else if(strncmp(line, "Buffers:", 8) == 0) + { + sscanf(line, "Buffers: %" SCNu64, &mem_buff); /* memory size returned in kb */ + } + else if(strncmp(line, "Cached:", 7) == 0) + { + sscanf(line, "Cached: %" SCNu64, &mem_cache); /* memory size returned in kb */ + } + } + fclose(f); + memory_used_host = mem_total - mem_free - mem_buff - mem_cache; + + /* + * Get total number of allocated file descriptors (not all open files!) + * File descriptor is a data structure used by a program to get a handle on a file + */ + + snprintf(filepath, sizeof(filepath), "%s/proc/sys/fs/file-nr", scap_get_host_root()); + f = fopen(filepath, "r"); + if(!f) + { + ASSERT(false); + return; + } + int matched_fds = fscanf(f, "%" SCNu64, &open_fds_host); + fclose(f); + + if (matched_fds != 1) { + ASSERT(false); + return; + } +} + +void metrics_collector::get_cpu_usage_and_total_procs(double start_time, double &cpu_usage_perc, double &cpu_usage_perc_total_host, uint32_t &procs_running_host) +{ + FILE* f; + char filepath[512]; + char line[512]; + + struct tms time; + if (times (&time) == (clock_t) -1) + { + return; + } + + /* Number of clock ticks per second, often referred to as USER_HZ / jiffies. */ + long hz = 100; +#ifdef _SC_CLK_TCK + if ((hz = sysconf(_SC_CLK_TCK)) < 0) + { + ASSERT(false); + hz = 100; + } +#endif + /* Current uptime of the host machine in seconds. + * /proc/uptime offers higher precision w/ 2 decimals. + */ + + snprintf(filepath, sizeof(filepath), "%s/proc/uptime", scap_get_host_root()); + f = fopen(filepath, "r"); + if(!f) + { + ASSERT(false); + return; + } + + double machine_uptime_sec = 0; + int matched_uptime = fscanf(f, "%lf", &machine_uptime_sec); + fclose(f); + + if (matched_uptime != 1) { + ASSERT(false); + return; + } + + /* + * Get CPU usage of the agent itself (referred to as calling process meaning /proc/self/) + */ + + /* Current utime is amount of processor time in user mode of calling process. Convert to seconds. */ + double user_sec = (double)time.tms_utime / hz; + + /* Current stime is amount of time the calling process has been scheduled in kernel mode. Convert to seconds. */ + double system_sec = (double)time.tms_stime / hz; + + + /* CPU usage as percentage is computed by dividing the time the process uses the CPU by the + * currently elapsed time of the calling process. Compare to `ps` linux util. */ + double elapsed_sec = machine_uptime_sec - start_time; + if (elapsed_sec > 0) + { + cpu_usage_perc = (double)100.0 * (user_sec + system_sec) / elapsed_sec; + cpu_usage_perc = std::round(cpu_usage_perc * 10.0) / 10.0; // round to 1 decimal + } + + /* + * Get total host CPU usage (all CPUs) as percentage and retrieve number of procs currently running. + */ + + snprintf(filepath, sizeof(filepath), "%s/proc/stat", scap_get_host_root()); + f = fopen(filepath, "r"); + if(!f) + { + ASSERT(false); + return; + } + + /* Need only first 7 columns of /proc/stat cpu line */ + uint64_t user, nice, system, idle, iowait, irq, softirq = 0; + while(fgets(line, sizeof(line), f) != NULL) + { + if(strncmp(line, "cpu ", 4) == 0) + { + /* Always first line in /proc/stat file, unit: jiffies */ + sscanf(line, "cpu %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &user, &nice, &system, &idle, &iowait, &irq, &softirq); + } + else if(strncmp(line, "procs_running ", 14) == 0) + { + sscanf(line, "procs_running %" SCNu32, &procs_running_host); + break; + } + } + fclose(f); + auto sum = user + nice + system + idle + iowait + irq + softirq; + if (sum > 0) + { + cpu_usage_perc_total_host = 100.0 - ((idle * 100.0) / sum); + cpu_usage_perc_total_host = std::round(cpu_usage_perc_total_host * 10.0) / 10.0; // round to 1 decimal + } +} + +uint64_t metrics_collector::get_container_memory_usage() const +{ + /* In Kubernetes `container_memory_working_set_bytes` is the memory measure the OOM killer uses + * and values from `/sys/fs/cgroup/memory/memory.usage_in_bytes` are close enough. + * + * Please note that `kubectl top pod` numbers would reflect the sum of containers in a pod and + * typically libs clients (e.g. Falco) pods contain sidekick containers that use memory as well. + * This metric accounts only for the container with the security monitoring agent running. + */ + uint64_t memory_used = 0; + const char* filepath = getenv(SINSP_AGENT_CGROUP_MEM_PATH_ENV_VAR); + if (filepath == nullptr) + { + filepath = "/sys/fs/cgroup/memory/memory.usage_in_bytes"; + } + + FILE* f = fopen(filepath, "r"); + if(!f) + { + return 0; + } + + /* memory size returned in bytes */ + int fscanf_matched = fscanf(f, "%" SCNu64, &memory_used); + fclose(f); + + if (fscanf_matched != 1) { + return 0; + } + return memory_used; +} + +metrics_collector::metrics_collector(sinsp* inspector, const uint32_t flags) : + m_inspector(inspector), + m_metrics_flags((PPM_SCAP_STATS_KERNEL_COUNTERS | PPM_SCAP_STATS_LIBBPF_STATS | PPM_SCAP_STATS_RESOURCE_UTILIZATION | PPM_SCAP_STATS_STATE_COUNTERS)) +{ + m_metrics_flags = flags; +} + +metrics_collector::~metrics_collector() +{ +} + +void metrics_collector::snapshot() +{ + m_metrics.clear(); + if (!m_inspector) + { + return; + } + + /* + * libscap metrics + */ + + if((m_metrics_flags & PPM_SCAP_STATS_KERNEL_COUNTERS) || (m_metrics_flags & PPM_SCAP_STATS_LIBBPF_STATS)) + { + uint32_t nstats = 0; + int32_t rc = 0; + // libscap metrics: m_metrics_flags are pushed down from consumers' input, + // libbpf stats only collected when ENGINE_FLAG_BPF_STATS_ENABLED aka `kernel.bpf_stats_enabled = 1` + const scap_stats_v2* scap_stats_v2_snapshot = m_inspector->get_capture_stats_v2(m_metrics_flags, &nstats, &rc); + if (scap_stats_v2_snapshot && nstats > 0 && rc == 0) + { + // Move into m_metrics via std::move + m_metrics = std::vector(scap_stats_v2_snapshot, scap_stats_v2_snapshot + nstats); + } + } + + /* + * libsinsp metrics + */ + + if((m_metrics_flags & PPM_SCAP_STATS_RESOURCE_UTILIZATION)) + { + const scap_agent_info* agent_info = m_inspector->get_agent_info(); + uint32_t rss = 0; + uint32_t vsz = 0; + uint32_t pss = 0; + uint64_t memory_used_host = 0; + uint64_t open_fds_host = 0; + double cpu_usage_perc = 0.0; + double cpu_usage_perc_total_host = 0.0; + uint32_t procs_running_host = 0; + get_cpu_usage_and_total_procs(agent_info->start_time, cpu_usage_perc, cpu_usage_perc_total_host, procs_running_host); + get_rss_vsz_pss_total_memory_and_open_fds(rss, vsz, pss, memory_used_host, open_fds_host); + // Resource utilization of the agent itself + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC], \ + PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_D, STATS_VALUE_UNIT_PERC, STATS_VALUE_NON_MONOTONIC_CURRENT, cpu_usage_perc)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_RSS], \ + PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_MEMORY_KILOBYTES, STATS_VALUE_NON_MONOTONIC_CURRENT, rss)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ], \ + PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_MEMORY_KILOBYTES, STATS_VALUE_NON_MONOTONIC_CURRENT, vsz)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_PSS], \ + PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_MEMORY_KILOBYTES, STATS_VALUE_NON_MONOTONIC_CURRENT, pss)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY], \ + PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_MEMORY_BYTES, STATS_VALUE_NON_MONOTONIC_CURRENT, get_container_memory_usage())); + // Resource utilization / load indicators of the underlying host + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST], \ + PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_D, STATS_VALUE_UNIT_PERC, STATS_VALUE_NON_MONOTONIC_CURRENT, cpu_usage_perc_total_host)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_PROCS_HOST], \ + PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_COUNT, STATS_VALUE_NON_MONOTONIC_CURRENT, procs_running_host)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST], \ + PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_MEMORY_KILOBYTES, STATS_VALUE_NON_MONOTONIC_CURRENT, memory_used_host)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST], \ + PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_NON_MONOTONIC_CURRENT, open_fds_host)); + } + + if((m_metrics_flags & PPM_SCAP_STATS_STATE_COUNTERS)) + { + std::shared_ptr sinsp_stats_v2 = m_inspector->get_sinsp_stats_v2(); + + if (!sinsp_stats_v2) + { + m_inspector->set_sinsp_stats_v2_enabled(); + sinsp_stats_v2 = m_inspector->get_sinsp_stats_v2(); + } + + if (sinsp_stats_v2) + { + uint64_t n_fds = 0; + uint64_t n_threads = 0; + if (m_inspector->m_thread_manager) + { + n_threads = m_inspector->m_thread_manager->get_thread_count(); + threadinfo_map_t* threadtable = m_inspector->m_thread_manager->get_threads(); + if (threadtable) + { + threadtable->loop([&] (sinsp_threadinfo& tinfo) { + sinsp_fdtable* fdtable = tinfo.get_fd_table(); + if (fdtable != nullptr) + { + n_fds += fdtable->size(); + } + return true; + }); + } + } + + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_THREADS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_NON_MONOTONIC_CURRENT, n_threads)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_FDS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_NON_MONOTONIC_CURRENT, n_fds)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_FD_LOOKUPS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_noncached_fd_lookups)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_FD_LOOKUPS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_cached_fd_lookups)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_FD_LOOKUPS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_failed_fd_lookups)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_FDS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_added_fds)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_FDS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_removed_fds)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORED_EVTS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_stored_evts)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORE_EVTS_DROPS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_store_evts_drops)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVED_EVTS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_retrieved_evts)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVE_EVTS_DROPS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_retrieve_evts_drops)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_THREAD_LOOKUPS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_noncached_thread_lookups)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_THREAD_LOOKUPS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_cached_thread_lookups)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_THREAD_LOOKUPS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_failed_thread_lookups)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_THREADS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_added_threads)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_THREADS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_removed_threads)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_DROPS_FULL_THREADTABLE], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_drops_full_threadtable)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_MISSING_CONTAINER_IMAGES], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_COUNT, STATS_VALUE_NON_MONOTONIC_CURRENT, sinsp_stats_v2->m_n_missing_container_images)); + m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_CONTAINERS], \ + PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_COUNT, STATS_VALUE_NON_MONOTONIC_CURRENT, sinsp_stats_v2->m_n_containers)); + } + } +} + +const std::vector& metrics_collector::get_metrics() const +{ + return m_metrics; +} + +// Static member init +std::unique_ptr metrics_collector::mc_instance = nullptr; + +// Factory method implementation +std::unique_ptr metrics_collector::create(sinsp* inspector, const uint32_t flags) +{ + if (!mc_instance) + { + mc_instance = std::unique_ptr(new metrics_collector(inspector, flags)); + } + + return std::move(mc_instance); +} + +} // namespace metrics +} // namespace libsinsp + +#endif diff --git a/userspace/libsinsp/stats.h b/userspace/libsinsp/metrics_collector.h similarity index 63% rename from userspace/libsinsp/stats.h rename to userspace/libsinsp/metrics_collector.h index a64e7c87f9..730e10762c 100644 --- a/userspace/libsinsp/stats.h +++ b/userspace/libsinsp/metrics_collector.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 /* -Copyright (C) 2023 The Falco Authors. +Copyright (C) 2024 The Falco Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -76,23 +76,87 @@ enum sinsp_stats_v2_resource_utilization }; #ifdef __linux__ + namespace libsinsp { -namespace stats { - - /*! - \brief Retrieve current sinsp stats v2 including resource utilization metrics. - \param agent_info Pointer to a \ref scap_agent_info containing relevant constants from the agent start up moment. - \param thread_manager Pointer to a \ref thread_manager to access threadtable properties. - \param stats_v2 Pointer to a \ref sinsp_stats_v2 containing counters related to the sinsp state tables (e.g. adding, removing, storing, failed lookup activities). - \param buffer Pointer to a \ref scap_stats_v2 pre-allocated sinsp_stats_v2_buffer (aka scap_stats_v2 schema). - \param nstats Pointer reflecting number of statistics in returned buffer - \param rc Pointer to return code - \note Intended to be called once every x hours. - - \return Pointer to a \ref scap_stats_v2 buffer filled with the current sinsp stats v2 including resource utilization metrics. - */ - const scap_stats_v2* get_sinsp_stats_v2(uint32_t flags, const scap_agent_info* agent_info, sinsp_thread_manager* thread_manager, std::shared_ptr stats_v2, scap_stats_v2* buffer, uint32_t* nstats, int32_t* rc); - -} -} +namespace metrics { + +class metrics_collector +{ +public: + // Factory method for creating instances + static std::unique_ptr create(sinsp* inspector, const uint32_t flags); + ~metrics_collector(); + + // Method to fill up m_metrics_buffer with current metrics; refreshes m_metrics with up-to-date metrics on each call + void snapshot(); + + // Method to get a const reference to m_metrics buffer + const std::vector& get_metrics() const; + +private: + metrics_collector(sinsp* inspector, const uint32_t flags); + static std::unique_ptr mc_instance; + sinsp* m_inspector; + uint32_t m_metrics_flags; + std::vector m_metrics; + + void 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); + void get_cpu_usage_and_total_procs(double start_time, double &cpu_usage_perc, double &cpu_usage_perc_total_host, uint32_t &procs_running_host); + uint64_t get_container_memory_usage() const; + + template + const scap_stats_v2 new_stat(const char* name, uint32_t flags, scap_stats_v2_value_type type, scap_stats_v2_value_unit unit, scap_stats_v2_metric_type metric_type, T val) + { + scap_stats_v2 stat; + strlcpy(stat.name, name, STATS_NAME_MAX); + stat.flags = flags; + stat.type = type; + stat.unit = unit; + stat.metric_type = metric_type; + set_stat_value(stat, type, val); + return stat; + } + + template + void set_stat_value(scap_stats_v2& stat, scap_stats_v2_value_type type, T val) + { + switch (type) + { + case STATS_VALUE_TYPE_U32: + stat.type = STATS_VALUE_TYPE_U32; + stat.value.u32 = static_cast(val); + break; + case STATS_VALUE_TYPE_S32: + stat.type = STATS_VALUE_TYPE_S32; + stat.value.s32 = static_cast(val); + break; + case STATS_VALUE_TYPE_U64: + stat.type = STATS_VALUE_TYPE_U64; + stat.value.u64 = static_cast(val); + break; + case STATS_VALUE_TYPE_S64: + stat.type = STATS_VALUE_TYPE_S64; + stat.value.s64 = static_cast(val); + break; + case STATS_VALUE_TYPE_D: + stat.type = STATS_VALUE_TYPE_D; + stat.value.d = static_cast(val); + break; + case STATS_VALUE_TYPE_F: + stat.type = STATS_VALUE_TYPE_F; + stat.value.f = static_cast(val); + break; + case STATS_VALUE_TYPE_I: + stat.type = STATS_VALUE_TYPE_I; + stat.value.i = static_cast(val); + break; + default: + break; + } + } +}; + +} // namespace metrics +} // namespace libsinsp + #endif diff --git a/userspace/libsinsp/sinsp.cpp b/userspace/libsinsp/sinsp.cpp index 29313a2b78..8a778ea9ca 100644 --- a/userspace/libsinsp/sinsp.cpp +++ b/userspace/libsinsp/sinsp.cpp @@ -1740,21 +1740,6 @@ const scap_agent_info* sinsp::get_agent_info() const return m_agent_info; } -scap_stats_v2* sinsp::get_sinsp_stats_v2_buffer() -{ - return m_sinsp_stats_v2_buffer; -} - -const scap_stats_v2* sinsp::get_sinsp_stats_v2_buffer() const -{ - return m_sinsp_stats_v2_buffer; -} - -std::shared_ptr sinsp::get_sinsp_stats_v2() -{ - return m_sinsp_stats_v2; -} - std::shared_ptr sinsp::get_sinsp_stats_v2() const { return m_sinsp_stats_v2; diff --git a/userspace/libsinsp/sinsp.h b/userspace/libsinsp/sinsp.h index eab132b1b7..13c2c6972b 100644 --- a/userspace/libsinsp/sinsp.h +++ b/userspace/libsinsp/sinsp.h @@ -70,7 +70,7 @@ limitations under the License. #include #include #include -#include +#include #include #include #include @@ -464,20 +464,10 @@ class SINSP_PUBLIC sinsp : public capture_stats_source */ const scap_agent_info* get_agent_info() const; - /*! - \brief Return sinsp stats v2 static size buffer w/ scap_stats_v2 schema. - - \note sinsp stats may be refactored near-term. - */ - scap_stats_v2* get_sinsp_stats_v2_buffer(); - const scap_stats_v2* get_sinsp_stats_v2_buffer() const; - /*! \brief Return sinsp stats v2 containing continually updated counters around thread and fd state tables. - \note sinsp stats may be refactored near-term. */ - std::shared_ptr get_sinsp_stats_v2(); std::shared_ptr get_sinsp_stats_v2() const; /*! diff --git a/userspace/libsinsp/stats.cpp b/userspace/libsinsp/stats.cpp deleted file mode 100644 index 4a4a95182b..0000000000 --- a/userspace/libsinsp/stats.cpp +++ /dev/null @@ -1,423 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -/* -Copyright (C) 2023 The Falco Authors. - -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. - -*/ - -#ifdef __linux__ - -#include -#include -#include -#include -#include -#include - -static const char *const sinsp_stats_v2_resource_utilization_names[] = { - [SINSP_RESOURCE_UTILIZATION_CPU_PERC] = "cpu_usage_perc", - [SINSP_RESOURCE_UTILIZATION_MEMORY_RSS] = "memory_rss", - [SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ] = "memory_vsz", - [SINSP_RESOURCE_UTILIZATION_MEMORY_PSS] = "memory_pss", - [SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY] = "container_memory_used", - [SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST] = "cpu_usage_perc_total_host", - [SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST] = "memory_used_host", - [SINSP_RESOURCE_UTILIZATION_PROCS_HOST] = "procs_running_host", - [SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST] = "open_fds_host", - [SINSP_STATS_V2_N_THREADS] = "n_threads", - [SINSP_STATS_V2_N_FDS] = "n_fds", - [SINSP_STATS_V2_NONCACHED_FD_LOOKUPS] = "n_noncached_fd_lookups", - [SINSP_STATS_V2_CACHED_FD_LOOKUPS] = "n_cached_fd_lookups", - [SINSP_STATS_V2_FAILED_FD_LOOKUPS] = "n_failed_fd_lookups", - [SINSP_STATS_V2_ADDED_FDS] = "n_added_fds", - [SINSP_STATS_V2_REMOVED_FDS] = "n_removed_fds", - [SINSP_STATS_V2_STORED_EVTS] = "n_stored_evts", - [SINSP_STATS_V2_STORE_EVTS_DROPS] = "n_store_evts_drops", - [SINSP_STATS_V2_RETRIEVED_EVTS] = "n_retrieved_evts", - [SINSP_STATS_V2_RETRIEVE_EVTS_DROPS] = "n_retrieve_evts_drops", - [SINSP_STATS_V2_NONCACHED_THREAD_LOOKUPS] = "n_noncached_thread_lookups", - [SINSP_STATS_V2_CACHED_THREAD_LOOKUPS] = "n_cached_thread_lookups", - [SINSP_STATS_V2_FAILED_THREAD_LOOKUPS] = "n_failed_thread_lookups", - [SINSP_STATS_V2_ADDED_THREADS] = "n_added_threads", - [SINSP_STATS_V2_REMOVED_THREADS] = "n_removed_threads", - [SINSP_STATS_V2_N_DROPS_FULL_THREADTABLE] = "n_drops_full_threadtable", - [SINSP_STATS_V2_N_MISSING_CONTAINER_IMAGES] = "n_missing_container_images", - [SINSP_STATS_V2_N_CONTAINERS] = "n_containers", -}; - -void 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) -{ - FILE* f; - char filepath[512]; - char line[512]; - - /* - * Get memory usage of the agent itself (referred to as calling process meaning /proc/self/) - */ - - f = fopen("/proc/self/status", "r"); - if(!f) - { - ASSERT(false); - return; - } - - while(fgets(line, sizeof(line), f) != NULL) - { - if(strncmp(line, "VmSize:", 7) == 0) - { - sscanf(line, "VmSize: %" SCNu32, &vsz); /* memory size returned in kb */ - } - else if(strncmp(line, "VmRSS:", 6) == 0) - { - sscanf(line, "VmRSS: %" SCNu32, &rss); /* memory size returned in kb */ - } - } - fclose(f); - - f = fopen("/proc/self/smaps_rollup", "r"); - if(!f) - { - ASSERT(false); - return; - } - - while(fgets(line, sizeof(line), f) != NULL) - { - if(strncmp(line, "Pss:", 4) == 0) - { - sscanf(line, "Pss: %" SCNu32, &pss); /* memory size returned in kb */ - break; - } - } - fclose(f); - - /* - * Get total host memory usage - */ - - snprintf(filepath, sizeof(filepath), "%s/proc/meminfo", scap_get_host_root()); - f = fopen(filepath, "r"); - if(!f) - { - ASSERT(false); - return; - } - - uint64_t mem_total, mem_free, mem_buff, mem_cache = 0; - - while(fgets(line, sizeof(line), f) != NULL) - { - if(strncmp(line, "MemTotal:", 9) == 0) - { - sscanf(line, "MemTotal: %" SCNu64, &mem_total); /* memory size returned in kb */ - } - else if(strncmp(line, "MemFree:", 8) == 0) - { - sscanf(line, "MemFree: %" SCNu64, &mem_free); /* memory size returned in kb */ - } - else if(strncmp(line, "Buffers:", 8) == 0) - { - sscanf(line, "Buffers: %" SCNu64, &mem_buff); /* memory size returned in kb */ - } - else if(strncmp(line, "Cached:", 7) == 0) - { - sscanf(line, "Cached: %" SCNu64, &mem_cache); /* memory size returned in kb */ - } - } - fclose(f); - memory_used_host = mem_total - mem_free - mem_buff - mem_cache; - - /* - * Get total number of allocated file descriptors (not all open files!) - * File descriptor is a data structure used by a program to get a handle on a file - */ - - snprintf(filepath, sizeof(filepath), "%s/proc/sys/fs/file-nr", scap_get_host_root()); - f = fopen(filepath, "r"); - if(!f) - { - ASSERT(false); - return; - } - int matched_fds = fscanf(f, "%" SCNu64, &open_fds_host); - fclose(f); - - if (matched_fds != 1) { - ASSERT(false); - return; - } -} - -void get_cpu_usage_and_total_procs(double start_time, double &cpu_usage_perc, double &cpu_usage_perc_total_host, uint32_t &procs_running_host) -{ - FILE* f; - char filepath[512]; - char line[512]; - - struct tms time; - if (times (&time) == (clock_t) -1) - { - return; - } - - /* Number of clock ticks per second, often referred to as USER_HZ / jiffies. */ - long hz = 100; -#ifdef _SC_CLK_TCK - if ((hz = sysconf(_SC_CLK_TCK)) < 0) - { - ASSERT(false); - hz = 100; - } -#endif - /* Current uptime of the host machine in seconds. - * /proc/uptime offers higher precision w/ 2 decimals. - */ - - snprintf(filepath, sizeof(filepath), "%s/proc/uptime", scap_get_host_root()); - f = fopen(filepath, "r"); - if(!f) - { - ASSERT(false); - return; - } - - double machine_uptime_sec = 0; - int matched_uptime = fscanf(f, "%lf", &machine_uptime_sec); - fclose(f); - - if (matched_uptime != 1) { - ASSERT(false); - return; - } - - /* - * Get CPU usage of the agent itself (referred to as calling process meaning /proc/self/) - */ - - /* Current utime is amount of processor time in user mode of calling process. Convert to seconds. */ - double user_sec = (double)time.tms_utime / hz; - - /* Current stime is amount of time the calling process has been scheduled in kernel mode. Convert to seconds. */ - double system_sec = (double)time.tms_stime / hz; - - - /* CPU usage as percentage is computed by dividing the time the process uses the CPU by the - * currently elapsed time of the calling process. Compare to `ps` linux util. */ - double elapsed_sec = machine_uptime_sec - start_time; - if (elapsed_sec > 0) - { - cpu_usage_perc = (double)100.0 * (user_sec + system_sec) / elapsed_sec; - cpu_usage_perc = std::round(cpu_usage_perc * 10.0) / 10.0; // round to 1 decimal - } - - /* - * Get total host CPU usage (all CPUs) as percentage and retrieve number of procs currently running. - */ - - snprintf(filepath, sizeof(filepath), "%s/proc/stat", scap_get_host_root()); - f = fopen(filepath, "r"); - if(!f) - { - ASSERT(false); - return; - } - - /* Need only first 7 columns of /proc/stat cpu line */ - uint64_t user, nice, system, idle, iowait, irq, softirq = 0; - while(fgets(line, sizeof(line), f) != NULL) - { - if(strncmp(line, "cpu ", 4) == 0) - { - /* Always first line in /proc/stat file, unit: jiffies */ - sscanf(line, "cpu %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &user, &nice, &system, &idle, &iowait, &irq, &softirq); - } - else if(strncmp(line, "procs_running ", 14) == 0) - { - sscanf(line, "procs_running %" SCNu32, &procs_running_host); - break; - } - } - fclose(f); - auto sum = user + nice + system + idle + iowait + irq + softirq; - if (sum > 0) - { - cpu_usage_perc_total_host = 100.0 - ((idle * 100.0) / sum); - cpu_usage_perc_total_host = std::round(cpu_usage_perc_total_host * 10.0) / 10.0; // round to 1 decimal - } -} - -uint64_t get_container_memory_usage() -{ - /* In Kubernetes `container_memory_working_set_bytes` is the memory measure the OOM killer uses - * and values from `/sys/fs/cgroup/memory/memory.usage_in_bytes` are close enough. - * -> contrasted numbers from multiple sources in a real-life Kubernetes cluster. - * - * Please note that `kubectl top pod` numbers would reflect the sum of containers in a pod and - * typically libs clients (e.g. Falco) pods contain sidekick containers that use memory as well. - * This metric accounts only for the container with the security monitoring agent running. - */ - uint64_t memory_used = 0; - const char* filepath = getenv(SINSP_AGENT_CGROUP_MEM_PATH_ENV_VAR); - if (filepath == nullptr) - { - filepath = "/sys/fs/cgroup/memory/memory.usage_in_bytes"; - } - - FILE* f = fopen(filepath, "r"); - if(!f) - { - return 0; - } - - /* memory size returned in bytes */ - int fscanf_matched = fscanf(f, "%" SCNu64, &memory_used); - fclose(f); - - if (fscanf_matched != 1) { - return 0; - } - return memory_used; -} - -const scap_stats_v2* libsinsp::stats::get_sinsp_stats_v2(uint32_t flags, const scap_agent_info* agent_info, sinsp_thread_manager* thread_manager, std::shared_ptr stats_v2, scap_stats_v2* buffer, uint32_t* nstats, int32_t* rc) -{ - if (!buffer) - { - *nstats = 0; - *rc = SCAP_FAILURE; - return NULL; - } - - *nstats = 0; - if((flags & PPM_SCAP_STATS_RESOURCE_UTILIZATION)) - { - uint32_t rss = 0; - uint32_t vsz = 0; - uint32_t pss = 0; - uint64_t memory_used_host = 0; - uint64_t open_fds_host = 0; - double cpu_usage_perc = 0.0; - double cpu_usage_perc_total_host = 0.0; - uint32_t procs_running_host = 0; - - if(strncmp(buffer[SINSP_RESOURCE_UTILIZATION_CPU_PERC].name, sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC], 15) != 0) - { - // Init - for(uint32_t i = SINSP_RESOURCE_UTILIZATION_CPU_PERC; i < SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST + 1; i++) - { - buffer[i].flags = PPM_SCAP_STATS_RESOURCE_UTILIZATION; - strlcpy(buffer[i].name, sinsp_stats_v2_resource_utilization_names[i], STATS_NAME_MAX); - } - - buffer[SINSP_RESOURCE_UTILIZATION_CPU_PERC].type = STATS_VALUE_TYPE_D; - buffer[SINSP_RESOURCE_UTILIZATION_MEMORY_RSS].type = STATS_VALUE_TYPE_U32; - buffer[SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ].type = STATS_VALUE_TYPE_U32; - buffer[SINSP_RESOURCE_UTILIZATION_MEMORY_PSS].type = STATS_VALUE_TYPE_U32; - buffer[SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST].type = STATS_VALUE_TYPE_D; - buffer[SINSP_RESOURCE_UTILIZATION_PROCS_HOST].type = STATS_VALUE_TYPE_U32; - buffer[SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST].type = STATS_VALUE_TYPE_U64; - } - - // Get stats / metrics snapshot - - get_cpu_usage_and_total_procs(agent_info->start_time, cpu_usage_perc, cpu_usage_perc_total_host, procs_running_host); - get_rss_vsz_pss_total_memory_and_open_fds(rss, vsz, pss, memory_used_host, open_fds_host); - - buffer[SINSP_RESOURCE_UTILIZATION_CPU_PERC].value.d = cpu_usage_perc; - buffer[SINSP_RESOURCE_UTILIZATION_MEMORY_RSS].value.u32 = rss; - buffer[SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ].value.u32 = vsz; - buffer[SINSP_RESOURCE_UTILIZATION_MEMORY_PSS].value.u32 = pss; - buffer[SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY].value.u64 = get_container_memory_usage(); - buffer[SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST].value.d = cpu_usage_perc_total_host; - buffer[SINSP_RESOURCE_UTILIZATION_PROCS_HOST].value.u32 = procs_running_host; - buffer[SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST].value.u64 = memory_used_host; - buffer[SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST].value.u64 = open_fds_host; - - *nstats = SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST + 1; - - } - - if((flags & PPM_SCAP_STATS_STATE_COUNTERS) && stats_v2) - { - if(strncmp(buffer[SINSP_STATS_V2_N_THREADS].name, sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_THREADS], 10) != 0) - { - // Init - for(uint32_t i = SINSP_STATS_V2_N_THREADS; i < SINSP_MAX_STATS_V2; i++) - { - buffer[i].flags = PPM_SCAP_STATS_STATE_COUNTERS; - strlcpy(buffer[i].name, sinsp_stats_v2_resource_utilization_names[i], STATS_NAME_MAX); - } - - buffer[SINSP_STATS_V2_NONCACHED_FD_LOOKUPS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_CACHED_FD_LOOKUPS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_FAILED_FD_LOOKUPS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_ADDED_FDS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_REMOVED_FDS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_STORED_EVTS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_STORE_EVTS_DROPS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_RETRIEVED_EVTS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_RETRIEVE_EVTS_DROPS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_NONCACHED_THREAD_LOOKUPS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_CACHED_THREAD_LOOKUPS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_FAILED_THREAD_LOOKUPS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_ADDED_THREADS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_REMOVED_THREADS].type = STATS_VALUE_TYPE_U64; - buffer[SINSP_STATS_V2_N_DROPS_FULL_THREADTABLE].type = STATS_VALUE_TYPE_U32; - buffer[SINSP_STATS_V2_N_MISSING_CONTAINER_IMAGES].type = STATS_VALUE_TYPE_U32; - buffer[SINSP_STATS_V2_N_CONTAINERS].type = STATS_VALUE_TYPE_U32; - - } - - // Get stats / metrics snapshot - - buffer[SINSP_STATS_V2_N_THREADS].value.u64 = thread_manager->get_thread_count(); - buffer[SINSP_STATS_V2_N_FDS].value.u64 = 0; - threadinfo_map_t* threadtable = thread_manager->get_threads(); - threadtable->loop([&] (sinsp_threadinfo& tinfo) { - sinsp_fdtable* fdtable = tinfo.get_fd_table(); - if (fdtable != nullptr) - { - buffer[SINSP_STATS_V2_N_FDS].value.u64 += fdtable->size(); - } - return true; - }); - buffer[SINSP_STATS_V2_NONCACHED_FD_LOOKUPS].value.u64 = stats_v2->m_n_noncached_fd_lookups; - buffer[SINSP_STATS_V2_CACHED_FD_LOOKUPS].value.u64 = stats_v2->m_n_cached_fd_lookups; - buffer[SINSP_STATS_V2_FAILED_FD_LOOKUPS].value.u64 = stats_v2->m_n_failed_fd_lookups; - buffer[SINSP_STATS_V2_ADDED_FDS].value.u64 = stats_v2->m_n_added_fds; - buffer[SINSP_STATS_V2_REMOVED_FDS].value.u64 = stats_v2->m_n_removed_fds; - buffer[SINSP_STATS_V2_STORED_EVTS].value.u64 = stats_v2->m_n_stored_evts; - buffer[SINSP_STATS_V2_STORE_EVTS_DROPS].value.u64 = stats_v2->m_n_store_evts_drops; - buffer[SINSP_STATS_V2_RETRIEVED_EVTS].value.u64 = stats_v2->m_n_retrieved_evts; - buffer[SINSP_STATS_V2_RETRIEVE_EVTS_DROPS].value.u64 = stats_v2->m_n_retrieve_evts_drops; - buffer[SINSP_STATS_V2_NONCACHED_THREAD_LOOKUPS].value.u64 = stats_v2->m_n_noncached_thread_lookups; - buffer[SINSP_STATS_V2_CACHED_THREAD_LOOKUPS].value.u64 = stats_v2->m_n_cached_thread_lookups; - buffer[SINSP_STATS_V2_FAILED_THREAD_LOOKUPS].value.u64 = stats_v2->m_n_failed_thread_lookups; - buffer[SINSP_STATS_V2_ADDED_THREADS].value.u64 = stats_v2->m_n_added_threads; - buffer[SINSP_STATS_V2_REMOVED_THREADS].value.u64 = stats_v2->m_n_removed_threads; - buffer[SINSP_STATS_V2_N_DROPS_FULL_THREADTABLE].value.u32 = stats_v2->m_n_drops_full_threadtable; - buffer[SINSP_STATS_V2_N_MISSING_CONTAINER_IMAGES].value.u32 = stats_v2->m_n_missing_container_images; - buffer[SINSP_STATS_V2_N_CONTAINERS].value.u32 = stats_v2->m_n_containers; - - *nstats = SINSP_MAX_STATS_V2; - } - - *rc = SCAP_SUCCESS; - return buffer; -} - -#endif diff --git a/userspace/libsinsp/test/CMakeLists.txt b/userspace/libsinsp/test/CMakeLists.txt index 6f7601bc04..85ef11a3ab 100644 --- a/userspace/libsinsp/test/CMakeLists.txt +++ b/userspace/libsinsp/test/CMakeLists.txt @@ -114,7 +114,7 @@ set(LIBSINSP_UNIT_TESTS_SOURCES dns_manager.ut.cpp eventformatter.ut.cpp savefile.ut.cpp - sinsp_stats.ut.cpp + sinsp_metrics.ut.cpp thread_table.ut.cpp ifinfo.ut.cpp public_sinsp_API/event_related.cpp diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp new file mode 100644 index 0000000000..ff66e67fc1 --- /dev/null +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: Apache-2.0 +/* +Copyright (C) 2024 The Falco Authors. + +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. + +*/ +#ifdef __linux__ + +#include +#include "sinsp_with_test_input.h" +#include + +TEST_F(sinsp_with_test_input, sinsp_metrics_collector) +{ + m_inspector.set_sinsp_stats_v2_enabled(); + // Extra call to verify that we don't fail + m_inspector.set_sinsp_stats_v2_enabled(); + DEFAULT_TREE + auto evt = generate_random_event(p2_t1_tid); + ASSERT_EQ(get_field_as_string(evt, "proc.nthreads"), "3"); + + /* Snapshot current metrics and get the updated metrics_snapshot buffer */ + uint32_t test_metrics_flags = (PPM_SCAP_STATS_KERNEL_COUNTERS | PPM_SCAP_STATS_LIBBPF_STATS | PPM_SCAP_STATS_RESOURCE_UTILIZATION | PPM_SCAP_STATS_STATE_COUNTERS); + std::unique_ptr metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); + metrics_collector->snapshot(); + auto metrics_snapshot = metrics_collector->get_metrics(); + ASSERT_EQ(metrics_snapshot.size(), 28); + + /* These names should always be available, note that we currently can't check for the merged scap stats metrics here */ + std::unordered_set minimal_stats_names = {"cpu_usage_perc", "memory_rss", "open_fds_host", \ + "n_threads", "n_fds", "n_added_fds", "n_added_threads", "n_removed_threads", "n_containers"}; + + for(const auto& stat_name : minimal_stats_names) + { + uint32_t i = 0; + for (const auto& stat : metrics_snapshot) + { + if(stat_name.compare(stat.name) == 0) + { + break; + } + i++; + } + if(i == metrics_snapshot.size()) + { + FAIL() << "unable to find stat '" << stat_name << "' in metrics_snapshot buffer"; + } + } + + /* Assert some values are greater than 0 */ + ASSERT_GT(metrics_snapshot[SINSP_RESOURCE_UTILIZATION_MEMORY_RSS].value.u32, 0); + ASSERT_GT(metrics_snapshot[SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ].value.u32, 0); + ASSERT_GT(metrics_snapshot[SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST].value.d, 0); + ASSERT_GT(metrics_snapshot[SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST].value.u64, 0); + ASSERT_GT(metrics_snapshot[SINSP_RESOURCE_UTILIZATION_PROCS_HOST].value.u32, 0); + ASSERT_GT(metrics_snapshot[SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST].value.u64, 0); + + ASSERT_GT(metrics_snapshot[SINSP_STATS_V2_N_THREADS].value.u64, 0); + ASSERT_GT(metrics_snapshot[SINSP_STATS_V2_N_FDS].value.u64, 0); + ASSERT_GT(metrics_snapshot[SINSP_STATS_V2_ADDED_THREADS].value.u64, 0); + + /* Empty call */ + metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, 0); + metrics_collector->snapshot(); + metrics_snapshot = metrics_collector->get_metrics(); + ASSERT_EQ(metrics_snapshot.size(), 0); + + /* Just checking that we don't crash w/ selective flags */ + test_metrics_flags = 0; + test_metrics_flags |= PPM_SCAP_STATS_KERNEL_COUNTERS; // 20, but can't test it here it's 0 + test_metrics_flags |= PPM_SCAP_STATS_LIBBPF_STATS; // 21 (x86_64 machine), but can't test it here it's 0 + metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); + metrics_collector->snapshot(); + metrics_snapshot = metrics_collector->get_metrics(); + ASSERT_EQ(metrics_snapshot.size(), 0); + + test_metrics_flags = 0; + test_metrics_flags |= PPM_SCAP_STATS_RESOURCE_UTILIZATION; + metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); + metrics_collector->snapshot(); + metrics_snapshot = metrics_collector->get_metrics(); + ASSERT_EQ(metrics_snapshot.size(), 9); + + test_metrics_flags = 0; + test_metrics_flags |= PPM_SCAP_STATS_STATE_COUNTERS; + metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); + metrics_collector->snapshot(); + metrics_snapshot = metrics_collector->get_metrics(); + ASSERT_EQ(metrics_snapshot.size(), 19); + + test_metrics_flags = (PPM_SCAP_STATS_RESOURCE_UTILIZATION | PPM_SCAP_STATS_STATE_COUNTERS); + metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); + metrics_collector->snapshot(); + metrics_snapshot = metrics_collector->get_metrics(); + ASSERT_EQ(metrics_snapshot.size(), 28); + + /* Check we don't crash if inspector is invalid and verify metrics vector is cleared */ + test_metrics_flags = (PPM_SCAP_STATS_RESOURCE_UTILIZATION | PPM_SCAP_STATS_STATE_COUNTERS); + metrics_collector = libsinsp::metrics::metrics_collector::create(nullptr, test_metrics_flags); + metrics_collector->snapshot(); + metrics_snapshot = metrics_collector->get_metrics(); + ASSERT_EQ(metrics_snapshot.size(), 0); + +} +#endif diff --git a/userspace/libsinsp/test/sinsp_stats.ut.cpp b/userspace/libsinsp/test/sinsp_stats.ut.cpp deleted file mode 100644 index 64caaa8bf3..0000000000 --- a/userspace/libsinsp/test/sinsp_stats.ut.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -/* -Copyright (C) 2023 The Falco Authors. - -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. - -*/ -#ifdef __linux__ - -#include -#include "sinsp_with_test_input.h" -#include - -TEST_F(sinsp_with_test_input, sinsp_stats_v2_resource_utilization) -{ - m_inspector.set_sinsp_stats_v2_enabled(); - // Extra call to see we don't fail - m_inspector.set_sinsp_stats_v2_enabled(); - // Adopted from test: TEST_F(sinsp_with_test_input, PROC_FILTER_nthreads) - DEFAULT_TREE - /* we call a random event to obtain an event associated with this thread info */ - auto evt = generate_random_event(p2_t1_tid); - ASSERT_EQ(get_field_as_string(evt, "proc.nthreads"), "3"); - - const scap_agent_info* agent_info = m_inspector.get_agent_info(); - uint32_t nstats = 0; - int32_t rc; - const scap_stats_v2* sinsp_stats_v2_snapshot; - auto buffer = m_inspector.get_sinsp_stats_v2_buffer(); - auto sinsp_stats_v2_counters = m_inspector.get_sinsp_stats_v2(); - sinsp_thread_manager* thread_manager = m_inspector.m_thread_manager.get(); - uint32_t flags = 0; - sinsp_stats_v2_snapshot = libsinsp::stats::get_sinsp_stats_v2(flags, agent_info, thread_manager, sinsp_stats_v2_counters, buffer, &nstats, &rc); - ASSERT_EQ(nstats, 0); - ASSERT_EQ(rc, SCAP_SUCCESS); - /* Extra call */ - flags |= PPM_SCAP_STATS_RESOURCE_UTILIZATION; - sinsp_stats_v2_snapshot = libsinsp::stats::get_sinsp_stats_v2(flags, agent_info, thread_manager, sinsp_stats_v2_counters, buffer, &nstats, &rc); - ASSERT_EQ(nstats, SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST + 1); - ASSERT_EQ(rc, SCAP_SUCCESS); - - flags = (PPM_SCAP_STATS_RESOURCE_UTILIZATION | PPM_SCAP_STATS_STATE_COUNTERS); - sinsp_stats_v2_snapshot = libsinsp::stats::get_sinsp_stats_v2(flags, agent_info, thread_manager, sinsp_stats_v2_counters, buffer, &nstats, &rc); - ASSERT_EQ(nstats, SINSP_MAX_STATS_V2); - ASSERT_EQ(rc, SCAP_SUCCESS); - - /* These names should always be available */ - std::unordered_set minimal_stats_names = {"cpu_usage_perc", "memory_rss", "open_fds_host", "n_threads", "n_fds", "n_added_fds", "n_added_threads", "n_removed_threads", "n_containers"}; - - uint32_t i = 0; - for(const auto& stat_name : minimal_stats_names) - { - for(i = 0; i < nstats; i++) - { - if(stat_name.compare(sinsp_stats_v2_snapshot[i].name) == 0) - { - break; - } - } - - if(i == nstats) - { - FAIL() << "unable to find stat '" << stat_name << "' in the sinsp_stats_v2 buffer"; - } - } - - /* Assert values are greater than 0 */ - ASSERT_GT(sinsp_stats_v2_snapshot[SINSP_RESOURCE_UTILIZATION_MEMORY_RSS].value.u32, 0); - ASSERT_GT(sinsp_stats_v2_snapshot[SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ].value.u32, 0); - ASSERT_GT(sinsp_stats_v2_snapshot[SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST].value.d, 0); - ASSERT_GT(sinsp_stats_v2_snapshot[SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST].value.u64, 0); - ASSERT_GT(sinsp_stats_v2_snapshot[SINSP_RESOURCE_UTILIZATION_PROCS_HOST].value.u32, 0); - ASSERT_GT(sinsp_stats_v2_snapshot[SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST].value.u64, 0); - - ASSERT_GT(sinsp_stats_v2_snapshot[SINSP_STATS_V2_N_THREADS].value.u64, 0); - ASSERT_GT(sinsp_stats_v2_snapshot[SINSP_STATS_V2_N_FDS].value.u64, 0); - ASSERT_GT(sinsp_stats_v2_snapshot[SINSP_STATS_V2_ADDED_THREADS].value.u64, 0); - - /* Empty call */ - nstats = 0; - flags = 0; - sinsp_stats_v2_snapshot = libsinsp::stats::get_sinsp_stats_v2(flags, agent_info, thread_manager, sinsp_stats_v2_counters, buffer, &nstats, &rc); - ASSERT_EQ(nstats, 0); - ASSERT_EQ(rc, SCAP_SUCCESS); -} -#endif From 535d592a6cd239a1d5d3b1d8ede68c52b0404b72 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Fri, 26 Jan 2024 23:16:01 +0000 Subject: [PATCH 03/22] refactor: naming change stats -> metrics if applicable + complete metrics_v2 schema updates Signed-off-by: Melissa Kilby --- test/libscap/test_suites/engines/bpf/bpf.cpp | 12 +- .../libscap/test_suites/engines/kmod/kmod.cpp | 12 +- .../engines/modern_bpf/modern_bpf.cpp | 12 +- userspace/libpman/include/libpman.h | 8 +- userspace/libpman/src/state.h | 4 +- userspace/libpman/src/stats.c | 31 +++-- userspace/libscap/engine/bpf/bpf.h | 4 +- userspace/libscap/engine/bpf/scap_bpf.c | 40 +++--- userspace/libscap/engine/gvisor/gvisor.cpp | 2 +- userspace/libscap/engine/gvisor/gvisor.h | 6 +- .../libscap/engine/gvisor/scap_gvisor.cpp | 10 +- userspace/libscap/engine/kmod/kmod.h | 4 +- userspace/libscap/engine/kmod/scap_kmod.c | 14 +- .../engine/modern_bpf/scap_modern_bpf.c | 6 +- userspace/libscap/engine/noop/noop.c | 2 +- userspace/libscap/engine/noop/noop.h | 4 +- .../engine/source_plugin/source_plugin.c | 10 +- .../engine/source_plugin/source_plugin.h | 4 +- .../libscap/examples/01-open/scap_open.c | 8 +- userspace/libscap/metrics_v2.h | 91 +++++++++++++ userspace/libscap/scap.c | 2 +- userspace/libscap/scap.h | 6 +- userspace/libscap/scap_stats_v2.h | 91 ------------- userspace/libscap/scap_vtable.h | 6 +- userspace/libsinsp/capture_stats_source.h | 4 +- userspace/libsinsp/metrics_collector.cpp | 128 +++++++++--------- userspace/libsinsp/metrics_collector.h | 68 +++++----- userspace/libsinsp/sinsp.cpp | 4 +- userspace/libsinsp/sinsp.h | 8 +- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 14 +- 30 files changed, 319 insertions(+), 296 deletions(-) create mode 100644 userspace/libscap/metrics_v2.h delete mode 100644 userspace/libscap/scap_stats_v2.h diff --git a/test/libscap/test_suites/engines/bpf/bpf.cpp b/test/libscap/test_suites/engines/bpf/bpf.cpp index 62985dafea..60439298cb 100644 --- a/test/libscap/test_suites/engines/bpf/bpf.cpp +++ b/test/libscap/test_suites/engines/bpf/bpf.cpp @@ -129,17 +129,17 @@ TEST(bpf, double_scap_stats_call) scap_close(h); } -TEST(bpf, scap_stats_v2_check_results) +TEST(bpf, metrics_v2_check_results) { char error_buffer[SCAP_LASTERR_SIZE] = {0}; int ret = 0; scap_t* h = open_bpf_engine(error_buffer, &ret, 4 * 4096, LIBSCAP_TEST_BPF_PROBE_PATH); ASSERT_FALSE(!h || ret != SCAP_SUCCESS) << "unable to open bpf engine: " << error_buffer << std::endl; - uint32_t flags = PPM_SCAP_STATS_KERNEL_COUNTERS | PPM_SCAP_STATS_LIBBPF_STATS; + uint32_t flags = METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS; uint32_t nstats; int32_t rc; - const scap_stats_v2* stats_v2 = scap_get_stats_v2(h, flags, &nstats, &rc); + const metrics_v2* stats_v2 = scap_get_stats_v2(h, flags, &nstats, &rc); ASSERT_EQ(rc, SCAP_SUCCESS); ASSERT_GT(nstats, 0); @@ -169,14 +169,14 @@ TEST(bpf, scap_stats_v2_check_results) scap_close(h); } -TEST(bpf, double_scap_stats_v2_call) +TEST(bpf, double_metrics_v2_call) { char error_buffer[SCAP_LASTERR_SIZE] = {0}; int ret = 0; scap_t* h = open_bpf_engine(error_buffer, &ret, 4 * 4096, LIBSCAP_TEST_BPF_PROBE_PATH); ASSERT_FALSE(!h || ret != SCAP_SUCCESS) << "unable to open bpf engine: " << error_buffer << std::endl; - uint32_t flags = PPM_SCAP_STATS_KERNEL_COUNTERS | PPM_SCAP_STATS_LIBBPF_STATS; + uint32_t flags = METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS; uint32_t nstats; int32_t rc; @@ -192,7 +192,7 @@ TEST(bpf, double_scap_stats_v2_call) scap_close(h); } -TEST(bpf, scap_stats_v2_check_empty) +TEST(bpf, metrics_v2_check_empty) { char error_buffer[SCAP_LASTERR_SIZE] = {0}; int ret = 0; diff --git a/test/libscap/test_suites/engines/kmod/kmod.cpp b/test/libscap/test_suites/engines/kmod/kmod.cpp index 33520c6ee7..8518111ff7 100644 --- a/test/libscap/test_suites/engines/kmod/kmod.cpp +++ b/test/libscap/test_suites/engines/kmod/kmod.cpp @@ -184,17 +184,17 @@ TEST(kmod, double_scap_stats_call) scap_close(h); } -TEST(kmod, scap_stats_v2_check_results) +TEST(kmod, metrics_v2_check_results) { char error_buffer[SCAP_LASTERR_SIZE] = {0}; int ret = 0; scap_t* h = open_kmod_engine(error_buffer, &ret, 4 * 4096, LIBSCAP_TEST_KERNEL_MODULE_PATH); ASSERT_FALSE(!h || ret != SCAP_SUCCESS) << "unable to open kmod engine: " << error_buffer << std::endl; - uint32_t flags = PPM_SCAP_STATS_KERNEL_COUNTERS | PPM_SCAP_STATS_LIBBPF_STATS; + uint32_t flags = METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS; uint32_t nstats; int32_t rc; - const scap_stats_v2* stats_v2 = scap_get_stats_v2(h, flags, &nstats, &rc); + const metrics_v2* stats_v2 = scap_get_stats_v2(h, flags, &nstats, &rc); ASSERT_EQ(rc, SCAP_SUCCESS); ASSERT_GT(nstats, 0); @@ -220,14 +220,14 @@ TEST(kmod, scap_stats_v2_check_results) scap_close(h); } -TEST(kmod, double_scap_stats_v2_call) +TEST(kmod, double_metrics_v2_call) { char error_buffer[SCAP_LASTERR_SIZE] = {0}; int ret = 0; scap_t* h = open_kmod_engine(error_buffer, &ret, 4 * 4096, LIBSCAP_TEST_KERNEL_MODULE_PATH); ASSERT_FALSE(!h || ret != SCAP_SUCCESS) << "unable to open kmod engine: " << error_buffer << std::endl; - uint32_t flags = PPM_SCAP_STATS_KERNEL_COUNTERS; + uint32_t flags = METRICS_V2_KERNEL_COUNTERS; uint32_t nstats; int32_t rc; @@ -243,7 +243,7 @@ TEST(kmod, double_scap_stats_v2_call) scap_close(h); } -TEST(kmod, scap_stats_v2_check_empty) +TEST(kmod, metrics_v2_check_empty) { char error_buffer[SCAP_LASTERR_SIZE] = {0}; int ret = 0; diff --git a/test/libscap/test_suites/engines/modern_bpf/modern_bpf.cpp b/test/libscap/test_suites/engines/modern_bpf/modern_bpf.cpp index 4c9486ae4c..f59a976c23 100644 --- a/test/libscap/test_suites/engines/modern_bpf/modern_bpf.cpp +++ b/test/libscap/test_suites/engines/modern_bpf/modern_bpf.cpp @@ -248,7 +248,7 @@ TEST(modern_bpf, double_scap_stats_call) scap_close(h); } -TEST(modern_bpf, scap_stats_v2_check_results) +TEST(modern_bpf, metrics_v2_check_results) { char error_buffer[FILENAME_MAX] = {0}; int ret = 0; @@ -256,10 +256,10 @@ TEST(modern_bpf, scap_stats_v2_check_results) scap_t* h = open_modern_bpf_engine(error_buffer, &ret, 1 * 1024 * 1024, 0, false); ASSERT_EQ(!h || ret != SCAP_SUCCESS, false) << "unable to open modern bpf engine with one single shared ring buffer: " << error_buffer << std::endl; - uint32_t flags = PPM_SCAP_STATS_KERNEL_COUNTERS | PPM_SCAP_STATS_LIBBPF_STATS; + uint32_t flags = METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS; uint32_t nstats; int32_t rc; - const scap_stats_v2* stats_v2 = scap_get_stats_v2(h, flags, &nstats, &rc); + const metrics_v2* stats_v2 = scap_get_stats_v2(h, flags, &nstats, &rc); ASSERT_EQ(rc, SCAP_SUCCESS); ASSERT_GT(nstats, 0); @@ -289,7 +289,7 @@ TEST(modern_bpf, scap_stats_v2_check_results) scap_close(h); } -TEST(modern_bpf, scap_stats_v2_check_empty) +TEST(modern_bpf, metrics_v2_check_empty) { char error_buffer[FILENAME_MAX] = {0}; int ret = 0; @@ -306,7 +306,7 @@ TEST(modern_bpf, scap_stats_v2_check_empty) scap_close(h); } -TEST(modern_bpf, double_scap_stats_v2_call) +TEST(modern_bpf, double_metrics_v2_call) { char error_buffer[FILENAME_MAX] = {0}; int ret = 0; @@ -314,7 +314,7 @@ TEST(modern_bpf, double_scap_stats_v2_call) scap_t* h = open_modern_bpf_engine(error_buffer, &ret, 1 * 1024 * 1024, 0, false); ASSERT_EQ(!h || ret != SCAP_SUCCESS, false) << "unable to open modern bpf engine with one single shared ring buffer: " << error_buffer << std::endl; - uint32_t flags = PPM_SCAP_STATS_KERNEL_COUNTERS | PPM_SCAP_STATS_LIBBPF_STATS; + uint32_t flags = METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS; uint32_t nstats; int32_t rc; diff --git a/userspace/libpman/include/libpman.h b/userspace/libpman/include/libpman.h index 39b877125d..fa279c5003 100644 --- a/userspace/libpman/include/libpman.h +++ b/userspace/libpman/include/libpman.h @@ -29,7 +29,7 @@ extern "C" #endif /* Forward declare them */ - struct scap_stats_v2; + struct metrics_v2; struct scap_stats; /* `libpman` return values convention: @@ -300,15 +300,15 @@ extern "C" int pman_get_scap_stats(struct scap_stats* scap_stats_struct); /** - * @brief Return a `scap_stats_v2` struct filled with statistics. + * @brief Return a `metrics_v2` struct filled with statistics. * * @param flags holding statistics category flags. * @param nstats number of stats allocated. * @param rc return code, SCAP_FAILURE in case of error. * - * @return pointer to `struct scap_stats_v2` + * @return pointer to `struct metrics_v2` */ - struct scap_stats_v2* pman_get_scap_stats_v2(uint32_t flags, uint32_t* nstats, int32_t* rc); + struct metrics_v2* pman_get_metrics_v2(uint32_t flags, uint32_t* nstats, int32_t* rc); /** * @brief Receive an array with `nCPUs` elements. For every CPU diff --git a/userspace/libpman/src/state.h b/userspace/libpman/src/state.h index b8b3fd1d03..15c8da58a2 100644 --- a/userspace/libpman/src/state.h +++ b/userspace/libpman/src/state.h @@ -32,7 +32,7 @@ limitations under the License. /* Pay attention this need to be bumped every time we add a new bpf program that is directly attached into the kernel */ #define MODERN_BPF_PROG_ATTACHED_MAX 9 -struct scap_stats_v2; +struct metrics_v2; struct internal_state { @@ -57,7 +57,7 @@ struct internal_state int32_t attached_progs_fds[MODERN_BPF_PROG_ATTACHED_MAX]; /* file descriptors of attached programs, used to collect stats */ uint16_t n_attached_progs; /* number of attached progs */ - struct scap_stats_v2* stats; /* array of stats collected by libpman */ + struct metrics_v2* stats; /* array of stats collected by libpman */ falcosecurity_log_fn log_fn; }; diff --git a/userspace/libpman/src/stats.c b/userspace/libpman/src/stats.c index 452cf0587e..810c66639e 100644 --- a/userspace/libpman/src/stats.c +++ b/userspace/libpman/src/stats.c @@ -139,7 +139,7 @@ int pman_get_scap_stats(struct scap_stats *stats) return errno; } -struct scap_stats_v2 *pman_get_scap_stats_v2(uint32_t flags, uint32_t *nstats, int32_t *rc) +struct metrics_v2 *pman_get_metrics_v2(uint32_t flags, uint32_t *nstats, int32_t *rc) { *rc = SCAP_FAILURE; /* This is the expected number of stats */ @@ -150,17 +150,17 @@ struct scap_stats_v2 *pman_get_scap_stats_v2(uint32_t flags, uint32_t *nstats, i /* If it is the first time we call this function we populate the stats */ if(g_state.stats == NULL) { - g_state.stats = (scap_stats_v2 *)calloc(*nstats, sizeof(scap_stats_v2)); + g_state.stats = (metrics_v2 *)calloc(*nstats, sizeof(metrics_v2)); if(g_state.stats == NULL) { - pman_print_error("unable to allocate memory for 'scap_stats_v2' array"); + pman_print_error("unable to allocate memory for 'metrics_v2' array"); return NULL; } } /* KERNEL COUNTER STATS */ - if(flags & PPM_SCAP_STATS_KERNEL_COUNTERS) + if(flags & METRICS_V2_KERNEL_COUNTERS) { char error_message[MAX_ERROR_MESSAGE_LEN]; int counter_maps_fd = bpf_map__fd(g_state.skel->maps.counter_maps); @@ -172,10 +172,12 @@ struct scap_stats_v2 *pman_get_scap_stats_v2(uint32_t flags, uint32_t *nstats, i for(uint32_t stat = 0; stat < MODERN_BPF_MAX_KERNEL_COUNTERS_STATS; stat++) { - g_state.stats[stat].type = STATS_VALUE_TYPE_U64; - g_state.stats[stat].flags = PPM_SCAP_STATS_KERNEL_COUNTERS; + g_state.stats[stat].type = METRIC_VALUE_TYPE_U64; + g_state.stats[stat].flags = METRICS_V2_KERNEL_COUNTERS; + g_state.stats[stat].unit = METRIC_VALUE_UNIT_COUNT; + g_state.stats[stat].metric_type = METRIC_VALUE_MONOTONIC; g_state.stats[stat].value.u64 = 0; - strlcpy(g_state.stats[stat].name, modern_bpf_kernel_counters_stats_names[stat], STATS_NAME_MAX); + strlcpy(g_state.stats[stat].name, modern_bpf_kernel_counters_stats_names[stat], METRIC_NAME_MAX); } /* We always take statistics from all the CPUs, even if some of them are not online. @@ -221,7 +223,7 @@ struct scap_stats_v2 *pman_get_scap_stats_v2(uint32_t flags, uint32_t *nstats, i * Meanwhile, we can simulate perf comparisons between future LSM hooks and sys enter and exit tracepoints * via leveraging syscall selection mechanisms `handle->curr_sc_set`. */ - if((flags & PPM_SCAP_STATS_LIBBPF_STATS)) + if((flags & METRICS_V2_LIBBPF_STATS)) { for(int bpf_prog = 0; bpf_prog < MODERN_BPF_PROG_ATTACHED_MAX; bpf_prog++) { @@ -247,21 +249,28 @@ struct scap_stats_v2 *pman_get_scap_stats_v2(uint32_t flags, uint32_t *nstats, i pman_print_error("no enough space for all the stats"); return NULL; } - g_state.stats[offset].type = STATS_VALUE_TYPE_U64; - g_state.stats[offset].flags = PPM_SCAP_STATS_LIBBPF_STATS; - strlcpy(g_state.stats[offset].name, info.name, STATS_NAME_MAX); + g_state.stats[offset].type = METRIC_VALUE_TYPE_U64; + g_state.stats[offset].flags = METRICS_V2_LIBBPF_STATS; + strlcpy(g_state.stats[offset].name, info.name, METRIC_NAME_MAX); switch(stat) { case RUN_CNT: strlcat(g_state.stats[offset].name, modern_bpf_libbpf_stats_names[RUN_CNT], sizeof(g_state.stats[offset].name)); + g_state.stats[stat].flags = METRICS_V2_KERNEL_COUNTERS; + g_state.stats[stat].unit = METRIC_VALUE_UNIT_COUNT; + g_state.stats[stat].metric_type = METRIC_VALUE_MONOTONIC; g_state.stats[offset].value.u64 = info.run_cnt; break; case RUN_TIME_NS: strlcat(g_state.stats[offset].name, modern_bpf_libbpf_stats_names[RUN_TIME_NS], sizeof(g_state.stats[offset].name)); + g_state.stats[stat].unit = METRIC_VALUE_UNIT_TIME_NS; + g_state.stats[stat].metric_type = METRIC_VALUE_MONOTONIC; g_state.stats[offset].value.u64 = info.run_time_ns; break; case AVG_TIME_NS: strlcat(g_state.stats[offset].name, modern_bpf_libbpf_stats_names[AVG_TIME_NS], sizeof(g_state.stats[offset].name)); + g_state.stats[stat].unit = METRIC_VALUE_UNIT_TIME_NS; + g_state.stats[stat].metric_type = METRIC_VALUE_NON_MONOTONIC_CURRENT; g_state.stats[offset].value.u64 = 0; if(info.run_cnt > 0) { diff --git a/userspace/libscap/engine/bpf/bpf.h b/userspace/libscap/engine/bpf/bpf.h index fee573ab43..b317be073b 100644 --- a/userspace/libscap/engine/bpf/bpf.h +++ b/userspace/libscap/engine/bpf/bpf.h @@ -22,7 +22,7 @@ limitations under the License. #include #include #include -#include +#include #include // @@ -58,7 +58,7 @@ struct bpf_engine uint64_t m_api_version; uint64_t m_schema_version; bool capturing; - scap_stats_v2* m_stats; + metrics_v2* m_stats; uint32_t m_nstats; uint64_t m_flags; }; diff --git a/userspace/libscap/engine/bpf/scap_bpf.c b/userspace/libscap/engine/bpf/scap_bpf.c index 6d017059ff..7edce64bbe 100644 --- a/userspace/libscap/engine/bpf/scap_bpf.c +++ b/userspace/libscap/engine/bpf/scap_bpf.c @@ -856,7 +856,7 @@ static int load_all_progs(struct bpf_engine *handle) return SCAP_SUCCESS; } -static int allocate_scap_stats_v2(struct bpf_engine *handle) +static int allocate_metrics_v2(struct bpf_engine *handle) { int nprogs_attached = 0; for(int j=0; j < BPF_PROG_ATTACHED_MAX; j++) @@ -867,7 +867,7 @@ static int allocate_scap_stats_v2(struct bpf_engine *handle) } } handle->m_nstats = (BPF_MAX_KERNEL_COUNTERS_STATS + (nprogs_attached * BPF_MAX_LIBBPF_STATS)); - handle->m_stats = (scap_stats_v2 *)malloc(handle->m_nstats * sizeof(scap_stats_v2)); + handle->m_stats = (metrics_v2*)malloc(handle->m_nstats * sizeof(metrics_v2)); if(!handle->m_stats) { @@ -1515,10 +1515,10 @@ int32_t scap_bpf_load( return SCAP_FAILURE; } - /* allocate_scap_stats_v2 dynamically based on number of valid m_attached_progs, + /* allocate_metrics_v2 dynamically based on number of valid m_attached_progs, * In the future, it may change when and how we perform the allocation. */ - if(allocate_scap_stats_v2(handle) != SCAP_SUCCESS) + if(allocate_metrics_v2(handle) != SCAP_SUCCESS) { return SCAP_FAILURE; } @@ -1703,7 +1703,7 @@ int32_t scap_bpf_get_stats(struct scap_engine_handle engine, OUT scap_stats* sta return SCAP_SUCCESS; } -const struct scap_stats_v2* scap_bpf_get_stats_v2(struct scap_engine_handle engine, uint32_t flags, OUT uint32_t* nstats, OUT int32_t* rc) +const struct metrics_v2* scap_bpf_get_stats_v2(struct scap_engine_handle engine, uint32_t flags, OUT uint32_t* nstats, OUT int32_t* rc) { struct bpf_engine *handle = engine.m_handle; int ret; @@ -1711,7 +1711,7 @@ const struct scap_stats_v2* scap_bpf_get_stats_v2(struct scap_engine_handle engi int offset = 0; // offset in stats buffer *nstats = 0; uint32_t nstats_allocated = handle->m_nstats; - scap_stats_v2* stats = handle->m_stats; + metrics_v2* stats = handle->m_stats; if (!stats) { *rc = SCAP_FAILURE; @@ -1721,18 +1721,20 @@ const struct scap_stats_v2* scap_bpf_get_stats_v2(struct scap_engine_handle engi // we can't collect libbpf stats if bpf stats are not enabled if (!(handle->m_flags & ENGINE_FLAG_BPF_STATS_ENABLED)) { - flags &= ~PPM_SCAP_STATS_LIBBPF_STATS; + flags &= ~METRICS_V2_LIBBPF_STATS; } - if ((flags & PPM_SCAP_STATS_KERNEL_COUNTERS) && (BPF_MAX_KERNEL_COUNTERS_STATS <= nstats_allocated)) + if ((flags & METRICS_V2_KERNEL_COUNTERS) && (BPF_MAX_KERNEL_COUNTERS_STATS <= nstats_allocated)) { /* KERNEL SIDE STATS COUNTERS */ for(int stat = 0; stat < BPF_MAX_KERNEL_COUNTERS_STATS; stat++) { - stats[stat].type = STATS_VALUE_TYPE_U64; - stats[stat].flags = PPM_SCAP_STATS_KERNEL_COUNTERS; + stats[stat].type = METRIC_VALUE_TYPE_U64; + stats[stat].flags = METRICS_V2_KERNEL_COUNTERS; + stats[stat].metric_type = METRIC_VALUE_MONOTONIC; + stats[stat].unit = METRIC_VALUE_UNIT_COUNT; stats[stat].value.u64 = 0; - strlcpy(stats[stat].name, bpf_kernel_counters_stats_names[stat], STATS_NAME_MAX); + strlcpy(stats[stat].name, bpf_kernel_counters_stats_names[stat], METRIC_NAME_MAX); } for(int cpu = 0; cpu < handle->m_ncpus; cpu++) @@ -1781,7 +1783,7 @@ const struct scap_stats_v2* scap_bpf_get_stats_v2(struct scap_engine_handle engi * Please note that libbpf stats are available only on kernels >= 5.1, they could be backported but * it's possible that in some of our supported kernels they won't be available. */ - if ((flags & PPM_SCAP_STATS_LIBBPF_STATS)) + if ((flags & METRICS_V2_LIBBPF_STATS)) { for(int bpf_prog = 0; bpf_prog < BPF_PROG_ATTACHED_MAX; bpf_prog++) { @@ -1805,8 +1807,8 @@ const struct scap_stats_v2* scap_bpf_get_stats_v2(struct scap_engine_handle engi { break; } - stats[offset].type = STATS_VALUE_TYPE_U64; - stats[offset].flags = PPM_SCAP_STATS_LIBBPF_STATS; + stats[offset].type = METRIC_VALUE_TYPE_U64; + stats[offset].flags = METRICS_V2_LIBBPF_STATS; /* The possibility to specify a name for a BPF program was introduced in kernel 4.15 * https://github.com/torvalds/linux/commit/cb4d2b3f03d8eed90be3a194e5b54b734ec4bbe9 * So it's possible that in some of our supported kernels `info.name` will be "". @@ -1814,25 +1816,31 @@ const struct scap_stats_v2* scap_bpf_get_stats_v2(struct scap_engine_handle engi if(strlen(info.name) == 0) { /* Fallback on the elf section name */ - strlcpy(stats[offset].name, handle->m_attached_progs[bpf_prog].name, STATS_NAME_MAX); + strlcpy(stats[offset].name, handle->m_attached_progs[bpf_prog].name, METRIC_NAME_MAX); } else { - strlcpy(stats[offset].name, info.name, STATS_NAME_MAX); + strlcpy(stats[offset].name, info.name, METRIC_NAME_MAX); } switch(stat) { case RUN_CNT: strlcat(stats[offset].name, bpf_libbpf_stats_names[RUN_CNT], sizeof(stats[offset].name)); stats[offset].value.u64 = info.run_cnt; + stats[offset].unit = METRIC_VALUE_UNIT_COUNT; + stats[offset].metric_type = METRIC_VALUE_MONOTONIC; break; case RUN_TIME_NS: strlcat(stats[offset].name, bpf_libbpf_stats_names[RUN_TIME_NS], sizeof(stats[offset].name)); stats[offset].value.u64 = info.run_time_ns; + stats[offset].unit = METRIC_VALUE_UNIT_TIME_NS; + stats[offset].metric_type = METRIC_VALUE_MONOTONIC; break; case AVG_TIME_NS: strlcat(stats[offset].name, bpf_libbpf_stats_names[AVG_TIME_NS], sizeof(stats[offset].name)); stats[offset].value.u64 = 0; + stats[offset].unit = METRIC_VALUE_UNIT_TIME_NS; + stats[offset].metric_type = METRIC_VALUE_NON_MONOTONIC_CURRENT; if (info.run_cnt > 0) { stats[offset].value.u64 = info.run_time_ns / info.run_cnt; diff --git a/userspace/libscap/engine/gvisor/gvisor.cpp b/userspace/libscap/engine/gvisor/gvisor.cpp index be91630b47..6d300792fc 100644 --- a/userspace/libscap/engine/gvisor/gvisor.cpp +++ b/userspace/libscap/engine/gvisor/gvisor.cpp @@ -189,7 +189,7 @@ static int32_t gvisor_get_stats(scap_engine_handle engine, scap_stats* stats) return engine.m_handle->get_stats(stats); } -static const struct scap_stats_v2* gvisor_get_stats_v2(scap_engine_handle engine, uint32_t flags, uint32_t* nstats, int32_t* rc) +static const struct metrics_v2* gvisor_get_stats_v2(scap_engine_handle engine, uint32_t flags, uint32_t* nstats, int32_t* rc) { return engine.m_handle->get_stats_v2(flags, nstats, rc); } diff --git a/userspace/libscap/engine/gvisor/gvisor.h b/userspace/libscap/engine/gvisor/gvisor.h index 76a96ae00b..38bb3bba22 100644 --- a/userspace/libscap/engine/gvisor/gvisor.h +++ b/userspace/libscap/engine/gvisor/gvisor.h @@ -28,7 +28,7 @@ limitations under the License. #include #include #include -#include +#include #include #include @@ -183,7 +183,7 @@ class engine { uint32_t get_vxid(uint64_t pid) const; int32_t get_stats(scap_stats *stats) const; - const struct scap_stats_v2* get_stats_v2(uint32_t flags, uint32_t* nstats, int32_t* rc); + const struct metrics_v2* get_stats_v2(uint32_t flags, uint32_t* nstats, int32_t* rc); private: int32_t process_message_from_fd(int fd); void free_sandbox_buffers(); @@ -221,7 +221,7 @@ class engine { } m_gvisor_stats; // Stats v2. - scap_stats_v2 m_stats[scap_gvisor::stats::MAX_GVISOR_COUNTERS_STATS]; + metrics_v2 m_stats[scap_gvisor::stats::MAX_GVISOR_COUNTERS_STATS]; }; diff --git a/userspace/libscap/engine/gvisor/scap_gvisor.cpp b/userspace/libscap/engine/gvisor/scap_gvisor.cpp index 29b50329bb..5f89ebf093 100644 --- a/userspace/libscap/engine/gvisor/scap_gvisor.cpp +++ b/userspace/libscap/engine/gvisor/scap_gvisor.cpp @@ -418,10 +418,10 @@ int32_t engine::get_stats(scap_stats *stats) const return SCAP_SUCCESS; } -const scap_stats_v2* engine::get_stats_v2(uint32_t flags, uint32_t* nstats, int32_t* rc) +const metrics_v2* engine::get_stats_v2(uint32_t flags, uint32_t* nstats, int32_t* rc) { *nstats = scap_gvisor::stats::MAX_GVISOR_COUNTERS_STATS; - scap_stats_v2* stats = engine::m_stats; + metrics_v2* stats = engine::m_stats; if (!stats) { *nstats = 0; @@ -432,9 +432,11 @@ const scap_stats_v2* engine::get_stats_v2(uint32_t flags, uint32_t* nstats, int3 /* GVISOR STATS COUNTERS */ for(uint32_t stat = 0; stat < scap_gvisor::stats::MAX_GVISOR_COUNTERS_STATS; stat++) { - stats[stat].type = STATS_VALUE_TYPE_U64; + stats[stat].type = METRIC_VALUE_TYPE_U64; + stats[stat].unit = METRIC_VALUE_UNIT_COUNT; + stats[stat].metric_type = METRIC_VALUE_MONOTONIC; stats[stat].value.u64 = 0; - strlcpy(stats[stat].name, gvisor_counters_stats_names[stat], STATS_NAME_MAX); + strlcpy(stats[stat].name, gvisor_counters_stats_names[stat], METRIC_NAME_MAX); } stats[scap_gvisor::stats::GVISOR_N_EVTS].value.u64 = m_gvisor_stats.n_evts; stats[scap_gvisor::stats::GVISOR_N_DROPS_BUG].value.u64 = m_gvisor_stats.n_drops_parsing; diff --git a/userspace/libscap/engine/kmod/kmod.h b/userspace/libscap/engine/kmod/kmod.h index 5fce56c5ab..10d573805f 100644 --- a/userspace/libscap/engine/kmod/kmod.h +++ b/userspace/libscap/engine/kmod/kmod.h @@ -20,7 +20,7 @@ limitations under the License. #include #include #include -#include +#include #include @@ -32,5 +32,5 @@ struct kmod_engine uint64_t m_api_version; uint64_t m_schema_version; bool capturing; - scap_stats_v2 m_stats[KMOD_MAX_KERNEL_COUNTERS_STATS]; + metrics_v2 m_stats[KMOD_MAX_KERNEL_COUNTERS_STATS]; }; diff --git a/userspace/libscap/engine/kmod/scap_kmod.c b/userspace/libscap/engine/kmod/scap_kmod.c index 59c1001d00..136727efb7 100644 --- a/userspace/libscap/engine/kmod/scap_kmod.c +++ b/userspace/libscap/engine/kmod/scap_kmod.c @@ -578,13 +578,13 @@ int32_t scap_kmod_get_stats(struct scap_engine_handle engine, scap_stats* stats) return SCAP_SUCCESS; } -const struct scap_stats_v2* scap_kmod_get_stats_v2(struct scap_engine_handle engine, uint32_t flags, OUT uint32_t* nstats, OUT int32_t* rc) +const struct metrics_v2* scap_kmod_get_stats_v2(struct scap_engine_handle engine, uint32_t flags, OUT uint32_t* nstats, OUT int32_t* rc) { struct kmod_engine *handle = engine.m_handle; struct scap_device_set *devset = &handle->m_dev_set; uint32_t j; *nstats = 0; - scap_stats_v2* stats = handle->m_stats; + metrics_v2* stats = handle->m_stats; if (!stats) { @@ -592,15 +592,17 @@ const struct scap_stats_v2* scap_kmod_get_stats_v2(struct scap_engine_handle eng return NULL; } - if ((flags & PPM_SCAP_STATS_KERNEL_COUNTERS)) + if ((flags & METRICS_V2_KERNEL_COUNTERS)) { /* KERNEL SIDE STATS COUNTERS */ for(uint32_t stat = 0; stat < KMOD_MAX_KERNEL_COUNTERS_STATS; stat++) { - stats[stat].type = STATS_VALUE_TYPE_U64; - stats[stat].flags = PPM_SCAP_STATS_KERNEL_COUNTERS; + stats[stat].type = METRIC_VALUE_TYPE_U64; + stats[stat].flags = METRICS_V2_KERNEL_COUNTERS; + stats[stat].unit = METRIC_VALUE_UNIT_COUNT; + stats[stat].metric_type = METRIC_VALUE_MONOTONIC; stats[stat].value.u64 = 0; - strlcpy(stats[stat].name, kmod_kernel_counters_stats_names[stat], STATS_NAME_MAX); + strlcpy(stats[stat].name, kmod_kernel_counters_stats_names[stat], METRIC_NAME_MAX); } for(j = 0; j < devset->m_ndevs; j++) diff --git a/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c b/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c index d6c6fdb86b..50826401e5 100644 --- a/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c +++ b/userspace/libscap/engine/modern_bpf/scap_modern_bpf.c @@ -259,15 +259,15 @@ int32_t scap_modern_bpf__get_stats(struct scap_engine_handle engine, OUT scap_st return SCAP_SUCCESS; } -const struct scap_stats_v2* scap_modern_bpf__get_stats_v2(struct scap_engine_handle engine, uint32_t flags, OUT uint32_t* nstats, OUT int32_t* rc) +const struct metrics_v2* scap_modern_bpf__get_stats_v2(struct scap_engine_handle engine, uint32_t flags, OUT uint32_t* nstats, OUT int32_t* rc) { struct modern_bpf_engine* handle = engine.m_handle; if (!(handle->m_flags & ENGINE_FLAG_BPF_STATS_ENABLED)) { // we can't collect libbpf stats if bpf stats are not enabled - flags &= ~PPM_SCAP_STATS_LIBBPF_STATS; + flags &= ~METRICS_V2_LIBBPF_STATS; } - return pman_get_scap_stats_v2(flags, nstats, rc); + return pman_get_metrics_v2(flags, nstats, rc); } int32_t scap_modern_bpf__get_n_tracepoint_hit(struct scap_engine_handle engine, OUT long* ret) diff --git a/userspace/libscap/engine/noop/noop.c b/userspace/libscap/engine/noop/noop.c index a9daca1968..eeb20a2d53 100644 --- a/userspace/libscap/engine/noop/noop.c +++ b/userspace/libscap/engine/noop/noop.c @@ -87,7 +87,7 @@ int32_t noop_get_stats(struct scap_engine_handle engine, scap_stats* stats) return SCAP_SUCCESS; } -const struct scap_stats_v2* noop_get_stats_v2(struct scap_engine_handle engine, uint32_t flags, uint32_t* nstats, int32_t* rc) +const struct metrics_v2* noop_get_stats_v2(struct scap_engine_handle engine, uint32_t flags, uint32_t* nstats, int32_t* rc) { *rc = SCAP_SUCCESS; *nstats = 0; diff --git a/userspace/libscap/engine/noop/noop.h b/userspace/libscap/engine/noop/noop.h index c0ea97b08b..191009a02d 100644 --- a/userspace/libscap/engine/noop/noop.h +++ b/userspace/libscap/engine/noop/noop.h @@ -24,7 +24,7 @@ limitations under the License. typedef struct scap scap_t; typedef struct ppm_evt_hdr scap_evt; typedef struct scap_stats scap_stats; -typedef struct scap_stats_v2 scap_stats_v2; +typedef struct metrics_v2 metrics_v2; struct noop_engine* noop_alloc_handle(scap_t* main_handle, char* lasterr_ptr); void noop_free_handle(struct scap_engine_handle engine); @@ -35,7 +35,7 @@ int32_t noop_stop_capture(struct scap_engine_handle engine); int32_t unimplemented_op(char* err, size_t err_size); int32_t noop_configure(struct scap_engine_handle engine, enum scap_setting setting, unsigned long arg1, unsigned long arg2); int32_t noop_get_stats(struct scap_engine_handle engine, scap_stats* stats); -const struct scap_stats_v2* noop_get_stats_v2(struct scap_engine_handle engine, uint32_t flags, uint32_t* nstats, int32_t* rc); +const struct metrics_v2* noop_get_stats_v2(struct scap_engine_handle engine, uint32_t flags, uint32_t* nstats, int32_t* rc); int32_t noop_get_n_tracepoint_hit(struct scap_engine_handle engine, long* ret); uint32_t noop_get_n_devs(struct scap_engine_handle engine); uint64_t noop_get_max_buf_used(struct scap_engine_handle engine); diff --git a/userspace/libscap/engine/source_plugin/source_plugin.c b/userspace/libscap/engine/source_plugin/source_plugin.c index 70116a5275..5853371ef4 100644 --- a/userspace/libscap/engine/source_plugin/source_plugin.c +++ b/userspace/libscap/engine/source_plugin/source_plugin.c @@ -274,11 +274,11 @@ static int32_t get_stats(struct scap_engine_handle engine, OUT scap_stats* stats return SCAP_SUCCESS; } -const struct scap_stats_v2* get_source_plugin_stats_v2(struct scap_engine_handle engine, uint32_t flags, OUT uint32_t* nstats, OUT int32_t* rc) +const struct metrics_v2* get_source_plugin_stats_v2(struct scap_engine_handle engine, uint32_t flags, OUT uint32_t* nstats, OUT int32_t* rc) { struct source_plugin_engine *handle = engine.m_handle; *nstats = MAX_SOURCE_PLUGIN_COUNTERS_STATS; - scap_stats_v2* stats = handle->m_stats; + metrics_v2* stats = handle->m_stats; if (!stats) { *nstats = 0; @@ -289,9 +289,11 @@ const struct scap_stats_v2* get_source_plugin_stats_v2(struct scap_engine_handle /* SOURCE PLUGIN STATS COUNTERS */ for(uint32_t stat = 0; stat < MAX_SOURCE_PLUGIN_COUNTERS_STATS; stat++) { - stats[stat].type = STATS_VALUE_TYPE_U64; + stats[stat].type = METRIC_VALUE_TYPE_U64; stats[stat].value.u64 = 0; - strlcpy(stats[stat].name, source_plugin_counters_stats_names[stat], STATS_NAME_MAX); + stats[stat].unit = METRIC_VALUE_UNIT_COUNT; + stats[stat].metric_type = METRIC_VALUE_MONOTONIC; + strlcpy(stats[stat].name, source_plugin_counters_stats_names[stat], METRIC_NAME_MAX); } stats[N_EVTS].value.u64 = handle->m_nevts; diff --git a/userspace/libscap/engine/source_plugin/source_plugin.h b/userspace/libscap/engine/source_plugin/source_plugin.h index fd6eb13f3d..8b871e08df 100644 --- a/userspace/libscap/engine/source_plugin/source_plugin.h +++ b/userspace/libscap/engine/source_plugin/source_plugin.h @@ -20,7 +20,7 @@ limitations under the License. #include #include #include -#include +#include struct scap; @@ -49,6 +49,6 @@ struct source_plugin_engine ss_plugin_rc m_input_plugin_last_batch_res; // Stats v2. - scap_stats_v2 m_stats[MAX_SOURCE_PLUGIN_COUNTERS_STATS]; + metrics_v2 m_stats[MAX_SOURCE_PLUGIN_COUNTERS_STATS]; }; diff --git a/userspace/libscap/examples/01-open/scap_open.c b/userspace/libscap/examples/01-open/scap_open.c index 235a3b3ffd..e68bc58202 100644 --- a/userspace/libscap/examples/01-open/scap_open.c +++ b/userspace/libscap/examples/01-open/scap_open.c @@ -824,10 +824,10 @@ void print_stats() { gettimeofday(&tval_end, NULL); timersub(&tval_end, &tval_start, &tval_result); - uint32_t flags = PPM_SCAP_STATS_KERNEL_COUNTERS | PPM_SCAP_STATS_LIBBPF_STATS; + uint32_t flags = METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS; uint32_t nstats; int32_t rc; - const scap_stats_v2* stats_v2; + const metrics_v2* stats_v2; stats_v2 = scap_get_stats_v2(g_h, flags, &nstats, &rc); uint64_t engine_flags = scap_get_engine_flags(g_h); uint64_t n_evts = 0; @@ -835,7 +835,7 @@ void print_stats() { for(int stat = 0; stat < nstats; stat++) { - if ((strncmp(stats_v2[stat].name, "n_evts", 6) == 0) && stats_v2[0].type == STATS_VALUE_TYPE_U64) + if ((strncmp(stats_v2[stat].name, "n_evts", 6) == 0) && stats_v2[0].type == METRIC_VALUE_TYPE_U64) { n_evts = stats_v2[stat].value.u64; break; @@ -876,7 +876,7 @@ void print_stats() { for(int stat = 0; stat < nstats; stat++) { - if (stats_v2[stat].type == STATS_VALUE_TYPE_U64) + if (stats_v2[stat].type == METRIC_VALUE_TYPE_U64) { printf("[%u] %s: %lu\n", stats_v2[stat].flags, stats_v2[stat].name, stats_v2[stat].value.u64); } diff --git a/userspace/libscap/metrics_v2.h b/userspace/libscap/metrics_v2.h new file mode 100644 index 0000000000..95e4c83a6f --- /dev/null +++ b/userspace/libscap/metrics_v2.h @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: Apache-2.0 +/* +Copyright (C) 2024 The Falco Authors. + +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. + +*/ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +// +// Limits for metrics_v2 metric name +// +#define METRIC_NAME_MAX 512 + +// +// metrics_v2 flags +// +#define METRICS_V2_KERNEL_COUNTERS (1 << 0) +#define METRICS_V2_LIBBPF_STATS (1 << 1) +#define METRICS_V2_RESOURCE_UTILIZATION (1 << 2) +#define METRICS_V2_STATE_COUNTERS (1 << 3) + +typedef union metrics_v2_value { + uint32_t u32; + int32_t s32; + uint64_t u64; + int64_t s64; + double d; + float f; + int i; +}metrics_v2_value; + +typedef enum metrics_v2_value_type{ + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_TYPE_S32, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_TYPE_S64, + METRIC_VALUE_TYPE_D, + METRIC_VALUE_TYPE_F, + METRIC_VALUE_TYPE_I, +}metrics_v2_value_type; + +typedef enum metrics_v2_value_unit{ + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_UNIT_PERC, + METRIC_VALUE_UNIT_MEMORY_BYTES, + METRIC_VALUE_UNIT_MEMORY_KILOBYTES, + METRIC_VALUE_UNIT_TIME_NS, +}metrics_v2_value_unit; + +typedef enum metrics_v2_metric_type{ + METRIC_VALUE_MONOTONIC, + METRIC_VALUE_NON_MONOTONIC_CURRENT, +}metrics_v2_metric_type; + +/*! + \brief Metrics schema, used for libscap and libsinsp metrics about an in progress capture. +*/ +typedef struct metrics_v2 +{ + /* Metric metadata */ + char name[METRIC_NAME_MAX]; + uint32_t flags; + metrics_v2_metric_type metric_type; + /* Metric value */ + metrics_v2_value value; + metrics_v2_value_type type; + metrics_v2_value_unit unit; +}metrics_v2; + +#ifdef __cplusplus +} +#endif diff --git a/userspace/libscap/scap.c b/userspace/libscap/scap.c index 55babfd559..535eb7d27d 100644 --- a/userspace/libscap/scap.c +++ b/userspace/libscap/scap.c @@ -278,7 +278,7 @@ int32_t scap_get_stats(scap_t* handle, OUT scap_stats* stats) // // Return engine statistics (including counters and `bpftool prog show` like stats) // -const struct scap_stats_v2* scap_get_stats_v2(scap_t* handle, uint32_t flags, OUT uint32_t* nstats, OUT int32_t* rc) +const struct metrics_v2* scap_get_stats_v2(scap_t* handle, uint32_t flags, OUT uint32_t* nstats, OUT int32_t* rc) { if(handle->m_vtable) { diff --git a/userspace/libscap/scap.h b/userspace/libscap/scap.h index 2405f01ad1..ea513f4140 100644 --- a/userspace/libscap/scap.h +++ b/userspace/libscap/scap.h @@ -20,7 +20,7 @@ limitations under the License. #include #include -#include +#include #ifdef __cplusplus extern "C" { @@ -653,9 +653,9 @@ int32_t scap_get_stats(scap_t* handle, OUT scap_stats* stats); \param nstats Pointer reflecting number of statistics in returned buffer. \param rc Pointer to return code. - \return Pointer to a \ref scap_stats_v2 structure filled with the statistics. + \return Pointer to a \ref metrics_v2 structure filled with the statistics. */ -const struct scap_stats_v2* scap_get_stats_v2(scap_t* handle, uint32_t flags, OUT uint32_t* nstats, OUT int32_t* rc); +const struct metrics_v2* scap_get_stats_v2(scap_t* handle, uint32_t flags, OUT uint32_t* nstats, OUT int32_t* rc); /*! \brief Returns the set of ppm_sc whose events have EF_MODIFIES_STATE flag or whose syscall have UF_NEVER_DROP flag. diff --git a/userspace/libscap/scap_stats_v2.h b/userspace/libscap/scap_stats_v2.h deleted file mode 100644 index 4bf6c6c94e..0000000000 --- a/userspace/libscap/scap_stats_v2.h +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -/* -Copyright (C) 2023 The Falco Authors. - -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. - -*/ - -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - - -// -// Limits for scap_stats_v2 metric name -// -#define STATS_NAME_MAX 512 - -// -// scap_stats_v2 flags -// -#define PPM_SCAP_STATS_KERNEL_COUNTERS (1 << 0) -#define PPM_SCAP_STATS_LIBBPF_STATS (1 << 1) -#define PPM_SCAP_STATS_RESOURCE_UTILIZATION (1 << 2) -#define PPM_SCAP_STATS_STATE_COUNTERS (1 << 3) - -typedef union scap_stats_v2_value { - uint32_t u32; - int32_t s32; - uint64_t u64; - int64_t s64; - double d; - float f; - int i; -}scap_stats_v2_value; - -typedef enum scap_stats_v2_value_type{ - STATS_VALUE_TYPE_U32, - STATS_VALUE_TYPE_S32, - STATS_VALUE_TYPE_U64, - STATS_VALUE_TYPE_S64, - STATS_VALUE_TYPE_D, - STATS_VALUE_TYPE_F, - STATS_VALUE_TYPE_I, -}scap_stats_v2_value_type; - -typedef enum scap_stats_v2_value_unit{ - STATS_VALUE_UNIT_COUNT, - STATS_VALUE_UNIT_PERC, - STATS_VALUE_UNIT_MEMORY_BYTES, - STATS_VALUE_UNIT_MEMORY_KILOBYTES, -}scap_stats_v2_value_unit; - -typedef enum scap_stats_v2_metric_type{ - STATS_VALUE_MONOTONIC, - STATS_VALUE_NON_MONOTONIC_CURRENT, -}scap_stats_v2_metric_type; - -/*! - \brief Statistics about an in progress capture (including counters and libbpf stats, compare to `bpftool prog show` CLI). -*/ -typedef struct scap_stats_v2 -{ - /* Metadata */ - char name[STATS_NAME_MAX]; - uint32_t flags; - scap_stats_v2_metric_type metric_type; - /* Stats values */ - scap_stats_v2_value value; - scap_stats_v2_value_type type; - scap_stats_v2_value_unit unit; -}scap_stats_v2; - -#ifdef __cplusplus -} -#endif diff --git a/userspace/libscap/scap_vtable.h b/userspace/libscap/scap_vtable.h index 9d4b0fdd2f..07cfd8cf41 100644 --- a/userspace/libscap/scap_vtable.h +++ b/userspace/libscap/scap_vtable.h @@ -29,7 +29,7 @@ extern "C" { struct scap_stats; typedef struct scap scap_t; -struct scap_stats_v2; +struct metrics_v2; typedef struct ppm_evt_hdr scap_evt; struct scap_proclist; @@ -218,9 +218,9 @@ struct scap_vtable { * @param flags holding statistics category flags * @param nstats Pointer reflecting number of statistics in returned buffer * @param rc Pointer to return code - * @return Pointer to a \ref scap_stats_v2 structure filled with the statistics + * @return Pointer to a \ref metrics_v2 structure filled with the statistics */ - const struct scap_stats_v2* (*get_stats_v2)(struct scap_engine_handle engine, uint32_t flags, uint32_t* nstats, int32_t* rc); + const struct metrics_v2* (*get_stats_v2)(struct scap_engine_handle engine, uint32_t flags, uint32_t* nstats, int32_t* rc); /** * @brief get the number of tracepoint hits diff --git a/userspace/libsinsp/capture_stats_source.h b/userspace/libsinsp/capture_stats_source.h index d681649dea..38000a995b 100644 --- a/userspace/libsinsp/capture_stats_source.h +++ b/userspace/libsinsp/capture_stats_source.h @@ -60,7 +60,7 @@ class SINSP_PUBLIC capture_stats_source /** * Get engine statistics (including counters and `bpftool prog show` like stats). * - * @return Pointer to a \ref scap_stats_v2 structure filled with the statistics. + * @return Pointer to a \ref metrics_v2 structure filled with the libscap stats. */ - virtual const struct scap_stats_v2* get_capture_stats_v2(uint32_t flags, uint32_t* nstats, int32_t* rc) const = 0; + virtual const struct metrics_v2* get_capture_stats_v2(uint32_t flags, uint32_t* nstats, int32_t* rc) const = 0; }; diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index 1b0045662a..bcc83754f0 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -295,7 +295,7 @@ uint64_t metrics_collector::get_container_memory_usage() const metrics_collector::metrics_collector(sinsp* inspector, const uint32_t flags) : m_inspector(inspector), - m_metrics_flags((PPM_SCAP_STATS_KERNEL_COUNTERS | PPM_SCAP_STATS_LIBBPF_STATS | PPM_SCAP_STATS_RESOURCE_UTILIZATION | PPM_SCAP_STATS_STATE_COUNTERS)) + m_metrics_flags((METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS)) { m_metrics_flags = flags; } @@ -316,17 +316,17 @@ void metrics_collector::snapshot() * libscap metrics */ - if((m_metrics_flags & PPM_SCAP_STATS_KERNEL_COUNTERS) || (m_metrics_flags & PPM_SCAP_STATS_LIBBPF_STATS)) + if((m_metrics_flags & METRICS_V2_KERNEL_COUNTERS) || (m_metrics_flags & METRICS_V2_LIBBPF_STATS)) { uint32_t nstats = 0; int32_t rc = 0; // libscap metrics: m_metrics_flags are pushed down from consumers' input, // libbpf stats only collected when ENGINE_FLAG_BPF_STATS_ENABLED aka `kernel.bpf_stats_enabled = 1` - const scap_stats_v2* scap_stats_v2_snapshot = m_inspector->get_capture_stats_v2(m_metrics_flags, &nstats, &rc); - if (scap_stats_v2_snapshot && nstats > 0 && rc == 0) + const metrics_v2* metrics_v2_snapshot = m_inspector->get_capture_stats_v2(m_metrics_flags, &nstats, &rc); + if (metrics_v2_snapshot && nstats > 0 && rc == 0) { // Move into m_metrics via std::move - m_metrics = std::vector(scap_stats_v2_snapshot, scap_stats_v2_snapshot + nstats); + m_metrics = std::vector(metrics_v2_snapshot, metrics_v2_snapshot + nstats); } } @@ -334,7 +334,7 @@ void metrics_collector::snapshot() * libsinsp metrics */ - if((m_metrics_flags & PPM_SCAP_STATS_RESOURCE_UTILIZATION)) + if((m_metrics_flags & METRICS_V2_RESOURCE_UTILIZATION)) { const scap_agent_info* agent_info = m_inspector->get_agent_info(); uint32_t rss = 0; @@ -348,28 +348,28 @@ void metrics_collector::snapshot() get_cpu_usage_and_total_procs(agent_info->start_time, cpu_usage_perc, cpu_usage_perc_total_host, procs_running_host); get_rss_vsz_pss_total_memory_and_open_fds(rss, vsz, pss, memory_used_host, open_fds_host); // Resource utilization of the agent itself - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC], \ - PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_D, STATS_VALUE_UNIT_PERC, STATS_VALUE_NON_MONOTONIC_CURRENT, cpu_usage_perc)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_RSS], \ - PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_MEMORY_KILOBYTES, STATS_VALUE_NON_MONOTONIC_CURRENT, rss)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ], \ - PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_MEMORY_KILOBYTES, STATS_VALUE_NON_MONOTONIC_CURRENT, vsz)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_PSS], \ - PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_MEMORY_KILOBYTES, STATS_VALUE_NON_MONOTONIC_CURRENT, pss)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY], \ - PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_MEMORY_BYTES, STATS_VALUE_NON_MONOTONIC_CURRENT, get_container_memory_usage())); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC], \ + METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_D, METRIC_VALUE_UNIT_PERC, METRIC_VALUE_NON_MONOTONIC_CURRENT, cpu_usage_perc)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_RSS], \ + METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_MEMORY_KILOBYTES, METRIC_VALUE_NON_MONOTONIC_CURRENT, rss)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ], \ + METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_MEMORY_KILOBYTES, METRIC_VALUE_NON_MONOTONIC_CURRENT, vsz)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_PSS], \ + METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_MEMORY_KILOBYTES, METRIC_VALUE_NON_MONOTONIC_CURRENT, pss)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY], \ + METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_MEMORY_BYTES, METRIC_VALUE_NON_MONOTONIC_CURRENT, get_container_memory_usage())); // Resource utilization / load indicators of the underlying host - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST], \ - PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_D, STATS_VALUE_UNIT_PERC, STATS_VALUE_NON_MONOTONIC_CURRENT, cpu_usage_perc_total_host)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_PROCS_HOST], \ - PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_COUNT, STATS_VALUE_NON_MONOTONIC_CURRENT, procs_running_host)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST], \ - PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_MEMORY_KILOBYTES, STATS_VALUE_NON_MONOTONIC_CURRENT, memory_used_host)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST], \ - PPM_SCAP_STATS_RESOURCE_UTILIZATION, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_NON_MONOTONIC_CURRENT, open_fds_host)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST], \ + METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_D, METRIC_VALUE_UNIT_PERC, METRIC_VALUE_NON_MONOTONIC_CURRENT, cpu_usage_perc_total_host)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_PROCS_HOST], \ + METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, procs_running_host)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST], \ + METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_MEMORY_KILOBYTES, METRIC_VALUE_NON_MONOTONIC_CURRENT, memory_used_host)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST], \ + METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, open_fds_host)); } - if((m_metrics_flags & PPM_SCAP_STATS_STATE_COUNTERS)) + if((m_metrics_flags & METRICS_V2_STATE_COUNTERS)) { std::shared_ptr sinsp_stats_v2 = m_inspector->get_sinsp_stats_v2(); @@ -400,49 +400,49 @@ void metrics_collector::snapshot() } } - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_THREADS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_NON_MONOTONIC_CURRENT, n_threads)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_FDS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_NON_MONOTONIC_CURRENT, n_fds)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_FD_LOOKUPS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_noncached_fd_lookups)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_FD_LOOKUPS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_cached_fd_lookups)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_FD_LOOKUPS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_failed_fd_lookups)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_FDS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_added_fds)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_FDS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_removed_fds)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORED_EVTS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_stored_evts)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORE_EVTS_DROPS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_store_evts_drops)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVED_EVTS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_retrieved_evts)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVE_EVTS_DROPS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_retrieve_evts_drops)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_THREAD_LOOKUPS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_noncached_thread_lookups)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_THREAD_LOOKUPS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_cached_thread_lookups)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_THREAD_LOOKUPS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_failed_thread_lookups)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_THREADS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_added_threads)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_THREADS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U64, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_removed_threads)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_DROPS_FULL_THREADTABLE], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_COUNT, STATS_VALUE_MONOTONIC, sinsp_stats_v2->m_n_drops_full_threadtable)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_MISSING_CONTAINER_IMAGES], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_COUNT, STATS_VALUE_NON_MONOTONIC_CURRENT, sinsp_stats_v2->m_n_missing_container_images)); - m_metrics.push_back(new_stat(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_CONTAINERS], \ - PPM_SCAP_STATS_STATE_COUNTERS, STATS_VALUE_TYPE_U32, STATS_VALUE_UNIT_COUNT, STATS_VALUE_NON_MONOTONIC_CURRENT, sinsp_stats_v2->m_n_containers)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_THREADS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, n_threads)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_FDS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, n_fds)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_FD_LOOKUPS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_noncached_fd_lookups)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_FD_LOOKUPS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_cached_fd_lookups)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_FD_LOOKUPS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_failed_fd_lookups)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_FDS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_added_fds)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_FDS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_removed_fds)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORED_EVTS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_stored_evts)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORE_EVTS_DROPS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_store_evts_drops)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVED_EVTS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_retrieved_evts)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVE_EVTS_DROPS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_retrieve_evts_drops)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_THREAD_LOOKUPS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_noncached_thread_lookups)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_THREAD_LOOKUPS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_cached_thread_lookups)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_THREAD_LOOKUPS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_failed_thread_lookups)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_THREADS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_added_threads)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_THREADS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_removed_threads)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_DROPS_FULL_THREADTABLE], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_drops_full_threadtable)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_MISSING_CONTAINER_IMAGES], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, sinsp_stats_v2->m_n_missing_container_images)); + m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_CONTAINERS], \ + METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, sinsp_stats_v2->m_n_containers)); } } } -const std::vector& metrics_collector::get_metrics() const +const std::vector& metrics_collector::get_metrics() const { return m_metrics; } diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index 730e10762c..b7e1593921 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -17,7 +17,7 @@ limitations under the License. */ #pragma once -#include +#include #include #include @@ -91,64 +91,64 @@ class metrics_collector void snapshot(); // Method to get a const reference to m_metrics buffer - const std::vector& get_metrics() const; + const std::vector& get_metrics() const; private: metrics_collector(sinsp* inspector, const uint32_t flags); static std::unique_ptr mc_instance; sinsp* m_inspector; uint32_t m_metrics_flags; - std::vector m_metrics; + std::vector m_metrics; void 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); void get_cpu_usage_and_total_procs(double start_time, double &cpu_usage_perc, double &cpu_usage_perc_total_host, uint32_t &procs_running_host); uint64_t get_container_memory_usage() const; template - const scap_stats_v2 new_stat(const char* name, uint32_t flags, scap_stats_v2_value_type type, scap_stats_v2_value_unit unit, scap_stats_v2_metric_type metric_type, T val) + const metrics_v2 new_metric(const char* name, uint32_t flags, metrics_v2_value_type type, metrics_v2_value_unit unit, metrics_v2_metric_type metric_type, T val) { - scap_stats_v2 stat; - strlcpy(stat.name, name, STATS_NAME_MAX); - stat.flags = flags; - stat.type = type; - stat.unit = unit; - stat.metric_type = metric_type; - set_stat_value(stat, type, val); - return stat; + metrics_v2 metric; + strlcpy(metric.name, name, METRIC_NAME_MAX); + metric.flags = flags; + metric.type = type; + metric.unit = unit; + metric.metric_type = metric_type; + set_new_metric(metric, type, val); + return metric; } template - void set_stat_value(scap_stats_v2& stat, scap_stats_v2_value_type type, T val) + void set_new_metric(metrics_v2& metric, metrics_v2_value_type type, T val) { switch (type) { - case STATS_VALUE_TYPE_U32: - stat.type = STATS_VALUE_TYPE_U32; - stat.value.u32 = static_cast(val); + case METRIC_VALUE_TYPE_U32: + metric.type = METRIC_VALUE_TYPE_U32; + metric.value.u32 = static_cast(val); break; - case STATS_VALUE_TYPE_S32: - stat.type = STATS_VALUE_TYPE_S32; - stat.value.s32 = static_cast(val); + case METRIC_VALUE_TYPE_S32: + metric.type = METRIC_VALUE_TYPE_S32; + metric.value.s32 = static_cast(val); break; - case STATS_VALUE_TYPE_U64: - stat.type = STATS_VALUE_TYPE_U64; - stat.value.u64 = static_cast(val); + case METRIC_VALUE_TYPE_U64: + metric.type = METRIC_VALUE_TYPE_U64; + metric.value.u64 = static_cast(val); break; - case STATS_VALUE_TYPE_S64: - stat.type = STATS_VALUE_TYPE_S64; - stat.value.s64 = static_cast(val); + case METRIC_VALUE_TYPE_S64: + metric.type = METRIC_VALUE_TYPE_S64; + metric.value.s64 = static_cast(val); break; - case STATS_VALUE_TYPE_D: - stat.type = STATS_VALUE_TYPE_D; - stat.value.d = static_cast(val); + case METRIC_VALUE_TYPE_D: + metric.type = METRIC_VALUE_TYPE_D; + metric.value.d = static_cast(val); break; - case STATS_VALUE_TYPE_F: - stat.type = STATS_VALUE_TYPE_F; - stat.value.f = static_cast(val); + case METRIC_VALUE_TYPE_F: + metric.type = METRIC_VALUE_TYPE_F; + metric.value.f = static_cast(val); break; - case STATS_VALUE_TYPE_I: - stat.type = STATS_VALUE_TYPE_I; - stat.value.i = static_cast(val); + case METRIC_VALUE_TYPE_I: + metric.type = METRIC_VALUE_TYPE_I; + metric.value.i = static_cast(val); break; default: break; diff --git a/userspace/libsinsp/sinsp.cpp b/userspace/libsinsp/sinsp.cpp index 8a778ea9ca..a6eb0c6502 100644 --- a/userspace/libsinsp/sinsp.cpp +++ b/userspace/libsinsp/sinsp.cpp @@ -1807,10 +1807,10 @@ void sinsp::print_capture_stats(sinsp_logger::severity sev) const stats.n_drops_bug); } -const scap_stats_v2* sinsp::get_capture_stats_v2(uint32_t flags, uint32_t* nstats, int32_t* rc) const +const metrics_v2* sinsp::get_capture_stats_v2(uint32_t flags, uint32_t* nstats, int32_t* rc) const { /* On purpose ignoring failures to not interrupt in case of stats retrieval failure. */ - const scap_stats_v2* stats_v2 = scap_get_stats_v2(m_h, flags, nstats, rc); + const metrics_v2* stats_v2 = scap_get_stats_v2(m_h, flags, nstats, rc); if (!stats_v2) { *nstats = 0; diff --git a/userspace/libsinsp/sinsp.h b/userspace/libsinsp/sinsp.h index 13c2c6972b..47022f3153 100644 --- a/userspace/libsinsp/sinsp.h +++ b/userspace/libsinsp/sinsp.h @@ -495,7 +495,7 @@ class SINSP_PUBLIC sinsp : public capture_stats_source \brief Fill the given structure with statistics about the currently open capture. - \note sinsp stats may be refactored near-term, see also scap_stats_v2. + \note sinsp stats may be refactored near-term, see also metrics_v2. */ void get_capture_stats(scap_stats* stats) const override; @@ -510,9 +510,9 @@ class SINSP_PUBLIC sinsp : public capture_stats_source \note sinsp stats may be refactored near-term. - \return Pointer to a \ref scap_stats_v2 structure filled with the statistics. + \return Pointer to a \ref metrics_v2 structure filled with the statistics. */ - const struct scap_stats_v2* get_capture_stats_v2(uint32_t flags, uint32_t* nstats, int32_t* rc) const override; + const struct metrics_v2* get_capture_stats_v2(uint32_t flags, uint32_t* nstats, int32_t* rc) const override; libsinsp::event_processor* m_external_event_processor; @@ -1140,7 +1140,7 @@ class SINSP_PUBLIC sinsp : public capture_stats_source const scap_machine_info* m_machine_info; const scap_agent_info* m_agent_info; std::shared_ptr m_sinsp_stats_v2; - scap_stats_v2 m_sinsp_stats_v2_buffer[SINSP_MAX_STATS_V2]; + metrics_v2 m_sinsp_stats_v2_buffer[SINSP_MAX_STATS_V2]; uint32_t m_num_cpus; bool m_flush_memory_dump; bool m_large_envs_enabled; diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index ff66e67fc1..52db87270a 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -31,7 +31,7 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) ASSERT_EQ(get_field_as_string(evt, "proc.nthreads"), "3"); /* Snapshot current metrics and get the updated metrics_snapshot buffer */ - uint32_t test_metrics_flags = (PPM_SCAP_STATS_KERNEL_COUNTERS | PPM_SCAP_STATS_LIBBPF_STATS | PPM_SCAP_STATS_RESOURCE_UTILIZATION | PPM_SCAP_STATS_STATE_COUNTERS); + uint32_t test_metrics_flags = (METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); std::unique_ptr metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); metrics_collector->snapshot(); auto metrics_snapshot = metrics_collector->get_metrics(); @@ -78,35 +78,35 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) /* Just checking that we don't crash w/ selective flags */ test_metrics_flags = 0; - test_metrics_flags |= PPM_SCAP_STATS_KERNEL_COUNTERS; // 20, but can't test it here it's 0 - test_metrics_flags |= PPM_SCAP_STATS_LIBBPF_STATS; // 21 (x86_64 machine), but can't test it here it's 0 + test_metrics_flags |= METRICS_V2_KERNEL_COUNTERS; // 20, but can't test it here it's 0 + test_metrics_flags |= METRICS_V2_LIBBPF_STATS; // 21 (x86_64 machine), but can't test it here it's 0 metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 0); test_metrics_flags = 0; - test_metrics_flags |= PPM_SCAP_STATS_RESOURCE_UTILIZATION; + test_metrics_flags |= METRICS_V2_RESOURCE_UTILIZATION; metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 9); test_metrics_flags = 0; - test_metrics_flags |= PPM_SCAP_STATS_STATE_COUNTERS; + test_metrics_flags |= METRICS_V2_STATE_COUNTERS; metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 19); - test_metrics_flags = (PPM_SCAP_STATS_RESOURCE_UTILIZATION | PPM_SCAP_STATS_STATE_COUNTERS); + test_metrics_flags = (METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 28); /* Check we don't crash if inspector is invalid and verify metrics vector is cleared */ - test_metrics_flags = (PPM_SCAP_STATS_RESOURCE_UTILIZATION | PPM_SCAP_STATS_STATE_COUNTERS); + test_metrics_flags = (METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); metrics_collector = libsinsp::metrics::metrics_collector::create(nullptr, test_metrics_flags); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); From 3fc182827bd0be87c4db4df2cece91da5d69e537 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Sat, 27 Jan 2024 20:33:48 +0000 Subject: [PATCH 04/22] refactor(libsinsp): native memory conversion in metrics_v2 Signed-off-by: Melissa Kilby --- userspace/libscap/metrics_v2.h | 1 + userspace/libsinsp/metrics_collector.cpp | 47 +++++++----- userspace/libsinsp/metrics_collector.h | 58 +++++++++++--- userspace/libsinsp/sinsp.h | 1 - userspace/libsinsp/test/sinsp_metrics.ut.cpp | 81 +++++++++++++------- 5 files changed, 130 insertions(+), 58 deletions(-) diff --git a/userspace/libscap/metrics_v2.h b/userspace/libscap/metrics_v2.h index 95e4c83a6f..4e6320200a 100644 --- a/userspace/libscap/metrics_v2.h +++ b/userspace/libscap/metrics_v2.h @@ -63,6 +63,7 @@ typedef enum metrics_v2_value_unit{ METRIC_VALUE_UNIT_PERC, METRIC_VALUE_UNIT_MEMORY_BYTES, METRIC_VALUE_UNIT_MEMORY_KILOBYTES, + METRIC_VALUE_UNIT_MEMORY_MEGABYTES, METRIC_VALUE_UNIT_TIME_NS, }metrics_v2_value_unit; diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index bcc83754f0..9ba273a538 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -23,7 +23,6 @@ limitations under the License. #include #include #include -#include static const char *const sinsp_stats_v2_resource_utilization_names[] = { [SINSP_RESOURCE_UTILIZATION_CPU_PERC] = "cpu_usage_perc", @@ -293,11 +292,13 @@ uint64_t metrics_collector::get_container_memory_usage() const return memory_used; } -metrics_collector::metrics_collector(sinsp* inspector, const uint32_t flags) : +metrics_collector::metrics_collector(sinsp* inspector, const uint32_t& flags, const bool& convert_memory_to_mb) : m_inspector(inspector), - m_metrics_flags((METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS)) + m_metrics_flags((METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS)), + m_convert_memory_to_mb(true) { m_metrics_flags = flags; + m_convert_memory_to_mb = convert_memory_to_mb; } metrics_collector::~metrics_collector() @@ -337,34 +338,44 @@ void metrics_collector::snapshot() if((m_metrics_flags & METRICS_V2_RESOURCE_UTILIZATION)) { const scap_agent_info* agent_info = m_inspector->get_agent_info(); - uint32_t rss = 0; - uint32_t vsz = 0; - uint32_t pss = 0; - uint64_t memory_used_host = 0; - uint64_t open_fds_host = 0; - double cpu_usage_perc = 0.0; - double cpu_usage_perc_total_host = 0.0; - uint32_t procs_running_host = 0; + uint32_t rss{0}, vsz{0}, pss{0}, procs_running_host{0}; + uint64_t memory_used_host{0}, open_fds_host{0}; + double cpu_usage_perc{0.0}, cpu_usage_perc_total_host{0.0}; + uint64_t container_memory_usage = get_container_memory_usage(); + metrics_v2_value_unit rss_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, vsz_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, \ + pss_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, memory_used_host_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, container_memory_usage_unit{METRIC_VALUE_UNIT_MEMORY_BYTES}; + metrics_v2_value_type rss_type{METRIC_VALUE_TYPE_U32}, vsz_type{METRIC_VALUE_TYPE_U32}, \ + pss_type{METRIC_VALUE_TYPE_U32}, memory_used_host_type{METRIC_VALUE_TYPE_U32}, container_memory_usage_type{METRIC_VALUE_TYPE_U64}; get_cpu_usage_and_total_procs(agent_info->start_time, cpu_usage_perc, cpu_usage_perc_total_host, procs_running_host); get_rss_vsz_pss_total_memory_and_open_fds(rss, vsz, pss, memory_used_host, open_fds_host); + if(m_convert_memory_to_mb) + { + rss = convert_memory(rss_unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, rss); + vsz = convert_memory(vsz_unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, vsz); + pss = convert_memory(pss_unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, pss); + memory_used_host = convert_memory(memory_used_host_unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, memory_used_host); + container_memory_usage = convert_memory(container_memory_usage_unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, container_memory_usage); + rss_unit = vsz_unit = pss_unit = memory_used_host_unit = container_memory_usage_unit = METRIC_VALUE_UNIT_MEMORY_MEGABYTES; + rss_type = vsz_type = pss_type = memory_used_host_type = container_memory_usage_type = METRIC_VALUE_TYPE_D; + } // Resource utilization of the agent itself m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC], \ METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_D, METRIC_VALUE_UNIT_PERC, METRIC_VALUE_NON_MONOTONIC_CURRENT, cpu_usage_perc)); m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_RSS], \ - METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_MEMORY_KILOBYTES, METRIC_VALUE_NON_MONOTONIC_CURRENT, rss)); + METRICS_V2_RESOURCE_UTILIZATION, rss_type, rss_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, rss)); m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ], \ - METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_MEMORY_KILOBYTES, METRIC_VALUE_NON_MONOTONIC_CURRENT, vsz)); + METRICS_V2_RESOURCE_UTILIZATION, vsz_type, vsz_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, vsz)); m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_PSS], \ - METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_MEMORY_KILOBYTES, METRIC_VALUE_NON_MONOTONIC_CURRENT, pss)); + METRICS_V2_RESOURCE_UTILIZATION, pss_type, pss_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, pss)); m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY], \ - METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_MEMORY_BYTES, METRIC_VALUE_NON_MONOTONIC_CURRENT, get_container_memory_usage())); + METRICS_V2_RESOURCE_UTILIZATION, container_memory_usage_type, container_memory_usage_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, container_memory_usage)); // Resource utilization / load indicators of the underlying host m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST], \ METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_D, METRIC_VALUE_UNIT_PERC, METRIC_VALUE_NON_MONOTONIC_CURRENT, cpu_usage_perc_total_host)); m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_PROCS_HOST], \ METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, procs_running_host)); m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST], \ - METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_MEMORY_KILOBYTES, METRIC_VALUE_NON_MONOTONIC_CURRENT, memory_used_host)); + METRICS_V2_RESOURCE_UTILIZATION, memory_used_host_type, memory_used_host_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, memory_used_host)); m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST], \ METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, open_fds_host)); } @@ -451,11 +462,11 @@ const std::vector& metrics_collector::get_metrics() const std::unique_ptr metrics_collector::mc_instance = nullptr; // Factory method implementation -std::unique_ptr metrics_collector::create(sinsp* inspector, const uint32_t flags) +std::unique_ptr metrics_collector::create(sinsp* inspector, const uint32_t& flags, const bool& convert_memory_to_mb) { if (!mc_instance) { - mc_instance = std::unique_ptr(new metrics_collector(inspector, flags)); + mc_instance = std::unique_ptr(new metrics_collector(inspector, flags, convert_memory_to_mb)); } return std::move(mc_instance); diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index b7e1593921..cdabfca6a3 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -17,9 +17,11 @@ limitations under the License. */ #pragma once +#include #include #include #include +#include struct sinsp_stats_v2 { @@ -44,15 +46,15 @@ struct sinsp_stats_v2 enum sinsp_stats_v2_resource_utilization { - SINSP_RESOURCE_UTILIZATION_CPU_PERC = 0, ///< Current CPU usage, `ps` like, unit: percentage of one CPU. - SINSP_RESOURCE_UTILIZATION_MEMORY_RSS, ///< Current RSS (Resident Set Size), unit: kb. - SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ, ///< Current VSZ (Virtual Memory Size), unit: kb. - SINSP_RESOURCE_UTILIZATION_MEMORY_PSS, ///< Current PSS (Proportional Set Size), unit: kb. + SINSP_RESOURCE_UTILIZATION_CPU_PERC = 0, ///< Current CPU usage, `ps` util like calculation for the calling process (/proc/self), unit: percentage of one CPU. + SINSP_RESOURCE_UTILIZATION_MEMORY_RSS, ///< Current RSS (Resident Set Size), calculated based on /proc/self/status info, unit: kb. + SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ, ///< Current VSZ (Virtual Memory Size), calculated based on /proc/self/status info, unit: kb. + SINSP_RESOURCE_UTILIZATION_MEMORY_PSS, ///< Current PSS (Proportional Set Size), calculated based on /proc/self/smaps_rollup info, unit: kb. SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY, ///< Cgroup current memory used, default Kubernetes /sys/fs/cgroup/memory/memory.usage_in_bytes, unit: bytes. - SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST, ///< Current total host CPU usage (all CPUs), unit: percentage. - SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST, ///< Current total memory used out of available host memory, unit: kb. - SINSP_RESOURCE_UTILIZATION_PROCS_HOST, ///< Number of processes currently running on CPUs on the host, unit: count. - SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST, ///< Number of allocated fds on the host, unit: count. + SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST, ///< Current total host CPU usage (all CPUs), calculated based on ${HOST_ROOT}/proc/stat info, unit: percentage. + SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST, ///< Current total memory used out of available host memory, calculated based on ${HOST_ROOT}/proc/meminfo info, unit: kb. + SINSP_RESOURCE_UTILIZATION_PROCS_HOST, ///< Number of processes currently running on CPUs on the host, retrieved from ${HOST_ROOT}/proc/stat line `procs_running`, unit: count. + SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST, ///< Number of allocated fds on the host, retrieved from ${HOST_ROOT}/proc/sys/fs/file-nr, unit: count. SINSP_STATS_V2_N_THREADS, ///< Total number of threads currently stored in the sinsp state thread table, unit: count. SINSP_STATS_V2_N_FDS, ///< Total number of fds currently stored across all threadtables associated with each active thread in the sinsp state thread table, unit: count. SINSP_STATS_V2_NONCACHED_FD_LOOKUPS, ///< fdtable state related counters, unit: count. @@ -84,7 +86,7 @@ class metrics_collector { public: // Factory method for creating instances - static std::unique_ptr create(sinsp* inspector, const uint32_t flags); + static std::unique_ptr create(sinsp* inspector, const uint32_t& flags, const bool& convert_memory_to_mb); ~metrics_collector(); // Method to fill up m_metrics_buffer with current metrics; refreshes m_metrics with up-to-date metrics on each call @@ -93,11 +95,47 @@ class metrics_collector // Method to get a const reference to m_metrics buffer const std::vector& get_metrics() const; + // Method to convert memory units; however tied to metrics_v2 definitions + template + double convert_memory(metrics_v2_value_unit source_unit, metrics_v2_value_unit dest_unit, T val) + { + double factor = double(1); + switch(source_unit) + { + case METRIC_VALUE_UNIT_MEMORY_BYTES: + factor = double(1); + break; + case METRIC_VALUE_UNIT_MEMORY_KILOBYTES: + factor = (double)1024; + break; + case METRIC_VALUE_UNIT_MEMORY_MEGABYTES: + factor = (double)1024 * (double)1024; + break; + default: + return (double)0; + } + + double bytes_val = val * (double)factor; + switch(dest_unit) + { + case METRIC_VALUE_UNIT_MEMORY_BYTES: + return (double)bytes_val; + case METRIC_VALUE_UNIT_MEMORY_KILOBYTES: + return std::round((bytes_val / (double)1024) * (double)10) / (double)10; // round to 1 decimal + case METRIC_VALUE_UNIT_MEMORY_MEGABYTES: + return std::round((bytes_val / (double)1024 / (double)1024) * (double)10) / (double)10; // round to 1 decimal + default: + return (double)0; + } + return (double)0; + } + private: - metrics_collector(sinsp* inspector, const uint32_t flags); + metrics_collector(sinsp* inspector, const uint32_t& flags, const bool& convert_memory_to_mb); static std::unique_ptr mc_instance; sinsp* m_inspector; uint32_t m_metrics_flags; + bool m_convert_memory_to_mb; std::vector m_metrics; void 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); diff --git a/userspace/libsinsp/sinsp.h b/userspace/libsinsp/sinsp.h index 47022f3153..24364f61ac 100644 --- a/userspace/libsinsp/sinsp.h +++ b/userspace/libsinsp/sinsp.h @@ -1140,7 +1140,6 @@ class SINSP_PUBLIC sinsp : public capture_stats_source const scap_machine_info* m_machine_info; const scap_agent_info* m_agent_info; std::shared_ptr m_sinsp_stats_v2; - metrics_v2 m_sinsp_stats_v2_buffer[SINSP_MAX_STATS_V2]; uint32_t m_num_cpus; bool m_flush_memory_dump; bool m_large_envs_enabled; diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index 52db87270a..260e098f76 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -32,21 +32,26 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) /* Snapshot current metrics and get the updated metrics_snapshot buffer */ uint32_t test_metrics_flags = (METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); - std::unique_ptr metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); + bool convert_memory_to_mb = true; + std::unique_ptr metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags, convert_memory_to_mb); metrics_collector->snapshot(); auto metrics_snapshot = metrics_collector->get_metrics(); + /* Multiple calls */ + metrics_collector->snapshot(); + metrics_collector->snapshot(); + metrics_snapshot = metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 28); /* These names should always be available, note that we currently can't check for the merged scap stats metrics here */ - std::unordered_set minimal_stats_names = {"cpu_usage_perc", "memory_rss", "open_fds_host", \ + std::unordered_set minimal_metrics_names = {"cpu_usage_perc", "memory_rss", "open_fds_host", \ "n_threads", "n_fds", "n_added_fds", "n_added_threads", "n_removed_threads", "n_containers"}; - for(const auto& stat_name : minimal_stats_names) + for(const auto& metric_name : minimal_metrics_names) { uint32_t i = 0; - for (const auto& stat : metrics_snapshot) + for (const auto& metric: metrics_snapshot) { - if(stat_name.compare(stat.name) == 0) + if(metric_name.compare(metric.name) == 0) { break; } @@ -54,63 +59,81 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) } if(i == metrics_snapshot.size()) { - FAIL() << "unable to find stat '" << stat_name << "' in metrics_snapshot buffer"; + FAIL() << "unable to find stat '" << metric_name << "' in metrics_snapshot buffer"; } } - /* Assert some values are greater than 0 */ - ASSERT_GT(metrics_snapshot[SINSP_RESOURCE_UTILIZATION_MEMORY_RSS].value.u32, 0); - ASSERT_GT(metrics_snapshot[SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ].value.u32, 0); - ASSERT_GT(metrics_snapshot[SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST].value.d, 0); - ASSERT_GT(metrics_snapshot[SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST].value.u64, 0); - ASSERT_GT(metrics_snapshot[SINSP_RESOURCE_UTILIZATION_PROCS_HOST].value.u32, 0); - ASSERT_GT(metrics_snapshot[SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST].value.u64, 0); - - ASSERT_GT(metrics_snapshot[SINSP_STATS_V2_N_THREADS].value.u64, 0); - ASSERT_GT(metrics_snapshot[SINSP_STATS_V2_N_FDS].value.u64, 0); - ASSERT_GT(metrics_snapshot[SINSP_STATS_V2_ADDED_THREADS].value.u64, 0); + /* Assert successful memory unit changes and sanity check some values to be greater than 0 */ + const std::vector metrics_names_memory = {"memory_rss", "memory_vsz", "memory_pss", "container_memory_used", "memory_used_host"}; + const std::vector metrics_names_values_gt = {"n_threads", "n_fds", "n_added_threads", "memory_used_host"}; + uint32_t success_memory_cnt = 0; + uint32_t success_values_cnt = 0; + for (const auto& metric: metrics_snapshot) + { + if (std::find(metrics_names_memory.begin(), metrics_names_memory.end(), metric.name) != metrics_names_memory.end()) + { + ASSERT_EQ(metric.unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES); + ASSERT_EQ(metric.type, METRIC_VALUE_TYPE_D); + success_memory_cnt++; + } + if (std::find(metrics_names_values_gt.begin(), metrics_names_values_gt.end(), metric.name) != metrics_names_values_gt.end()) + { + ASSERT_GT(metric.value.u64, 0); + success_values_cnt++; + } + } + ASSERT_EQ(success_memory_cnt, metrics_names_memory.size()); + ASSERT_EQ(success_values_cnt, metrics_names_values_gt.size()); /* Empty call */ - metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, 0); + metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, 0, convert_memory_to_mb); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 0); - /* Just checking that we don't crash w/ selective flags */ + /* Sanity check empty inspector */ + test_metrics_flags = (METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); + metrics_collector = libsinsp::metrics::metrics_collector::create(nullptr, test_metrics_flags, convert_memory_to_mb); + metrics_collector->snapshot(); + metrics_snapshot = metrics_collector->get_metrics(); + ASSERT_EQ(metrics_snapshot.size(), 0); + + /* Some sanity checks for selective flags */ test_metrics_flags = 0; test_metrics_flags |= METRICS_V2_KERNEL_COUNTERS; // 20, but can't test it here it's 0 test_metrics_flags |= METRICS_V2_LIBBPF_STATS; // 21 (x86_64 machine), but can't test it here it's 0 - metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); + metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags, convert_memory_to_mb); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 0); test_metrics_flags = 0; test_metrics_flags |= METRICS_V2_RESOURCE_UTILIZATION; - metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); + metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags, convert_memory_to_mb); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 9); test_metrics_flags = 0; test_metrics_flags |= METRICS_V2_STATE_COUNTERS; - metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); + metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags, convert_memory_to_mb); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 19); test_metrics_flags = (METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); - metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags); + metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags, convert_memory_to_mb); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 28); - /* Check we don't crash if inspector is invalid and verify metrics vector is cleared */ - test_metrics_flags = (METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); - metrics_collector = libsinsp::metrics::metrics_collector::create(nullptr, test_metrics_flags); - metrics_collector->snapshot(); - metrics_snapshot = metrics_collector->get_metrics(); - ASSERT_EQ(metrics_snapshot.size(), 0); + /* Test public convert_memory method */ + double converted_memory = metrics_collector->convert_memory(METRIC_VALUE_UNIT_MEMORY_BYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, (uint64_t)52428800); + ASSERT_EQ(converted_memory, 50); + converted_memory = metrics_collector->convert_memory(METRIC_VALUE_UNIT_MEMORY_KILOBYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, (uint64_t)51200); + ASSERT_EQ(converted_memory, 50); + converted_memory = metrics_collector->convert_memory(METRIC_VALUE_UNIT_MEMORY_MEGABYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, (uint64_t)50); + ASSERT_EQ(converted_memory, 50); } #endif From 172d9587769d200a9baebb5fc7237bb2ce40e923 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Sun, 28 Jan 2024 23:47:47 +0000 Subject: [PATCH 05/22] cleanup(libsinsp): improve code clarity and adopt best practices Co-authored-by: Federico Aponte Signed-off-by: Melissa Kilby --- userspace/libsinsp/metrics_collector.cpp | 107 ++++++++----------- userspace/libsinsp/metrics_collector.h | 47 ++++---- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 35 +++--- 3 files changed, 87 insertions(+), 102 deletions(-) diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index 9ba273a538..72991d81bf 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -19,10 +19,10 @@ limitations under the License. #ifdef __linux__ #include +#include #include #include #include -#include static const char *const sinsp_stats_v2_resource_utilization_names[] = { [SINSP_RESOURCE_UTILIZATION_CPU_PERC] = "cpu_usage_perc", @@ -55,8 +55,7 @@ static const char *const sinsp_stats_v2_resource_utilization_names[] = { [SINSP_STATS_V2_N_CONTAINERS] = "n_containers", }; -namespace libsinsp { -namespace metrics { +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) { @@ -292,19 +291,6 @@ uint64_t metrics_collector::get_container_memory_usage() const return memory_used; } -metrics_collector::metrics_collector(sinsp* inspector, const uint32_t& flags, const bool& convert_memory_to_mb) : - m_inspector(inspector), - m_metrics_flags((METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS)), - m_convert_memory_to_mb(true) -{ - m_metrics_flags = flags; - m_convert_memory_to_mb = convert_memory_to_mb; -} - -metrics_collector::~metrics_collector() -{ -} - void metrics_collector::snapshot() { m_metrics.clear(); @@ -323,11 +309,11 @@ void metrics_collector::snapshot() int32_t rc = 0; // libscap metrics: m_metrics_flags are pushed down from consumers' input, // libbpf stats only collected when ENGINE_FLAG_BPF_STATS_ENABLED aka `kernel.bpf_stats_enabled = 1` - const metrics_v2* metrics_v2_snapshot = m_inspector->get_capture_stats_v2(m_metrics_flags, &nstats, &rc); - if (metrics_v2_snapshot && nstats > 0 && rc == 0) + const metrics_v2* metrics_v2_scap_snapshot = m_inspector->get_capture_stats_v2(m_metrics_flags, &nstats, &rc); + if (metrics_v2_scap_snapshot && nstats > 0 && rc == 0) { - // Move into m_metrics via std::move - m_metrics = std::vector(metrics_v2_snapshot, metrics_v2_snapshot + nstats); + // Move existing scap metrics raw buffer into m_metrics vector + m_metrics.assign(metrics_v2_scap_snapshot, metrics_v2_scap_snapshot + nstats); } } @@ -342,9 +328,9 @@ void metrics_collector::snapshot() uint64_t memory_used_host{0}, open_fds_host{0}; double cpu_usage_perc{0.0}, cpu_usage_perc_total_host{0.0}; uint64_t container_memory_usage = get_container_memory_usage(); - metrics_v2_value_unit rss_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, vsz_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, \ + metrics_v2_value_unit rss_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, vsz_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, pss_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, memory_used_host_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, container_memory_usage_unit{METRIC_VALUE_UNIT_MEMORY_BYTES}; - metrics_v2_value_type rss_type{METRIC_VALUE_TYPE_U32}, vsz_type{METRIC_VALUE_TYPE_U32}, \ + metrics_v2_value_type rss_type{METRIC_VALUE_TYPE_U32}, vsz_type{METRIC_VALUE_TYPE_U32}, pss_type{METRIC_VALUE_TYPE_U32}, memory_used_host_type{METRIC_VALUE_TYPE_U32}, container_memory_usage_type{METRIC_VALUE_TYPE_U64}; get_cpu_usage_and_total_procs(agent_info->start_time, cpu_usage_perc, cpu_usage_perc_total_host, procs_running_host); get_rss_vsz_pss_total_memory_and_open_fds(rss, vsz, pss, memory_used_host, open_fds_host); @@ -359,24 +345,24 @@ void metrics_collector::snapshot() rss_type = vsz_type = pss_type = memory_used_host_type = container_memory_usage_type = METRIC_VALUE_TYPE_D; } // Resource utilization of the agent itself - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC], METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_D, METRIC_VALUE_UNIT_PERC, METRIC_VALUE_NON_MONOTONIC_CURRENT, cpu_usage_perc)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_RSS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_RSS], METRICS_V2_RESOURCE_UTILIZATION, rss_type, rss_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, rss)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ], METRICS_V2_RESOURCE_UTILIZATION, vsz_type, vsz_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, vsz)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_PSS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_PSS], METRICS_V2_RESOURCE_UTILIZATION, pss_type, pss_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, pss)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY], METRICS_V2_RESOURCE_UTILIZATION, container_memory_usage_type, container_memory_usage_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, container_memory_usage)); // Resource utilization / load indicators of the underlying host - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST], METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_D, METRIC_VALUE_UNIT_PERC, METRIC_VALUE_NON_MONOTONIC_CURRENT, cpu_usage_perc_total_host)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_PROCS_HOST], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_PROCS_HOST], METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, procs_running_host)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST], METRICS_V2_RESOURCE_UTILIZATION, memory_used_host_type, memory_used_host_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, memory_used_host)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST], METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, open_fds_host)); } @@ -400,7 +386,8 @@ void metrics_collector::snapshot() threadinfo_map_t* threadtable = m_inspector->m_thread_manager->get_threads(); if (threadtable) { - threadtable->loop([&] (sinsp_threadinfo& tinfo) { + threadtable->loop([&n_fds] (sinsp_threadinfo& tinfo) + { sinsp_fdtable* fdtable = tinfo.get_fd_table(); if (fdtable != nullptr) { @@ -411,43 +398,43 @@ void metrics_collector::snapshot() } } - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_THREADS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_THREADS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, n_threads)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_FDS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_FDS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, n_fds)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_FD_LOOKUPS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_FD_LOOKUPS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_noncached_fd_lookups)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_FD_LOOKUPS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_FD_LOOKUPS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_cached_fd_lookups)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_FD_LOOKUPS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_FD_LOOKUPS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_failed_fd_lookups)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_FDS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_FDS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_added_fds)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_FDS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_FDS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_removed_fds)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORED_EVTS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORED_EVTS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_stored_evts)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORE_EVTS_DROPS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORE_EVTS_DROPS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_store_evts_drops)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVED_EVTS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVED_EVTS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_retrieved_evts)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVE_EVTS_DROPS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVE_EVTS_DROPS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_retrieve_evts_drops)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_THREAD_LOOKUPS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_THREAD_LOOKUPS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_noncached_thread_lookups)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_THREAD_LOOKUPS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_THREAD_LOOKUPS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_cached_thread_lookups)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_THREAD_LOOKUPS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_THREAD_LOOKUPS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_failed_thread_lookups)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_THREADS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_THREADS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_added_threads)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_THREADS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_THREADS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_removed_threads)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_DROPS_FULL_THREADTABLE], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_DROPS_FULL_THREADTABLE], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_drops_full_threadtable)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_MISSING_CONTAINER_IMAGES], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_MISSING_CONTAINER_IMAGES], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, sinsp_stats_v2->m_n_missing_container_images)); - m_metrics.push_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_CONTAINERS], \ + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_CONTAINERS], \ METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, sinsp_stats_v2->m_n_containers)); } } @@ -458,21 +445,13 @@ const std::vector& metrics_collector::get_metrics() const return m_metrics; } -// Static member init -std::unique_ptr metrics_collector::mc_instance = nullptr; - -// Factory method implementation -std::unique_ptr metrics_collector::create(sinsp* inspector, const uint32_t& flags, const bool& convert_memory_to_mb) +metrics_collector::metrics_collector(sinsp* inspector, uint32_t flags, bool convert_memory_to_mb) : + m_inspector(inspector), + m_metrics_flags(flags), + m_convert_memory_to_mb(convert_memory_to_mb) { - if (!mc_instance) - { - mc_instance = std::unique_ptr(new metrics_collector(inspector, flags, convert_memory_to_mb)); - } - - return std::move(mc_instance); } -} // namespace metrics -} // namespace libsinsp +} // namespace libsinsp::metrics #endif diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index cdabfca6a3..bd7bbcf619 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -17,11 +17,12 @@ limitations under the License. */ #pragma once -#include + #include #include #include #include +#include struct sinsp_stats_v2 { @@ -79,63 +80,58 @@ enum sinsp_stats_v2_resource_utilization #ifdef __linux__ -namespace libsinsp { -namespace metrics { +namespace libsinsp::metrics { class metrics_collector { public: - // Factory method for creating instances - static std::unique_ptr create(sinsp* inspector, const uint32_t& flags, const bool& convert_memory_to_mb); - ~metrics_collector(); + metrics_collector(sinsp* inspector, uint32_t flags, bool convert_memory_to_mb); - // Method to fill up m_metrics_buffer with current metrics; refreshes m_metrics with up-to-date metrics on each call + // 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 buffer + // Method to get a const reference to m_metrics vector const std::vector& get_metrics() const; - // Method to convert memory units; however tied to metrics_v2 definitions + // Method to convert memory units; tied to metrics_v2 definitions template double convert_memory(metrics_v2_value_unit source_unit, metrics_v2_value_unit dest_unit, T val) { - double factor = double(1); + double factor = 1; switch(source_unit) { case METRIC_VALUE_UNIT_MEMORY_BYTES: - factor = double(1); + factor = 1; break; case METRIC_VALUE_UNIT_MEMORY_KILOBYTES: - factor = (double)1024; + factor = 1024.; break; case METRIC_VALUE_UNIT_MEMORY_MEGABYTES: - factor = (double)1024 * (double)1024; + factor = 1024. * 1024.; break; default: - return (double)0; + return 0; } - double bytes_val = val * (double)factor; + double bytes_val = val * factor; switch(dest_unit) { case METRIC_VALUE_UNIT_MEMORY_BYTES: - return (double)bytes_val; + return bytes_val; case METRIC_VALUE_UNIT_MEMORY_KILOBYTES: - return std::round((bytes_val / (double)1024) * (double)10) / (double)10; // round to 1 decimal + return std::round((bytes_val / 1024.) * 10.) / 10.; // round to 1 decimal case METRIC_VALUE_UNIT_MEMORY_MEGABYTES: - return std::round((bytes_val / (double)1024 / (double)1024) * (double)10) / (double)10; // round to 1 decimal + return std::round((bytes_val / 1024. / 1024.) * 10.) / 10.; // round to 1 decimal default: - return (double)0; + return 0; } - return (double)0; + return 0; } private: - metrics_collector(sinsp* inspector, const uint32_t& flags, const bool& convert_memory_to_mb); - static std::unique_ptr mc_instance; sinsp* m_inspector; - uint32_t m_metrics_flags; - bool m_convert_memory_to_mb; + uint32_t m_metrics_flags = METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS; + bool m_convert_memory_to_mb = true; std::vector m_metrics; void 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); @@ -194,7 +190,6 @@ class metrics_collector } }; -} // namespace metrics -} // namespace libsinsp +} // namespace libsinsp::metrics #endif diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index 260e098f76..091905b239 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -33,7 +33,7 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) /* Snapshot current metrics and get the updated metrics_snapshot buffer */ uint32_t test_metrics_flags = (METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); bool convert_memory_to_mb = true; - std::unique_ptr metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags, convert_memory_to_mb); + std::unique_ptr metrics_collector = std::make_unique(&m_inspector, test_metrics_flags, convert_memory_to_mb); metrics_collector->snapshot(); auto metrics_snapshot = metrics_collector->get_metrics(); /* Multiple calls */ @@ -65,7 +65,7 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) /* Assert successful memory unit changes and sanity check some values to be greater than 0 */ const std::vector metrics_names_memory = {"memory_rss", "memory_vsz", "memory_pss", "container_memory_used", "memory_used_host"}; - const std::vector metrics_names_values_gt = {"n_threads", "n_fds", "n_added_threads", "memory_used_host"}; + const std::vector metrics_names_values_gt = {"n_threads", "n_fds", "n_added_threads"}; uint32_t success_memory_cnt = 0; uint32_t success_values_cnt = 0; for (const auto& metric: metrics_snapshot) @@ -74,11 +74,22 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) { ASSERT_EQ(metric.unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES); ASSERT_EQ(metric.type, METRIC_VALUE_TYPE_D); - success_memory_cnt++; + if (strncmp(metric.name, "memory_used_host", 17) == 0 || strncmp(metric.name, "memory_rss", 11) == 0 ) + { + ASSERT_GT(metric.value.d, 0); + // Just making sure we don't get a high value due to an unitialized variables + ASSERT_LT(metric.value.d, 1000000); + success_memory_cnt++; + } else + { + success_memory_cnt++; + } } if (std::find(metrics_names_values_gt.begin(), metrics_names_values_gt.end(), metric.name) != metrics_names_values_gt.end()) { ASSERT_GT(metric.value.u64, 0); + // Just making sure we don't get a high value due to an unitialized variables + ASSERT_LT(metric.value.u64, 106721347371); success_values_cnt++; } } @@ -86,43 +97,43 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) ASSERT_EQ(success_values_cnt, metrics_names_values_gt.size()); /* Empty call */ - metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, 0, convert_memory_to_mb); + metrics_collector = std::make_unique(&m_inspector, 0, convert_memory_to_mb); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); - ASSERT_EQ(metrics_snapshot.size(), 0); + ASSERT_TRUE(metrics_snapshot.empty()); /* Sanity check empty inspector */ test_metrics_flags = (METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); - metrics_collector = libsinsp::metrics::metrics_collector::create(nullptr, test_metrics_flags, convert_memory_to_mb); + metrics_collector = std::make_unique(nullptr, test_metrics_flags, convert_memory_to_mb); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); - ASSERT_EQ(metrics_snapshot.size(), 0); + ASSERT_TRUE(metrics_snapshot.empty()); /* Some sanity checks for selective flags */ test_metrics_flags = 0; test_metrics_flags |= METRICS_V2_KERNEL_COUNTERS; // 20, but can't test it here it's 0 test_metrics_flags |= METRICS_V2_LIBBPF_STATS; // 21 (x86_64 machine), but can't test it here it's 0 - metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags, convert_memory_to_mb); + metrics_collector = std::make_unique(&m_inspector, test_metrics_flags, convert_memory_to_mb); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); - ASSERT_EQ(metrics_snapshot.size(), 0); + ASSERT_TRUE(metrics_snapshot.empty()); test_metrics_flags = 0; test_metrics_flags |= METRICS_V2_RESOURCE_UTILIZATION; - metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags, convert_memory_to_mb); + metrics_collector = std::make_unique(&m_inspector, test_metrics_flags, convert_memory_to_mb); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 9); test_metrics_flags = 0; test_metrics_flags |= METRICS_V2_STATE_COUNTERS; - metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags, convert_memory_to_mb); + metrics_collector = std::make_unique(&m_inspector, test_metrics_flags, convert_memory_to_mb); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 19); test_metrics_flags = (METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); - metrics_collector = libsinsp::metrics::metrics_collector::create(&m_inspector, test_metrics_flags, convert_memory_to_mb); + metrics_collector = std::make_unique(&m_inspector, test_metrics_flags, convert_memory_to_mb); metrics_collector->snapshot(); metrics_snapshot = metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 28); From 68f0554940a663b11bc30c22c68e8fa5af37f832 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Mon, 29 Jan 2024 01:36:51 +0000 Subject: [PATCH 06/22] new(libsinsp): add convert_metric_to_prometheus_text to metrics_collector Signed-off-by: Melissa Kilby --- userspace/libsinsp/metrics_collector.cpp | 53 ++++++++++++++++++++ userspace/libsinsp/metrics_collector.h | 24 +++++++-- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 14 ++++++ 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index 72991d81bf..9cf3e39f52 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -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) @@ -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_collector::get_metrics() const { return m_metrics; diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index bd7bbcf619..f7330101d2 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -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& 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 double convert_memory(metrics_v2_value_unit source_unit, metrics_v2_value_unit dest_unit, T val) { diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index 091905b239..87f7b50e42 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -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 From 40ebff3da3ef7db7aa291398c7b87eab1f68cee0 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Tue, 30 Jan 2024 00:48:08 +0000 Subject: [PATCH 07/22] cleanup(libsinsp): apply reviewers suggestions Co-authored-by: Federico Aponte Signed-off-by: Melissa Kilby --- userspace/libscap/engine/gvisor/gvisor.cpp | 2 +- userspace/libsinsp/metrics_collector.cpp | 2 +- userspace/libsinsp/metrics_collector.h | 13 +++---------- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 2 +- 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/userspace/libscap/engine/gvisor/gvisor.cpp b/userspace/libscap/engine/gvisor/gvisor.cpp index 6d300792fc..e1ec0145cd 100644 --- a/userspace/libscap/engine/gvisor/gvisor.cpp +++ b/userspace/libscap/engine/gvisor/gvisor.cpp @@ -189,7 +189,7 @@ static int32_t gvisor_get_stats(scap_engine_handle engine, scap_stats* stats) return engine.m_handle->get_stats(stats); } -static const struct metrics_v2* gvisor_get_stats_v2(scap_engine_handle engine, uint32_t flags, uint32_t* nstats, int32_t* rc) +static const metrics_v2* gvisor_get_stats_v2(scap_engine_handle engine, uint32_t flags, uint32_t* nstats, int32_t* rc) { return engine.m_handle->get_stats_v2(flags, nstats, rc); } diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index 9cf3e39f52..715ce91e68 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -456,7 +456,7 @@ void metrics_collector::snapshot() } } -const std::string metrics_collector::convert_metric_to_prometheus_text(std::string metric_name, metrics_v2 metric) const +std::string metrics_collector::convert_metric_to_prometheus_text(std::string metric_name, metrics_v2 metric) { std::string prometheus_text = metric_name; prometheus_text += "{raw_name=\"" + std::string(metric.name) + "\",unit=\"" + std::string(metrics_unit_name_mappings[metric.unit]) \ diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index f7330101d2..1de5041de0 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -107,13 +107,13 @@ class metrics_collector * * This method is a work in progress. */ - const std::string convert_metric_to_prometheus_text(std::string metric_name, metrics_v2 metric) const; + std::string convert_metric_to_prometheus_text(std::string metric_name, metrics_v2 metric); /*! \brief Method to convert memory units; tied to metrics_v2 definitions */ template - double convert_memory(metrics_v2_value_unit source_unit, metrics_v2_value_unit dest_unit, T val) + static double convert_memory(metrics_v2_value_unit source_unit, metrics_v2_value_unit dest_unit, T val) { double factor = 1; switch(source_unit) @@ -170,36 +170,29 @@ class metrics_collector } template - void set_new_metric(metrics_v2& metric, metrics_v2_value_type type, T val) + static void set_new_metric(metrics_v2& metric, metrics_v2_value_type type, T val) { switch (type) { case METRIC_VALUE_TYPE_U32: - metric.type = METRIC_VALUE_TYPE_U32; metric.value.u32 = static_cast(val); break; case METRIC_VALUE_TYPE_S32: - metric.type = METRIC_VALUE_TYPE_S32; metric.value.s32 = static_cast(val); break; case METRIC_VALUE_TYPE_U64: - metric.type = METRIC_VALUE_TYPE_U64; metric.value.u64 = static_cast(val); break; case METRIC_VALUE_TYPE_S64: - metric.type = METRIC_VALUE_TYPE_S64; metric.value.s64 = static_cast(val); break; case METRIC_VALUE_TYPE_D: - metric.type = METRIC_VALUE_TYPE_D; metric.value.d = static_cast(val); break; case METRIC_VALUE_TYPE_F: - metric.type = METRIC_VALUE_TYPE_F; metric.value.f = static_cast(val); break; case METRIC_VALUE_TYPE_I: - metric.type = METRIC_VALUE_TYPE_I; metric.value.i = static_cast(val); break; default: diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index 87f7b50e42..1aceb7ef4c 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -33,7 +33,7 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) /* Snapshot current metrics and get the updated metrics_snapshot buffer */ uint32_t test_metrics_flags = (METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); bool convert_memory_to_mb = true; - std::unique_ptr metrics_collector = std::make_unique(&m_inspector, test_metrics_flags, convert_memory_to_mb); + auto metrics_collector = std::make_unique(&m_inspector, test_metrics_flags, convert_memory_to_mb); metrics_collector->snapshot(); auto metrics_snapshot = metrics_collector->get_metrics(); /* Multiple calls */ From 8000c0c1ecc58cf2a0438913fc97a6ee81a41c34 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Tue, 30 Jan 2024 21:32:08 +0000 Subject: [PATCH 08/22] cleanup(libsinsp): metrics text - pass by string_view Co-authored-by: Federico Aponte Signed-off-by: Melissa Kilby --- userspace/libsinsp/metrics_collector.cpp | 4 ++-- userspace/libsinsp/metrics_collector.h | 3 ++- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index 715ce91e68..8776e49e50 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -456,9 +456,9 @@ void metrics_collector::snapshot() } } -std::string metrics_collector::convert_metric_to_prometheus_text(std::string metric_name, metrics_v2 metric) +std::string metrics_collector::convert_metric_to_prometheus_text(std::string_view metric_name, metrics_v2 metric) { - std::string prometheus_text = metric_name; + std::string prometheus_text(metric_name.begin(), metric_name.end()); 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) diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index 1de5041de0..9b90224869 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -23,6 +23,7 @@ limitations under the License. #include #include #include +#include struct sinsp_stats_v2 { @@ -107,7 +108,7 @@ class metrics_collector * * This method is a work in progress. */ - std::string convert_metric_to_prometheus_text(std::string metric_name, metrics_v2 metric); + std::string convert_metric_to_prometheus_text(std::string_view metric_name, metrics_v2 metric); /*! \brief Method to convert memory units; tied to metrics_v2 definitions diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index 1aceb7ef4c..0f2a8bb020 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -152,7 +152,8 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) // 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); + std::string_view s(metric_name); + std::string prometheus_text = metrics_collector->convert_metric_to_prometheus_text(s, 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"; From 94b1d223db851990ba91bcc9b24b16630e2394fa Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Fri, 2 Feb 2024 22:36:03 +0000 Subject: [PATCH 09/22] cleanup(libsinsp): expand convert_metric_to_prometheus_text Signed-off-by: Melissa Kilby --- userspace/libsinsp/metrics_collector.cpp | 21 ++++++++++++++------ userspace/libsinsp/metrics_collector.h | 18 ++++++++++++----- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 6 ++++-- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index 8776e49e50..411f01398a 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -66,9 +66,10 @@ static const char *const metrics_unit_name_mappings[] = { }; // 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", +// https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md +static const char *const metrics_metric_type_name_mappings_prom[] = { + [METRIC_VALUE_MONOTONIC] = "counter", + [METRIC_VALUE_NON_MONOTONIC_CURRENT] = "gauge", }; namespace libsinsp::metrics { @@ -456,11 +457,19 @@ void metrics_collector::snapshot() } } -std::string metrics_collector::convert_metric_to_prometheus_text(std::string_view metric_name, metrics_v2 metric) +std::string metrics_collector::convert_metric_to_prometheus_text(std::string_view metric_name, metrics_v2 metric, std::map custom_labels) { std::string prometheus_text(metric_name.begin(), metric_name.end()); - 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! + prometheus_text += "{raw_name=\"" + std::string(metric.name) + + "\",unit=\"" + std::string(metrics_unit_name_mappings[metric.unit]) + + "\",type=\"" + std::string(metrics_metric_type_name_mappings_prom[metric.metric_type]) + + "\"" ; + // add custom prom labels if applicable + for (const auto& [key, value] : custom_labels) + { + prometheus_text += "," + key + "=\"" + value + "\"" ; + } + prometheus_text += "} "; // white space at the end important! switch (metric.type) { case METRIC_VALUE_TYPE_U32: diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index 9b90224869..4051e02fa8 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -101,14 +101,22 @@ class metrics_collector /*! \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 + * Note: The design idea is to expose Prometheus metrics by piping text-based formats to new line-delimited fields + * exposed at /metrics in Falco's existing HTTP webserver, eliminating the need for implementing a complete Prometheus client. + * + * We exclusively support counter and gauge Prometheus metric types, covering metrics from kernel driver tracepoints + * to linsinsp and client metrics. Introducing a registry seems excessive, especially given the dynamic nature of the final + * metric string names, such as variations in tracepoints across architectures. + * There are no plans to include # HELP or # TYPE lines. Instead, we incorporate the Prometheus type as a label and direct + * users to our documentation at: + * https://falco.org/docs/metrics/falco-metrics/ + * + * Example + * test.memory_used_host{raw_name="memory_used_host",unit="MEMORY_MEGABYTES",type="gauge",host="testbox",kernel="6.6.7-200.fc39.x86_64"} 15096.000000 1706490801547502000 * * This method is a work in progress. */ - std::string convert_metric_to_prometheus_text(std::string_view metric_name, metrics_v2 metric); + std::string convert_metric_to_prometheus_text(std::string_view metric_name, metrics_v2 metric, std::map custom_labels = {}); /*! \brief Method to convert memory units; tied to metrics_v2 definitions diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index 0f2a8bb020..a803aa856a 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -147,16 +147,18 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) ASSERT_EQ(converted_memory, 50); /* Test public convert_metric_to_prometheus_text */ + // using an ordered map to ensure metrics text is predictable, as the goal is to have them be human-readable + std::map custom_prom_labels = {{"kernel", "6.6.7-200.fc39.x86_64"},{"host", "testbox"}}; 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_view s(metric_name); - std::string prometheus_text = metrics_collector->convert_metric_to_prometheus_text(s, metric); + std::string prometheus_text = metrics_collector->convert_metric_to_prometheus_text(s, metric, custom_prom_labels); 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"; + std::string prometheus_text_substring = "test.n_missing_container_images{raw_name=\"n_missing_container_images\",unit=\"COUNT\",type=\"gauge\",host=\"testbox\",kernel=\"6.6.7-200.fc39.x86_64\"} 0"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; } ASSERT_GT(prometheus_text.length(), 8); From 99c6ebbc384553fd9151a205f32cbf3831eb59a2 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Fri, 2 Feb 2024 22:55:38 +0000 Subject: [PATCH 10/22] update: introduce new rule counters metrics category macro Signed-off-by: Melissa Kilby --- userspace/libscap/metrics_v2.h | 1 + 1 file changed, 1 insertion(+) diff --git a/userspace/libscap/metrics_v2.h b/userspace/libscap/metrics_v2.h index 4e6320200a..805dbbb79c 100644 --- a/userspace/libscap/metrics_v2.h +++ b/userspace/libscap/metrics_v2.h @@ -37,6 +37,7 @@ extern "C" { #define METRICS_V2_LIBBPF_STATS (1 << 1) #define METRICS_V2_RESOURCE_UTILIZATION (1 << 2) #define METRICS_V2_STATE_COUNTERS (1 << 3) +#define METRICS_V2_RULE_COUNTERS (1 << 4) typedef union metrics_v2_value { uint32_t u32; From 44b1b3c8600be3ca392c550363a3765a648a5306 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Wed, 7 Feb 2024 06:53:29 +0000 Subject: [PATCH 11/22] refactor(libsinsp): convert_metric_to_prom_text follow some best practices Co-authored-by: Mickael Carl Signed-off-by: Melissa Kilby --- userspace/libpman/src/stats.c | 4 +- userspace/libscap/engine/bpf/scap_bpf.c | 4 +- userspace/libscap/metrics_v2.h | 2 +- userspace/libsinsp/metrics_collector.cpp | 97 ++++++++++++++------ userspace/libsinsp/metrics_collector.h | 67 ++++++++++---- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 65 +++++++++++-- 6 files changed, 179 insertions(+), 60 deletions(-) diff --git a/userspace/libpman/src/stats.c b/userspace/libpman/src/stats.c index 810c66639e..1289c0dbd1 100644 --- a/userspace/libpman/src/stats.c +++ b/userspace/libpman/src/stats.c @@ -263,13 +263,13 @@ struct metrics_v2 *pman_get_metrics_v2(uint32_t flags, uint32_t *nstats, int32_t break; case RUN_TIME_NS: strlcat(g_state.stats[offset].name, modern_bpf_libbpf_stats_names[RUN_TIME_NS], sizeof(g_state.stats[offset].name)); - g_state.stats[stat].unit = METRIC_VALUE_UNIT_TIME_NS; + g_state.stats[stat].unit = METRIC_VALUE_UNIT_DURATION_NS; g_state.stats[stat].metric_type = METRIC_VALUE_MONOTONIC; g_state.stats[offset].value.u64 = info.run_time_ns; break; case AVG_TIME_NS: strlcat(g_state.stats[offset].name, modern_bpf_libbpf_stats_names[AVG_TIME_NS], sizeof(g_state.stats[offset].name)); - g_state.stats[stat].unit = METRIC_VALUE_UNIT_TIME_NS; + g_state.stats[stat].unit = METRIC_VALUE_UNIT_DURATION_NS; g_state.stats[stat].metric_type = METRIC_VALUE_NON_MONOTONIC_CURRENT; g_state.stats[offset].value.u64 = 0; if(info.run_cnt > 0) diff --git a/userspace/libscap/engine/bpf/scap_bpf.c b/userspace/libscap/engine/bpf/scap_bpf.c index 7edce64bbe..0b0dde0763 100644 --- a/userspace/libscap/engine/bpf/scap_bpf.c +++ b/userspace/libscap/engine/bpf/scap_bpf.c @@ -1833,13 +1833,13 @@ const struct metrics_v2* scap_bpf_get_stats_v2(struct scap_engine_handle engine, case RUN_TIME_NS: strlcat(stats[offset].name, bpf_libbpf_stats_names[RUN_TIME_NS], sizeof(stats[offset].name)); stats[offset].value.u64 = info.run_time_ns; - stats[offset].unit = METRIC_VALUE_UNIT_TIME_NS; + stats[offset].unit = METRIC_VALUE_UNIT_DURATION_NS; stats[offset].metric_type = METRIC_VALUE_MONOTONIC; break; case AVG_TIME_NS: strlcat(stats[offset].name, bpf_libbpf_stats_names[AVG_TIME_NS], sizeof(stats[offset].name)); stats[offset].value.u64 = 0; - stats[offset].unit = METRIC_VALUE_UNIT_TIME_NS; + stats[offset].unit = METRIC_VALUE_UNIT_DURATION_NS; stats[offset].metric_type = METRIC_VALUE_NON_MONOTONIC_CURRENT; if (info.run_cnt > 0) { diff --git a/userspace/libscap/metrics_v2.h b/userspace/libscap/metrics_v2.h index 805dbbb79c..67a936e7ef 100644 --- a/userspace/libscap/metrics_v2.h +++ b/userspace/libscap/metrics_v2.h @@ -65,7 +65,7 @@ typedef enum metrics_v2_value_unit{ METRIC_VALUE_UNIT_MEMORY_BYTES, METRIC_VALUE_UNIT_MEMORY_KILOBYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, - METRIC_VALUE_UNIT_TIME_NS, + METRIC_VALUE_UNIT_DURATION_NS, }metrics_v2_value_unit; typedef enum metrics_v2_metric_type{ diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index 411f01398a..524a5e32ca 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -56,13 +56,14 @@ static const char *const sinsp_stats_v2_resource_utilization_names[] = { }; // 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", +// https://prometheus.io/docs/practices/naming/ +static const char *const metrics_unit_name_mappings_prom[] = { + [METRIC_VALUE_UNIT_COUNT] = "total", + [METRIC_VALUE_UNIT_PERC] = "percentage", + [METRIC_VALUE_UNIT_MEMORY_BYTES] = "bytes", + [METRIC_VALUE_UNIT_MEMORY_KILOBYTES] = "kilobytes", + [METRIC_VALUE_UNIT_MEMORY_MEGABYTES] = "megabytes", + [METRIC_VALUE_UNIT_DURATION_NS] = "duration_nanoseconds", }; // For simplicity, needs to stay in sync w/ typedef enum metrics_v2_metric_type @@ -457,49 +458,91 @@ void metrics_collector::snapshot() } } -std::string metrics_collector::convert_metric_to_prometheus_text(std::string_view metric_name, metrics_v2 metric, std::map custom_labels) +std::string metrics_collector::convert_metric_to_prom_text(metrics_v2 metric, std::string_view prom_namespace, std::string_view prom_subsystem, std::map const_labels) { - std::string prometheus_text(metric_name.begin(), metric_name.end()); - prometheus_text += "{raw_name=\"" + std::string(metric.name) - + "\",unit=\"" + std::string(metrics_unit_name_mappings[metric.unit]) - + "\",type=\"" + std::string(metrics_metric_type_name_mappings_prom[metric.metric_type]) - + "\"" ; - // add custom prom labels if applicable - for (const auto& [key, value] : custom_labels) + // Create `prom_metric_name_fully_qualified` + std::string prom_metric_name_fully_qualified; + if (!prom_namespace.empty()) { - prometheus_text += "," + key + "=\"" + value + "\"" ; + prom_metric_name_fully_qualified += std::string(prom_namespace) + "_"; } - prometheus_text += "} "; // white space at the end important! + if (!prom_subsystem.empty()) + { + prom_metric_name_fully_qualified += std::string(prom_subsystem) + "_"; + } + prom_metric_name_fully_qualified += std::string(metric.name) + "_"; + prom_metric_name_fully_qualified += std::string(metrics_unit_name_mappings_prom[metric.unit]); + + // Create the complete 3-lines text-based Prometheus exposition format https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md + std::string prom_text = "# HELP " + prom_metric_name_fully_qualified + " https://falco.org/docs/metrics/\n"; + prom_text += "# TYPE " + prom_metric_name_fully_qualified + " " + std::string(metrics_metric_type_name_mappings_prom[metric.metric_type]) + "\n"; + prom_text += prom_metric_name_fully_qualified; + prom_text += "{raw_name=\"" + std::string(metric.name) + "\"" ; + for (const auto& [key, value] : const_labels) + { + prom_text += "," + key + "=\"" + value + "\"" ; + } + prom_text += "} "; // white space at the end important! switch (metric.type) { case METRIC_VALUE_TYPE_U32: - prometheus_text += std::to_string(metric.value.u32); + prom_text += std::to_string(metric.value.u32); break; case METRIC_VALUE_TYPE_S32: - prometheus_text += std::to_string(metric.value.s32); + prom_text += std::to_string(metric.value.s32); break; case METRIC_VALUE_TYPE_U64: - prometheus_text += std::to_string(metric.value.u64); + prom_text += std::to_string(metric.value.u64); break; case METRIC_VALUE_TYPE_S64: - prometheus_text += std::to_string(metric.value.s64); + prom_text += std::to_string(metric.value.s64); break; case METRIC_VALUE_TYPE_D: - prometheus_text += std::to_string(metric.value.d); + prom_text += std::to_string(metric.value.d); break; case METRIC_VALUE_TYPE_F: - prometheus_text += std::to_string(metric.value.f); + prom_text += std::to_string(metric.value.f); break; case METRIC_VALUE_TYPE_I: - prometheus_text += std::to_string(metric.value.i); + prom_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; + prom_text += " "; + prom_text += std::to_string(sinsp_utils::get_current_time_ns()); + prom_text += "\n"; + return prom_text; +} + +std::string metrics_collector::convert_metric_to_prom_text(std::string_view metric_name, std::string_view prom_namespace, std::string_view prom_subsystem, std::map const_labels) +{ + // Create `prom_metric_name_fully_qualified` + std::string prom_metric_name_fully_qualified; + if (!prom_namespace.empty()) + { + prom_metric_name_fully_qualified += std::string(prom_namespace) + "_"; + } + if (!prom_subsystem.empty()) + { + prom_metric_name_fully_qualified += std::string(prom_subsystem) + "_"; + } + prom_metric_name_fully_qualified += std::string(metric_name) + "_info"; + + // Create the complete 3-lines text-based Prometheus exposition format https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md + std::string prom_text = "# HELP " + prom_metric_name_fully_qualified + " https://falco.org/docs/metrics/\n"; + prom_text += "# TYPE " + prom_metric_name_fully_qualified + " untyped\n"; + prom_text += prom_metric_name_fully_qualified; + prom_text += "{raw_name=\"" + std::string(metric_name) + "\"" ; + for (const auto& [key, value] : const_labels) + { + prom_text += "," + key + "=\"" + value + "\"" ; + } + prom_text += "} 1 "; // white space at the end important! + prom_text += std::to_string(sinsp_utils::get_current_time_ns()); + prom_text += "\n"; + return prom_text; } const std::vector& metrics_collector::get_metrics() const diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index 4051e02fa8..76d26b68a9 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -99,24 +99,52 @@ class metrics_collector const std::vector& get_metrics() const; /*! - \brief Method to convert a metric to the text-based Prometheus format. + \brief Method to convert a metric to the text-based Prometheus exposition 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's existing HTTP webserver, eliminating the need for implementing a complete Prometheus client. + * exposed at /metrics in Falco's existing HTTP webserver (w/ optional mTLS support), eliminating the need for implementing + * a complete Prometheus client. * * We exclusively support counter and gauge Prometheus metric types, covering metrics from kernel driver tracepoints * to linsinsp and client metrics. Introducing a registry seems excessive, especially given the dynamic nature of the final * metric string names, such as variations in tracepoints across architectures. - * There are no plans to include # HELP or # TYPE lines. Instead, we incorporate the Prometheus type as a label and direct - * users to our documentation at: - * https://falco.org/docs/metrics/falco-metrics/ + * Considering the simplistic use case, adding another dependency to the project does not seem justified. Furthermore, for C++ + * (compared to Go for example), there appear to be fewer formal client library projects available. Plus, we need to think + * about stability and long-term support before adding any new dependency. * - * Example - * test.memory_used_host{raw_name="memory_used_host",unit="MEMORY_MEGABYTES",type="gauge",host="testbox",kernel="6.6.7-200.fc39.x86_64"} 15096.000000 1706490801547502000 + * The final fully qualified Prometheus metric name partially follows https://prometheus.io/docs/practices/naming/ + * Prepend namespace and subsystem with "_" delimiter to create a fully qualified metric name according to + * https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#Opts + append unit with "_" delimiter + * We do not follow the concept of base_units, but guarantee no units are mixed per unique `prom_metric_name_fully_qualified` + * + * Example: + * + * # HELP testns_falco_n_threads_total https://falco.org/docs/metrics/ + * # TYPE testns_falco_n_threads_total gauge + * testns_falco_n_threads_total{raw_name="n_threads",example_key1="example1",example_key2="example2"} 12 1707281978248705000 + * # HELP testns_falco_memory_rss_megabytes https://falco.org/docs/metrics/ + * # TYPE testns_falco_memory_rss_megabytes gauge + * testns_falco_memory_rss_megabytes{raw_name="memory_rss",example_key1="example1",example_key2="example2"} 350.000000 1707281978248635000 * * This method is a work in progress. */ - std::string convert_metric_to_prometheus_text(std::string_view metric_name, metrics_v2 metric, std::map custom_labels = {}); + std::string convert_metric_to_prom_text(metrics_v2 metric, std::string_view prom_namespace = "", std::string_view prom_subsystem = "", std::map const_labels = {}); + + /*! + \brief Method to convert a software version like metric to the text-based Prometheus exposition format. + * + * Note: Instead of using const_labels, which is a rare use case according to https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels, + * exposing an overload to support metrics similar to https://www.robustperception.io/exposing-the-software-version-to-prometheus/. + * This approach is applicable to https://falco.org/docs/metrics/, such as Falco's "Base Fields" like falco.kernel_release and falco.version. + * + * Example: + * + * # HELP testns_falco_kernel_release_info https://falco.org/docs/metrics/ + * # TYPE testns_falco_kernel_release_info untyped + * testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7-200.fc39.x86_64"} 1 1707286535681433000 + */ + std::string convert_metric_to_prom_text(std::string_view metric_name, std::string_view prom_namespace = "", std::string_view prom_subsystem = "", std::map const_labels = {}); /*! \brief Method to convert memory units; tied to metrics_v2 definitions @@ -155,16 +183,9 @@ class metrics_collector return 0; } -private: - sinsp* m_inspector; - uint32_t m_metrics_flags = METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS; - bool m_convert_memory_to_mb = true; - std::vector m_metrics; - - void 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); - void get_cpu_usage_and_total_procs(double start_time, double &cpu_usage_perc, double &cpu_usage_perc_total_host, uint32_t &procs_running_host); - uint64_t get_container_memory_usage() const; - + /*! + \brief Method to create a new metrics_v2 + */ template const metrics_v2 new_metric(const char* name, uint32_t flags, metrics_v2_value_type type, metrics_v2_value_unit unit, metrics_v2_metric_type metric_type, T val) { @@ -178,6 +199,16 @@ class metrics_collector return metric; } +private: + sinsp* m_inspector; + uint32_t m_metrics_flags = METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS; + bool m_convert_memory_to_mb = true; + std::vector m_metrics; + + void 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); + void get_cpu_usage_and_total_procs(double start_time, double &cpu_usage_perc, double &cpu_usage_perc_total_host, uint32_t &procs_running_host); + uint64_t get_container_memory_usage() const; + template static void set_new_metric(metrics_v2& metric, metrics_v2_value_type type, T val) { diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index a803aa856a..cea7977478 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -146,22 +146,67 @@ 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 */ - // using an ordered map to ensure metrics text is predictable, as the goal is to have them be human-readable - std::map custom_prom_labels = {{"kernel", "6.6.7-200.fc39.x86_64"},{"host", "testbox"}}; + /* Test public convert_metric_to_prom_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_view s(metric_name); - std::string prometheus_text = metrics_collector->convert_metric_to_prometheus_text(s, metric, custom_prom_labels); 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\",type=\"gauge\",host=\"testbox\",kernel=\"6.6.7-200.fc39.x86_64\"} 0"; + // This resembles the Falco client use case + + // Falco output_rule metrics prepends either `falco.` or `scap.` to a single metric, see https://falco.org/docs/metrics/ + // Use same strings for `prom_subsystem`, but instead of `.` we use `_` delimiter to conform with Prometheus naming conventions + append the unit + std::string prometheus_text = metrics_collector->convert_metric_to_prom_text(metric, "testns", "falco", {{"example_key1", "example1"},{"example_key2", "example2"}}); + std::string prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ +# TYPE testns_falco_n_missing_container_images_total gauge +testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1",example_key2="example2"} 0)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); + // Test only one const_labels + prometheus_text = metrics_collector->convert_metric_to_prom_text(metric, "testns", "falco", {{"example_key1", "example1"}}); + prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ +# TYPE testns_falco_n_missing_container_images_total gauge +testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1"} 0)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); + // Test no const_labels + prometheus_text = metrics_collector->convert_metric_to_prom_text(metric, "testns", "falco"); + prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ +# TYPE testns_falco_n_missing_container_images_total gauge +testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); + // Test no prom_subsytem + prometheus_text = metrics_collector->convert_metric_to_prom_text(metric, "testns"); + prometheus_text_substring = R"(# HELP testns_n_missing_container_images_total https://falco.org/docs/metrics/ +# TYPE testns_n_missing_container_images_total gauge +testns_n_missing_container_images_total{raw_name="n_missing_container_images"} 0)"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); + // Test no prom_namespace + prometheus_text = metrics_collector->convert_metric_to_prom_text(metric); + prometheus_text_substring = R"(# HELP n_missing_container_images_total https://falco.org/docs/metrics/ +# TYPE n_missing_container_images_total gauge +n_missing_container_images_total{raw_name="n_missing_container_images"} 0)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); + // Test no prom_namespace, but prom_subsytem + prometheus_text = metrics_collector->convert_metric_to_prom_text(metric, "", "falco"); + prometheus_text_substring = R"(# HELP falco_n_missing_container_images_total https://falco.org/docs/metrics/ +# TYPE falco_n_missing_container_images_total gauge +falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); + } - ASSERT_GT(prometheus_text.length(), 8); } + + std::string prometheus_text = metrics_collector->convert_metric_to_prom_text("kernel_release", "testns", "falco", {{"kernel_release", "6.6.7-200.fc39.x86_64"}}); + std::string prometheus_text_substring = R"(# HELP testns_falco_kernel_release_info https://falco.org/docs/metrics/ +# TYPE testns_falco_kernel_release_info untyped +testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7-200.fc39.x86_64"} 1)"; + printf("%s", prometheus_text.c_str()); + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); } #endif From 289c63b17ba394a61dcae8ae5526f14a32c3a9b7 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Wed, 7 Feb 2024 07:20:55 +0000 Subject: [PATCH 12/22] chore: revert some changes to get_sinsp_stats_v2 Signed-off-by: Melissa Kilby --- userspace/libsinsp/sinsp.cpp | 5 +++++ userspace/libsinsp/sinsp.h | 1 + 2 files changed, 6 insertions(+) diff --git a/userspace/libsinsp/sinsp.cpp b/userspace/libsinsp/sinsp.cpp index a6eb0c6502..4b63a3dae3 100644 --- a/userspace/libsinsp/sinsp.cpp +++ b/userspace/libsinsp/sinsp.cpp @@ -1740,6 +1740,11 @@ const scap_agent_info* sinsp::get_agent_info() const return m_agent_info; } +std::shared_ptr sinsp::get_sinsp_stats_v2() +{ + return m_sinsp_stats_v2; +} + std::shared_ptr sinsp::get_sinsp_stats_v2() const { return m_sinsp_stats_v2; diff --git a/userspace/libsinsp/sinsp.h b/userspace/libsinsp/sinsp.h index 24364f61ac..794a16438a 100644 --- a/userspace/libsinsp/sinsp.h +++ b/userspace/libsinsp/sinsp.h @@ -468,6 +468,7 @@ class SINSP_PUBLIC sinsp : public capture_stats_source \brief Return sinsp stats v2 containing continually updated counters around thread and fd state tables. */ + std::shared_ptr get_sinsp_stats_v2(); std::shared_ptr get_sinsp_stats_v2() const; /*! From 24d01f4e01b5b7d91935d30910fef6a6f74191dc Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Thu, 8 Feb 2024 00:35:45 +0000 Subject: [PATCH 13/22] cleanup(libsinp): improve prometheus format conversion correctness Co-authored-by: Mickael Carl Signed-off-by: Melissa Kilby --- userspace/libscap/metrics_v2.h | 3 +- userspace/libsinsp/metrics_collector.cpp | 93 ++++++++++---------- userspace/libsinsp/metrics_collector.h | 47 +++++++--- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 51 ++++++----- 4 files changed, 109 insertions(+), 85 deletions(-) diff --git a/userspace/libscap/metrics_v2.h b/userspace/libscap/metrics_v2.h index 67a936e7ef..7eacb966ad 100644 --- a/userspace/libscap/metrics_v2.h +++ b/userspace/libscap/metrics_v2.h @@ -63,9 +63,10 @@ typedef enum metrics_v2_value_unit{ METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_UNIT_PERC, METRIC_VALUE_UNIT_MEMORY_BYTES, - METRIC_VALUE_UNIT_MEMORY_KILOBYTES, + METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, METRIC_VALUE_UNIT_DURATION_NS, + METRIC_VALUE_UNIT_DURATION_S, }metrics_v2_value_unit; typedef enum metrics_v2_metric_type{ diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index 524a5e32ca..e6e213ef60 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -57,18 +57,19 @@ static const char *const sinsp_stats_v2_resource_utilization_names[] = { // For simplicity, needs to stay in sync w/ typedef enum metrics_v2_value_unit // https://prometheus.io/docs/practices/naming/ -static const char *const metrics_unit_name_mappings_prom[] = { +static const char *const metrics_unit_name_mappings_prometheus[] = { [METRIC_VALUE_UNIT_COUNT] = "total", [METRIC_VALUE_UNIT_PERC] = "percentage", [METRIC_VALUE_UNIT_MEMORY_BYTES] = "bytes", - [METRIC_VALUE_UNIT_MEMORY_KILOBYTES] = "kilobytes", + [METRIC_VALUE_UNIT_MEMORY_KIBIBYTES] = "kibibytes", [METRIC_VALUE_UNIT_MEMORY_MEGABYTES] = "megabytes", [METRIC_VALUE_UNIT_DURATION_NS] = "duration_nanoseconds", + [METRIC_VALUE_UNIT_DURATION_S] = "duration_seconds", }; // For simplicity, needs to stay in sync w/ typedef enum metrics_v2_metric_type // https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md -static const char *const metrics_metric_type_name_mappings_prom[] = { +static const char *const metrics_metric_type_name_mappings_prometheus[] = { [METRIC_VALUE_MONOTONIC] = "counter", [METRIC_VALUE_NON_MONOTONIC_CURRENT] = "gauge", }; @@ -346,8 +347,8 @@ void metrics_collector::snapshot() uint64_t memory_used_host{0}, open_fds_host{0}; double cpu_usage_perc{0.0}, cpu_usage_perc_total_host{0.0}; uint64_t container_memory_usage = get_container_memory_usage(); - metrics_v2_value_unit rss_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, vsz_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, - pss_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, memory_used_host_unit{METRIC_VALUE_UNIT_MEMORY_KILOBYTES}, container_memory_usage_unit{METRIC_VALUE_UNIT_MEMORY_BYTES}; + metrics_v2_value_unit rss_unit{METRIC_VALUE_UNIT_MEMORY_KIBIBYTES}, vsz_unit{METRIC_VALUE_UNIT_MEMORY_KIBIBYTES}, + pss_unit{METRIC_VALUE_UNIT_MEMORY_KIBIBYTES}, memory_used_host_unit{METRIC_VALUE_UNIT_MEMORY_KIBIBYTES}, container_memory_usage_unit{METRIC_VALUE_UNIT_MEMORY_BYTES}; metrics_v2_value_type rss_type{METRIC_VALUE_TYPE_U32}, vsz_type{METRIC_VALUE_TYPE_U32}, pss_type{METRIC_VALUE_TYPE_U32}, memory_used_host_type{METRIC_VALUE_TYPE_U32}, container_memory_usage_type{METRIC_VALUE_TYPE_U64}; get_cpu_usage_and_total_procs(agent_info->start_time, cpu_usage_perc, cpu_usage_perc_total_host, procs_running_host); @@ -458,91 +459,87 @@ void metrics_collector::snapshot() } } -std::string metrics_collector::convert_metric_to_prom_text(metrics_v2 metric, std::string_view prom_namespace, std::string_view prom_subsystem, std::map const_labels) +std::string metrics_collector::convert_metric_to_prometheus_text(metrics_v2 metric, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, std::map const_labels) { - // Create `prom_metric_name_fully_qualified` - std::string prom_metric_name_fully_qualified; - if (!prom_namespace.empty()) + // Create `prometheus_metric_name_fully_qualified` + std::string prometheus_metric_name_fully_qualified; + if (!prometheus_namespace.empty()) { - prom_metric_name_fully_qualified += std::string(prom_namespace) + "_"; + prometheus_metric_name_fully_qualified += std::string(prometheus_namespace) + "_"; } - if (!prom_subsystem.empty()) + if (!prometheus_subsystem.empty()) { - prom_metric_name_fully_qualified += std::string(prom_subsystem) + "_"; + prometheus_metric_name_fully_qualified += std::string(prometheus_subsystem) + "_"; } - prom_metric_name_fully_qualified += std::string(metric.name) + "_"; - prom_metric_name_fully_qualified += std::string(metrics_unit_name_mappings_prom[metric.unit]); + prometheus_metric_name_fully_qualified += std::string(metric.name) + "_"; + prometheus_metric_name_fully_qualified += std::string(metrics_unit_name_mappings_prometheus[metric.unit]); // Create the complete 3-lines text-based Prometheus exposition format https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md - std::string prom_text = "# HELP " + prom_metric_name_fully_qualified + " https://falco.org/docs/metrics/\n"; - prom_text += "# TYPE " + prom_metric_name_fully_qualified + " " + std::string(metrics_metric_type_name_mappings_prom[metric.metric_type]) + "\n"; - prom_text += prom_metric_name_fully_qualified; - prom_text += "{raw_name=\"" + std::string(metric.name) + "\"" ; + std::string prometheus_text = "# HELP " + prometheus_metric_name_fully_qualified + " https://falco.org/docs/metrics/\n"; + prometheus_text += "# TYPE " + prometheus_metric_name_fully_qualified + " " + std::string(metrics_metric_type_name_mappings_prometheus[metric.metric_type]) + "\n"; + prometheus_text += prometheus_metric_name_fully_qualified; + prometheus_text += "{raw_name=\"" + std::string(metric.name) + "\"" ; for (const auto& [key, value] : const_labels) { - prom_text += "," + key + "=\"" + value + "\"" ; + prometheus_text += "," + key + "=\"" + value + "\"" ; } - prom_text += "} "; // white space at the end important! + prometheus_text += "} "; // white space at the end important! switch (metric.type) { case METRIC_VALUE_TYPE_U32: - prom_text += std::to_string(metric.value.u32); + prometheus_text += std::to_string(metric.value.u32); break; case METRIC_VALUE_TYPE_S32: - prom_text += std::to_string(metric.value.s32); + prometheus_text += std::to_string(metric.value.s32); break; case METRIC_VALUE_TYPE_U64: - prom_text += std::to_string(metric.value.u64); + prometheus_text += std::to_string(metric.value.u64); break; case METRIC_VALUE_TYPE_S64: - prom_text += std::to_string(metric.value.s64); + prometheus_text += std::to_string(metric.value.s64); break; case METRIC_VALUE_TYPE_D: - prom_text += std::to_string(metric.value.d); + prometheus_text += std::to_string(metric.value.d); break; case METRIC_VALUE_TYPE_F: - prom_text += std::to_string(metric.value.f); + prometheus_text += std::to_string(metric.value.f); break; case METRIC_VALUE_TYPE_I: - prom_text += std::to_string(metric.value.i); + prometheus_text += std::to_string(metric.value.i); break; default: break; } - prom_text += " "; - prom_text += std::to_string(sinsp_utils::get_current_time_ns()); - prom_text += "\n"; - return prom_text; + prometheus_text += "\n"; + return prometheus_text; } -std::string metrics_collector::convert_metric_to_prom_text(std::string_view metric_name, std::string_view prom_namespace, std::string_view prom_subsystem, std::map const_labels) +std::string metrics_collector::convert_metric_to_prometheus_text(std::string_view metric_name, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, std::map const_labels) { - // Create `prom_metric_name_fully_qualified` - std::string prom_metric_name_fully_qualified; - if (!prom_namespace.empty()) + // Create `prometheus_metric_name_fully_qualified` + std::string prometheus_metric_name_fully_qualified; + if (!prometheus_namespace.empty()) { - prom_metric_name_fully_qualified += std::string(prom_namespace) + "_"; + prometheus_metric_name_fully_qualified += std::string(prometheus_namespace) + "_"; } - if (!prom_subsystem.empty()) + if (!prometheus_subsystem.empty()) { - prom_metric_name_fully_qualified += std::string(prom_subsystem) + "_"; + prometheus_metric_name_fully_qualified += std::string(prometheus_subsystem) + "_"; } - prom_metric_name_fully_qualified += std::string(metric_name) + "_info"; + prometheus_metric_name_fully_qualified += std::string(metric_name) + "_info"; // Create the complete 3-lines text-based Prometheus exposition format https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md - std::string prom_text = "# HELP " + prom_metric_name_fully_qualified + " https://falco.org/docs/metrics/\n"; - prom_text += "# TYPE " + prom_metric_name_fully_qualified + " untyped\n"; - prom_text += prom_metric_name_fully_qualified; - prom_text += "{raw_name=\"" + std::string(metric_name) + "\"" ; + std::string prometheus_text = "# HELP " + prometheus_metric_name_fully_qualified + " https://falco.org/docs/metrics/\n"; + prometheus_text += "# TYPE " + prometheus_metric_name_fully_qualified + " gauge\n"; + prometheus_text += prometheus_metric_name_fully_qualified; + prometheus_text += "{raw_name=\"" + std::string(metric_name) + "\"" ; for (const auto& [key, value] : const_labels) { - prom_text += "," + key + "=\"" + value + "\"" ; + prometheus_text += "," + key + "=\"" + value + "\"" ; } - prom_text += "} 1 "; // white space at the end important! - prom_text += std::to_string(sinsp_utils::get_current_time_ns()); - prom_text += "\n"; - return prom_text; + prometheus_text += "} 1\n"; + return prometheus_text; } const std::vector& metrics_collector::get_metrics() const diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index 76d26b68a9..56aa30472e 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -99,7 +99,7 @@ class metrics_collector const std::vector& get_metrics() const; /*! - \brief Method to convert a metric to the text-based Prometheus exposition format. + \brief Method to convert a metrics_v2 metric to the text-based Prometheus exposition 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 @@ -116,35 +116,56 @@ class metrics_collector * The final fully qualified Prometheus metric name partially follows https://prometheus.io/docs/practices/naming/ * Prepend namespace and subsystem with "_" delimiter to create a fully qualified metric name according to * https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#Opts + append unit with "_" delimiter - * We do not follow the concept of base_units, but guarantee no units are mixed per unique `prom_metric_name_fully_qualified` + * We do not strictly follow and enforce the concept of base_units, but guarantee no units are mixed per unique + * `prometheus_metric_name_fully_qualified` + * + * We are monitoring updates wrt https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md * * Example: * * # HELP testns_falco_n_threads_total https://falco.org/docs/metrics/ * # TYPE testns_falco_n_threads_total gauge - * testns_falco_n_threads_total{raw_name="n_threads",example_key1="example1",example_key2="example2"} 12 1707281978248705000 + * testns_falco_n_threads_total{raw_name="n_threads",example_key1="example1",example_key2="example2"} 12 * # HELP testns_falco_memory_rss_megabytes https://falco.org/docs/metrics/ * # TYPE testns_falco_memory_rss_megabytes gauge - * testns_falco_memory_rss_megabytes{raw_name="memory_rss",example_key1="example1",example_key2="example2"} 350.000000 1707281978248635000 + * testns_falco_memory_rss_megabytes{raw_name="memory_rss",example_key1="example1",example_key2="example2"} 350.000000 * * This method is a work in progress. + * + * @param metric metrics_v2 metric + * @param prometheus_namespace first component of `prometheus_metric_name_fully_qualified` (optional) + * @param prometheus_subsystem second component of `prometheus_metric_name_fully_qualified` (optional) + * @param const_labels map of additional labels (rarely used for a metrics_v2 metric) + * @return Complete new line delimited text-based Prometheus exposition format metric string + * w/ a `prometheus_metric_name_fully_qualified` - optional components prepended to and unit appended to. + * 3-lines including # HELP and # TYPE lines followed by the metric line, raw metric name always present as label. */ - std::string convert_metric_to_prom_text(metrics_v2 metric, std::string_view prom_namespace = "", std::string_view prom_subsystem = "", std::map const_labels = {}); + std::string convert_metric_to_prometheus_text(metrics_v2 metric, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", std::map const_labels = {}); /*! - \brief Method to convert a software version like metric to the text-based Prometheus exposition format. + \brief Method to convert a software version like metric_name to the text-based Prometheus exposition format. * - * Note: Instead of using const_labels, which is a rare use case according to https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels, + * Note: Instead of using const_labels, which is a rare use case according to + * https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels, * exposing an overload to support metrics similar to https://www.robustperception.io/exposing-the-software-version-to-prometheus/. - * This approach is applicable to https://falco.org/docs/metrics/, such as Falco's "Base Fields" like falco.kernel_release and falco.version. + * This approach is applicable to https://falco.org/docs/metrics/, such as Falco's "Base Fields" like + * falco.kernel_release and falco.version. * * Example: * * # HELP testns_falco_kernel_release_info https://falco.org/docs/metrics/ - * # TYPE testns_falco_kernel_release_info untyped - * testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7-200.fc39.x86_64"} 1 1707286535681433000 + * # TYPE testns_falco_kernel_release_info gauge + * testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7-200.fc39.x86_64"} 1 + * + * @param metric_name raw metric name + * @param prometheus_namespace first component of `prometheus_metric_name_fully_qualified` (optional) + * @param prometheus_subsystem second component of `prometheus_metric_name_fully_qualified` (optional) + * @param const_labels map of additional labels (typically used in software version like metrics) + * @return Complete new line delimited text-based Prometheus exposition format metric string + * w/ a `prometheus_metric_name_fully_qualified` - optional components prepended to and unit appended to. + * 3-lines including # HELP and # TYPE lines followed by the metric line, raw metric name always present as label. */ - std::string convert_metric_to_prom_text(std::string_view metric_name, std::string_view prom_namespace = "", std::string_view prom_subsystem = "", std::map const_labels = {}); + std::string convert_metric_to_prometheus_text(std::string_view metric_name, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", std::map const_labels = {}); /*! \brief Method to convert memory units; tied to metrics_v2 definitions @@ -158,7 +179,7 @@ class metrics_collector case METRIC_VALUE_UNIT_MEMORY_BYTES: factor = 1; break; - case METRIC_VALUE_UNIT_MEMORY_KILOBYTES: + case METRIC_VALUE_UNIT_MEMORY_KIBIBYTES: factor = 1024.; break; case METRIC_VALUE_UNIT_MEMORY_MEGABYTES: @@ -173,7 +194,7 @@ class metrics_collector { case METRIC_VALUE_UNIT_MEMORY_BYTES: return bytes_val; - case METRIC_VALUE_UNIT_MEMORY_KILOBYTES: + case METRIC_VALUE_UNIT_MEMORY_KIBIBYTES: return std::round((bytes_val / 1024.) * 10.) / 10.; // round to 1 decimal case METRIC_VALUE_UNIT_MEMORY_MEGABYTES: return std::round((bytes_val / 1024. / 1024.) * 10.) / 10.; // round to 1 decimal diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index cea7977478..585ded7a60 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -141,12 +141,12 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) /* Test public convert_memory method */ double converted_memory = metrics_collector->convert_memory(METRIC_VALUE_UNIT_MEMORY_BYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, (uint64_t)52428800); ASSERT_EQ(converted_memory, 50); - converted_memory = metrics_collector->convert_memory(METRIC_VALUE_UNIT_MEMORY_KILOBYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, (uint64_t)51200); + converted_memory = metrics_collector->convert_memory(METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, (uint64_t)51200); ASSERT_EQ(converted_memory, 50); 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_prom_text */ + /* Test public convert_metric_to_prometheus_text */ for (const auto& metric: metrics_snapshot) { @@ -155,57 +155,62 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) // This resembles the Falco client use case // Falco output_rule metrics prepends either `falco.` or `scap.` to a single metric, see https://falco.org/docs/metrics/ - // Use same strings for `prom_subsystem`, but instead of `.` we use `_` delimiter to conform with Prometheus naming conventions + append the unit - std::string prometheus_text = metrics_collector->convert_metric_to_prom_text(metric, "testns", "falco", {{"example_key1", "example1"},{"example_key2", "example2"}}); + // Use same strings for `prometheus_subsystem`, but instead of `.` we use `_` delimiter to conform with Prometheus naming conventions + append the unit + std::string prometheus_text = metrics_collector->convert_metric_to_prometheus_text(metric, "testns", "falco", {{"example_key1", "example1"},{"example_key2", "example2"}}); std::string prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE testns_falco_n_missing_container_images_total gauge -testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1",example_key2="example2"} 0)"; +testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1",example_key2="example2"} 0 +)"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; ASSERT_GT(prometheus_text.length(), 8); // Test only one const_labels - prometheus_text = metrics_collector->convert_metric_to_prom_text(metric, "testns", "falco", {{"example_key1", "example1"}}); + prometheus_text = metrics_collector->convert_metric_to_prometheus_text(metric, "testns", "falco", {{"example_key1", "example1"}}); prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE testns_falco_n_missing_container_images_total gauge -testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1"} 0)"; +testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1"} 0 +)"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; ASSERT_GT(prometheus_text.length(), 8); // Test no const_labels - prometheus_text = metrics_collector->convert_metric_to_prom_text(metric, "testns", "falco"); + prometheus_text = metrics_collector->convert_metric_to_prometheus_text(metric, "testns", "falco"); prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE testns_falco_n_missing_container_images_total gauge -testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0)"; +testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 +)"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; ASSERT_GT(prometheus_text.length(), 8); - // Test no prom_subsytem - prometheus_text = metrics_collector->convert_metric_to_prom_text(metric, "testns"); + // Test no prometheus_subsytem + prometheus_text = metrics_collector->convert_metric_to_prometheus_text(metric, "testns"); prometheus_text_substring = R"(# HELP testns_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE testns_n_missing_container_images_total gauge -testns_n_missing_container_images_total{raw_name="n_missing_container_images"} 0)"; +testns_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 +)"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; ASSERT_GT(prometheus_text.length(), 8); - // Test no prom_namespace - prometheus_text = metrics_collector->convert_metric_to_prom_text(metric); + // Test no prometheus_namespace + prometheus_text = metrics_collector->convert_metric_to_prometheus_text(metric); prometheus_text_substring = R"(# HELP n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE n_missing_container_images_total gauge -n_missing_container_images_total{raw_name="n_missing_container_images"} 0)"; +n_missing_container_images_total{raw_name="n_missing_container_images"} 0 +)"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; ASSERT_GT(prometheus_text.length(), 8); - // Test no prom_namespace, but prom_subsytem - prometheus_text = metrics_collector->convert_metric_to_prom_text(metric, "", "falco"); + // Test no prometheus_namespace, but prometheus_subsytem + prometheus_text = metrics_collector->convert_metric_to_prometheus_text(metric, "", "falco"); prometheus_text_substring = R"(# HELP falco_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE falco_n_missing_container_images_total gauge -falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0)"; +falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 +)"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; ASSERT_GT(prometheus_text.length(), 8); - } } - std::string prometheus_text = metrics_collector->convert_metric_to_prom_text("kernel_release", "testns", "falco", {{"kernel_release", "6.6.7-200.fc39.x86_64"}}); + std::string prometheus_text = metrics_collector->convert_metric_to_prometheus_text("kernel_release", "testns", "falco", {{"kernel_release", "6.6.7-200.fc39.x86_64"}}); std::string prometheus_text_substring = R"(# HELP testns_falco_kernel_release_info https://falco.org/docs/metrics/ -# TYPE testns_falco_kernel_release_info untyped -testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7-200.fc39.x86_64"} 1)"; - printf("%s", prometheus_text.c_str()); +# TYPE testns_falco_kernel_release_info gauge +testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7-200.fc39.x86_64"} 1 +)"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; ASSERT_GT(prometheus_text.length(), 8); } From a5e9b507f0001746f6791365160fd9a015b26b43 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Sun, 11 Feb 2024 02:16:25 +0000 Subject: [PATCH 14/22] refactor!(libsinsp/metrics): new metrics_converter subclasses complementing metrics_collector Separation of concerns: new metrics_converter subclasses Rename the following metric names for consistency: cpu_usage_perc_total_host -> host_cpu_usage_perc memory_used_host -> host_memory_used_kb (or host_memory_used_mb if unit converted) procs_running_host -> host_procs_running open_fds_host -> host_open_fds memory_rss -> memory_rss_kb (or memory_rss_mb if unit converted) memory_pss -> memory_pss_kb (or memory_pss_mb if unit converted) memory_vsz -> memory_vsz_kb (or memory_vsz_mb if unit converted) container_memory_used -> container_memory_used_bytes (or container_memory_used_mb if unit converted) Signed-off-by: Melissa Kilby --- userspace/libscap/metrics_v2.h | 1 + userspace/libsinsp/metrics_collector.cpp | 563 +++++++++++++------ userspace/libsinsp/metrics_collector.h | 158 ++++-- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 243 ++++---- 4 files changed, 632 insertions(+), 333 deletions(-) diff --git a/userspace/libscap/metrics_v2.h b/userspace/libscap/metrics_v2.h index 7eacb966ad..a33666cff7 100644 --- a/userspace/libscap/metrics_v2.h +++ b/userspace/libscap/metrics_v2.h @@ -62,6 +62,7 @@ typedef enum metrics_v2_value_type{ typedef enum metrics_v2_value_unit{ METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_UNIT_PERC, + METRIC_VALUE_UNIT_RATIO, METRIC_VALUE_UNIT_MEMORY_BYTES, METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index e6e213ef60..38b6e930b1 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -23,17 +23,20 @@ limitations under the License. #include #include #include +#include + +static re2::RE2 s_libs_units_suffix("(_kb|_bytes|_perc|_ns)", re2::RE2::POSIX); static const char *const sinsp_stats_v2_resource_utilization_names[] = { [SINSP_RESOURCE_UTILIZATION_CPU_PERC] = "cpu_usage_perc", - [SINSP_RESOURCE_UTILIZATION_MEMORY_RSS] = "memory_rss", - [SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ] = "memory_vsz", - [SINSP_RESOURCE_UTILIZATION_MEMORY_PSS] = "memory_pss", - [SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY] = "container_memory_used", - [SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST] = "cpu_usage_perc_total_host", - [SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST] = "memory_used_host", - [SINSP_RESOURCE_UTILIZATION_PROCS_HOST] = "procs_running_host", - [SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST] = "open_fds_host", + [SINSP_RESOURCE_UTILIZATION_MEMORY_RSS] = "memory_rss_kb", + [SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ] = "memory_vsz_kb", + [SINSP_RESOURCE_UTILIZATION_MEMORY_PSS] = "memory_pss_kb", + [SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY] = "container_memory_used_bytes", + [SINSP_RESOURCE_UTILIZATION_HOST_CPU_PERC] = "host_cpu_usage_perc", + [SINSP_RESOURCE_UTILIZATION_HOST_MEMORY] = "host_memory_used_kb", + [SINSP_RESOURCE_UTILIZATION_HOST_PROCS] = "host_procs_running", + [SINSP_RESOURCE_UTILIZATION_HOST_FDS] = "host_open_fds", [SINSP_STATS_V2_N_THREADS] = "n_threads", [SINSP_STATS_V2_N_FDS] = "n_fds", [SINSP_STATS_V2_NONCACHED_FD_LOOKUPS] = "n_noncached_fd_lookups", @@ -60,6 +63,7 @@ static const char *const sinsp_stats_v2_resource_utilization_names[] = { static const char *const metrics_unit_name_mappings_prometheus[] = { [METRIC_VALUE_UNIT_COUNT] = "total", [METRIC_VALUE_UNIT_PERC] = "percentage", + [METRIC_VALUE_UNIT_RATIO] = "ratio", [METRIC_VALUE_UNIT_MEMORY_BYTES] = "bytes", [METRIC_VALUE_UNIT_MEMORY_KIBIBYTES] = "kibibytes", [METRIC_VALUE_UNIT_MEMORY_MEGABYTES] = "megabytes", @@ -74,9 +78,175 @@ static const char *const metrics_metric_type_name_mappings_prometheus[] = { [METRIC_VALUE_NON_MONOTONIC_CURRENT] = "gauge", }; -namespace libsinsp::metrics { +namespace libs::metrics { + +std::string metrics_converter::convert_metric_to_text(metrics_v2 metric) +{ + std::string metric_text = std::string(metric.name) + " "; + switch (metric.type) + { + case METRIC_VALUE_TYPE_U32: + metric_text += std::to_string(metric.value.u32); + break; + case METRIC_VALUE_TYPE_S32: + metric_text += std::to_string(metric.value.s32); + break; + case METRIC_VALUE_TYPE_U64: + metric_text += std::to_string(metric.value.u64); + break; + case METRIC_VALUE_TYPE_S64: + metric_text += std::to_string(metric.value.s64); + break; + case METRIC_VALUE_TYPE_D: + metric_text += std::to_string(metric.value.d); + break; + case METRIC_VALUE_TYPE_F: + metric_text += std::to_string(metric.value.f); + break; + case METRIC_VALUE_TYPE_I: + metric_text += std::to_string(metric.value.i); + break; + default: + break; + } + metric_text += "\n"; + return metric_text; +} + +void metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) +{ + return; +} + +void output_rule_metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) +{ + switch (metric.unit) + { + case METRIC_VALUE_UNIT_MEMORY_BYTES: + case METRIC_VALUE_UNIT_MEMORY_KIBIBYTES: + switch (metric.type) + { + case METRIC_VALUE_TYPE_U32: + { + metric.value.d = libs::metrics::convert_memory(metric.unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, metric.value.u32); + std::string metric_name_str(metric.name); + RE2::GlobalReplace(&metric_name_str, s_libs_units_suffix, "_mb"); + strlcpy(metric.name, metric_name_str.c_str(), METRIC_NAME_MAX); + metric.type = METRIC_VALUE_TYPE_D; + metric.unit = METRIC_VALUE_UNIT_MEMORY_MEGABYTES; + break; + } + case METRIC_VALUE_TYPE_U64: + { + metric.value.d = libs::metrics::convert_memory(metric.unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, metric.value.u64); + std::string metric_name_str(metric.name); + RE2::GlobalReplace(&metric_name_str, s_libs_units_suffix, "_mb"); + strlcpy(metric.name, metric_name_str.c_str(), METRIC_NAME_MAX); + metric.type = METRIC_VALUE_TYPE_D; + metric.unit = METRIC_VALUE_UNIT_MEMORY_MEGABYTES; + break; + } + default: + break; + } + break; + default: + break; + } +} + +std::string prometheus_metrics_converter::convert_metric_to_text(metrics_v2 metric, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, std::map const_labels) +{ + // Create `prometheus_metric_name_fully_qualified` + std::string prometheus_metric_name_fully_qualified; + if (!prometheus_namespace.empty()) + { + prometheus_metric_name_fully_qualified += std::string(prometheus_namespace) + "_"; + } + if (!prometheus_subsystem.empty()) + { + prometheus_metric_name_fully_qualified += std::string(prometheus_subsystem) + "_"; + } + prometheus_metric_name_fully_qualified += std::string(metric.name) + "_"; + // Remove native libs unit suffixes if applicable. + RE2::GlobalReplace(&prometheus_metric_name_fully_qualified, s_libs_units_suffix, ""); + prometheus_metric_name_fully_qualified += std::string(metrics_unit_name_mappings_prometheus[metric.unit]); + + // Create the complete 3-lines text-based Prometheus exposition format https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md + std::string prometheus_text = "# HELP " + prometheus_metric_name_fully_qualified + " https://falco.org/docs/metrics/\n"; + prometheus_text += "# TYPE " + prometheus_metric_name_fully_qualified + " " + std::string(metrics_metric_type_name_mappings_prometheus[metric.metric_type]) + "\n"; + prometheus_text += prometheus_metric_name_fully_qualified; + prometheus_text += "{raw_name=\"" + std::string(metric.name) + "\"" ; + for (const auto& [key, value] : const_labels) + { + prometheus_text += "," + key + "=\"" + value + "\"" ; + } + prometheus_text += "} "; // 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 += "\n"; + return prometheus_text; +} + +std::string prometheus_metrics_converter::convert_metric_to_text(std::string_view metric_name, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, std::map const_labels) +{ + // Create `prometheus_metric_name_fully_qualified` + std::string prometheus_metric_name_fully_qualified; + if (!prometheus_namespace.empty()) + { + prometheus_metric_name_fully_qualified += std::string(prometheus_namespace) + "_"; + } + if (!prometheus_subsystem.empty()) + { + prometheus_metric_name_fully_qualified += std::string(prometheus_subsystem) + "_"; + } + prometheus_metric_name_fully_qualified += std::string(metric_name) + "_info"; + + // Create the complete 3-lines text-based Prometheus exposition format https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md + std::string prometheus_text = "# HELP " + prometheus_metric_name_fully_qualified + " https://falco.org/docs/metrics/\n"; + prometheus_text += "# TYPE " + prometheus_metric_name_fully_qualified + " gauge\n"; + prometheus_text += prometheus_metric_name_fully_qualified; + prometheus_text += "{raw_name=\"" + std::string(metric_name) + "\"" ; + for (const auto& [key, value] : const_labels) + { + prometheus_text += "," + key + "=\"" + value + "\"" ; + } + prometheus_text += "} 1\n"; + return prometheus_text; +} -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) +void prometheus_metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) +{ + // todo + return; +} + +void libs_metrics_collector::get_rss_vsz_pss_total_memory_and_open_fds(uint32_t &rss, uint32_t &vsz, uint32_t &pss, uint64_t &host_memory_used, uint64_t &host_open_fds) { FILE* f; char filepath[512]; @@ -157,7 +327,7 @@ void metrics_collector::get_rss_vsz_pss_total_memory_and_open_fds(uint32_t &rss, } } fclose(f); - memory_used_host = mem_total - mem_free - mem_buff - mem_cache; + host_memory_used = mem_total - mem_free - mem_buff - mem_cache; /* * Get total number of allocated file descriptors (not all open files!) @@ -171,7 +341,7 @@ void metrics_collector::get_rss_vsz_pss_total_memory_and_open_fds(uint32_t &rss, ASSERT(false); return; } - int matched_fds = fscanf(f, "%" SCNu64, &open_fds_host); + int matched_fds = fscanf(f, "%" SCNu64, &host_open_fds); fclose(f); if (matched_fds != 1) { @@ -180,7 +350,7 @@ void metrics_collector::get_rss_vsz_pss_total_memory_and_open_fds(uint32_t &rss, } } -void metrics_collector::get_cpu_usage_and_total_procs(double start_time, double &cpu_usage_perc, double &cpu_usage_perc_total_host, uint32_t &procs_running_host) +void libs_metrics_collector::get_cpu_usage_and_total_procs(double start_time, double &cpu_usage_perc, double &host_cpu_usage_perc, uint32_t &host_procs_running) { FILE* f; char filepath[512]; @@ -265,7 +435,7 @@ void metrics_collector::get_cpu_usage_and_total_procs(double start_time, double } else if(strncmp(line, "procs_running ", 14) == 0) { - sscanf(line, "procs_running %" SCNu32, &procs_running_host); + sscanf(line, "procs_running %" SCNu32, &host_procs_running); break; } } @@ -273,12 +443,12 @@ void metrics_collector::get_cpu_usage_and_total_procs(double start_time, double auto sum = user + nice + system + idle + iowait + irq + softirq; if (sum > 0) { - cpu_usage_perc_total_host = 100.0 - ((idle * 100.0) / sum); - cpu_usage_perc_total_host = std::round(cpu_usage_perc_total_host * 10.0) / 10.0; // round to 1 decimal + host_cpu_usage_perc = 100.0 - ((idle * 100.0) / sum); + host_cpu_usage_perc = std::round(host_cpu_usage_perc * 10.0) / 10.0; // round to 1 decimal } } -uint64_t metrics_collector::get_container_memory_usage() const +uint64_t libs_metrics_collector::get_container_memory_used() const { /* In Kubernetes `container_memory_working_set_bytes` is the memory measure the OOM killer uses * and values from `/sys/fs/cgroup/memory/memory.usage_in_bytes` are close enough. @@ -310,7 +480,7 @@ uint64_t metrics_collector::get_container_memory_usage() const return memory_used; } -void metrics_collector::snapshot() +void libs_metrics_collector::snapshot() { m_metrics.clear(); if (!m_inspector) @@ -343,46 +513,77 @@ void metrics_collector::snapshot() if((m_metrics_flags & METRICS_V2_RESOURCE_UTILIZATION)) { const scap_agent_info* agent_info = m_inspector->get_agent_info(); - uint32_t rss{0}, vsz{0}, pss{0}, procs_running_host{0}; - uint64_t memory_used_host{0}, open_fds_host{0}; - double cpu_usage_perc{0.0}, cpu_usage_perc_total_host{0.0}; - uint64_t container_memory_usage = get_container_memory_usage(); - metrics_v2_value_unit rss_unit{METRIC_VALUE_UNIT_MEMORY_KIBIBYTES}, vsz_unit{METRIC_VALUE_UNIT_MEMORY_KIBIBYTES}, - pss_unit{METRIC_VALUE_UNIT_MEMORY_KIBIBYTES}, memory_used_host_unit{METRIC_VALUE_UNIT_MEMORY_KIBIBYTES}, container_memory_usage_unit{METRIC_VALUE_UNIT_MEMORY_BYTES}; - metrics_v2_value_type rss_type{METRIC_VALUE_TYPE_U32}, vsz_type{METRIC_VALUE_TYPE_U32}, - pss_type{METRIC_VALUE_TYPE_U32}, memory_used_host_type{METRIC_VALUE_TYPE_U32}, container_memory_usage_type{METRIC_VALUE_TYPE_U64}; - get_cpu_usage_and_total_procs(agent_info->start_time, cpu_usage_perc, cpu_usage_perc_total_host, procs_running_host); - get_rss_vsz_pss_total_memory_and_open_fds(rss, vsz, pss, memory_used_host, open_fds_host); - if(m_convert_memory_to_mb) - { - rss = convert_memory(rss_unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, rss); - vsz = convert_memory(vsz_unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, vsz); - pss = convert_memory(pss_unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, pss); - memory_used_host = convert_memory(memory_used_host_unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, memory_used_host); - container_memory_usage = convert_memory(container_memory_usage_unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, container_memory_usage); - rss_unit = vsz_unit = pss_unit = memory_used_host_unit = container_memory_usage_unit = METRIC_VALUE_UNIT_MEMORY_MEGABYTES; - rss_type = vsz_type = pss_type = memory_used_host_type = container_memory_usage_type = METRIC_VALUE_TYPE_D; - } + uint32_t rss{0}, vsz{0}, pss{0}, host_procs_running{0}; + uint64_t host_memory_used{0}, host_open_fds{0}; + double cpu_usage_perc{0.0}, host_cpu_usage_perc{0.0}; + uint64_t container_memory_used = get_container_memory_used(); + get_cpu_usage_and_total_procs(agent_info->start_time, cpu_usage_perc, host_cpu_usage_perc, host_procs_running); + get_rss_vsz_pss_total_memory_and_open_fds(rss, vsz, pss, host_memory_used, host_open_fds); + // Resource utilization of the agent itself m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC], - METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_D, METRIC_VALUE_UNIT_PERC, METRIC_VALUE_NON_MONOTONIC_CURRENT, cpu_usage_perc)); + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_D, + METRIC_VALUE_UNIT_PERC, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + cpu_usage_perc)); + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_RSS], - METRICS_V2_RESOURCE_UTILIZATION, rss_type, rss_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, rss)); + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + rss)); + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ], - METRICS_V2_RESOURCE_UTILIZATION, vsz_type, vsz_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, vsz)); + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + vsz)); + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_PSS], - METRICS_V2_RESOURCE_UTILIZATION, pss_type, pss_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, pss)); + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + pss)); + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY], - METRICS_V2_RESOURCE_UTILIZATION, container_memory_usage_type, container_memory_usage_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, container_memory_usage)); + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_MEMORY_BYTES, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + container_memory_used)); + // Resource utilization / load indicators of the underlying host - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST], - METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_D, METRIC_VALUE_UNIT_PERC, METRIC_VALUE_NON_MONOTONIC_CURRENT, cpu_usage_perc_total_host)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_PROCS_HOST], - METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, procs_running_host)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST], - METRICS_V2_RESOURCE_UTILIZATION, memory_used_host_type, memory_used_host_unit, METRIC_VALUE_NON_MONOTONIC_CURRENT, memory_used_host)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST], - METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, open_fds_host)); + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_HOST_CPU_PERC], + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_D, + METRIC_VALUE_UNIT_PERC, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + host_cpu_usage_perc)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_HOST_PROCS], + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + host_procs_running)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_HOST_MEMORY], + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + host_memory_used)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_HOST_FDS], + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + host_open_fds)); } if((m_metrics_flags & METRICS_V2_STATE_COUNTERS)) @@ -417,143 +618,157 @@ void metrics_collector::snapshot() } } - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_THREADS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, n_threads)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_FDS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, n_fds)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_FD_LOOKUPS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_noncached_fd_lookups)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_FD_LOOKUPS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_cached_fd_lookups)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_FD_LOOKUPS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_failed_fd_lookups)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_FDS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_added_fds)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_FDS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_removed_fds)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORED_EVTS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_stored_evts)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORE_EVTS_DROPS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_store_evts_drops)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVED_EVTS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_retrieved_evts)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVE_EVTS_DROPS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_retrieve_evts_drops)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_THREAD_LOOKUPS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_noncached_thread_lookups)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_THREAD_LOOKUPS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_cached_thread_lookups)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_THREAD_LOOKUPS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_failed_thread_lookups)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_THREADS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_added_threads)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_THREADS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_removed_threads)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_DROPS_FULL_THREADTABLE], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, sinsp_stats_v2->m_n_drops_full_threadtable)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_MISSING_CONTAINER_IMAGES], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, sinsp_stats_v2->m_n_missing_container_images)); - m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_CONTAINERS], \ - METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_NON_MONOTONIC_CURRENT, sinsp_stats_v2->m_n_containers)); + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_THREADS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + n_threads)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_FDS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + n_fds)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_FD_LOOKUPS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_noncached_fd_lookups)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_FD_LOOKUPS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_cached_fd_lookups)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_FD_LOOKUPS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_failed_fd_lookups)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_FDS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_added_fds)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_FDS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_removed_fds)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORED_EVTS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_stored_evts)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORE_EVTS_DROPS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_store_evts_drops)); + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVED_EVTS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_retrieved_evts)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVE_EVTS_DROPS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_retrieve_evts_drops)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_THREAD_LOOKUPS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_noncached_thread_lookups)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_THREAD_LOOKUPS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_cached_thread_lookups)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_THREAD_LOOKUPS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_failed_thread_lookups)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_THREADS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_added_threads)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_THREADS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_removed_threads)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_DROPS_FULL_THREADTABLE], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + sinsp_stats_v2->m_n_drops_full_threadtable)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_MISSING_CONTAINER_IMAGES], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + sinsp_stats_v2->m_n_missing_container_images)); + + m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_CONTAINERS], + METRICS_V2_STATE_COUNTERS, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + sinsp_stats_v2->m_n_containers)); } } } -std::string metrics_collector::convert_metric_to_prometheus_text(metrics_v2 metric, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, std::map const_labels) +const std::vector& libs_metrics_collector::get_metrics() const { - // Create `prometheus_metric_name_fully_qualified` - std::string prometheus_metric_name_fully_qualified; - if (!prometheus_namespace.empty()) - { - prometheus_metric_name_fully_qualified += std::string(prometheus_namespace) + "_"; - } - if (!prometheus_subsystem.empty()) - { - prometheus_metric_name_fully_qualified += std::string(prometheus_subsystem) + "_"; - } - prometheus_metric_name_fully_qualified += std::string(metric.name) + "_"; - prometheus_metric_name_fully_qualified += std::string(metrics_unit_name_mappings_prometheus[metric.unit]); - - // Create the complete 3-lines text-based Prometheus exposition format https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md - std::string prometheus_text = "# HELP " + prometheus_metric_name_fully_qualified + " https://falco.org/docs/metrics/\n"; - prometheus_text += "# TYPE " + prometheus_metric_name_fully_qualified + " " + std::string(metrics_metric_type_name_mappings_prometheus[metric.metric_type]) + "\n"; - prometheus_text += prometheus_metric_name_fully_qualified; - prometheus_text += "{raw_name=\"" + std::string(metric.name) + "\"" ; - for (const auto& [key, value] : const_labels) - { - prometheus_text += "," + key + "=\"" + value + "\"" ; - } - prometheus_text += "} "; // 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 += "\n"; - return prometheus_text; -} - -std::string metrics_collector::convert_metric_to_prometheus_text(std::string_view metric_name, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, std::map const_labels) -{ - // Create `prometheus_metric_name_fully_qualified` - std::string prometheus_metric_name_fully_qualified; - if (!prometheus_namespace.empty()) - { - prometheus_metric_name_fully_qualified += std::string(prometheus_namespace) + "_"; - } - if (!prometheus_subsystem.empty()) - { - prometheus_metric_name_fully_qualified += std::string(prometheus_subsystem) + "_"; - } - prometheus_metric_name_fully_qualified += std::string(metric_name) + "_info"; - - // Create the complete 3-lines text-based Prometheus exposition format https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md - std::string prometheus_text = "# HELP " + prometheus_metric_name_fully_qualified + " https://falco.org/docs/metrics/\n"; - prometheus_text += "# TYPE " + prometheus_metric_name_fully_qualified + " gauge\n"; - prometheus_text += prometheus_metric_name_fully_qualified; - prometheus_text += "{raw_name=\"" + std::string(metric_name) + "\"" ; - for (const auto& [key, value] : const_labels) - { - prometheus_text += "," + key + "=\"" + value + "\"" ; - } - prometheus_text += "} 1\n"; - return prometheus_text; + return m_metrics; } -const std::vector& metrics_collector::get_metrics() const +std::vector& libs_metrics_collector::get_metrics() { return m_metrics; } -metrics_collector::metrics_collector(sinsp* inspector, uint32_t flags, bool convert_memory_to_mb) : +libs_metrics_collector::libs_metrics_collector(sinsp* inspector, uint32_t flags) : m_inspector(inspector), - m_metrics_flags(flags), - m_convert_memory_to_mb(convert_memory_to_mb) + m_metrics_flags(flags) { } -} // namespace libsinsp::metrics +} // namespace libs::metrics #endif diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index 56aa30472e..84068a06ff 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -53,10 +53,10 @@ enum sinsp_stats_v2_resource_utilization SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ, ///< Current VSZ (Virtual Memory Size), calculated based on /proc/self/status info, unit: kb. SINSP_RESOURCE_UTILIZATION_MEMORY_PSS, ///< Current PSS (Proportional Set Size), calculated based on /proc/self/smaps_rollup info, unit: kb. SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY, ///< Cgroup current memory used, default Kubernetes /sys/fs/cgroup/memory/memory.usage_in_bytes, unit: bytes. - SINSP_RESOURCE_UTILIZATION_CPU_PERC_TOTAL_HOST, ///< Current total host CPU usage (all CPUs), calculated based on ${HOST_ROOT}/proc/stat info, unit: percentage. - SINSP_RESOURCE_UTILIZATION_MEMORY_TOTAL_HOST, ///< Current total memory used out of available host memory, calculated based on ${HOST_ROOT}/proc/meminfo info, unit: kb. - SINSP_RESOURCE_UTILIZATION_PROCS_HOST, ///< Number of processes currently running on CPUs on the host, retrieved from ${HOST_ROOT}/proc/stat line `procs_running`, unit: count. - SINSP_RESOURCE_UTILIZATION_FDS_TOTAL_HOST, ///< Number of allocated fds on the host, retrieved from ${HOST_ROOT}/proc/sys/fs/file-nr, unit: count. + SINSP_RESOURCE_UTILIZATION_HOST_CPU_PERC, ///< Current total host CPU usage (all CPUs), calculated based on ${HOST_ROOT}/proc/stat info, unit: percentage. + SINSP_RESOURCE_UTILIZATION_HOST_MEMORY, ///< Current total memory used out of available host memory, calculated based on ${HOST_ROOT}/proc/meminfo info, unit: kb. + SINSP_RESOURCE_UTILIZATION_HOST_PROCS, ///< Number of processes currently running on CPUs on the host, retrieved from ${HOST_ROOT}/proc/stat line `procs_running`, unit: count. + SINSP_RESOURCE_UTILIZATION_HOST_FDS, ///< Number of allocated fds on the host, retrieved from ${HOST_ROOT}/proc/sys/fs/file-nr, unit: count. SINSP_STATS_V2_N_THREADS, ///< Total number of threads currently stored in the sinsp state thread table, unit: count. SINSP_STATS_V2_N_FDS, ///< Total number of fds currently stored across all threadtables associated with each active thread in the sinsp state thread table, unit: count. SINSP_STATS_V2_NONCACHED_FD_LOOKUPS, ///< fdtable state related counters, unit: count. @@ -81,22 +81,58 @@ enum sinsp_stats_v2_resource_utilization #ifdef __linux__ -namespace libsinsp::metrics { +namespace libs::metrics +{ + +template +static double convert_memory(metrics_v2_value_unit source_unit, metrics_v2_value_unit dest_unit, T val) +{ + double factor = 1; + switch(source_unit) + { + case METRIC_VALUE_UNIT_MEMORY_BYTES: + factor = 1; + break; + case METRIC_VALUE_UNIT_MEMORY_KIBIBYTES: + factor = 1024.; + break; + case METRIC_VALUE_UNIT_MEMORY_MEGABYTES: + factor = 1024. * 1024.; + break; + default: + return 0; + } + + double bytes_val = val * factor; + switch(dest_unit) + { + case METRIC_VALUE_UNIT_MEMORY_BYTES: + return bytes_val; + case METRIC_VALUE_UNIT_MEMORY_KIBIBYTES: + return std::round((bytes_val / 1024.) * 10.) / 10.; // round to 1 decimal + case METRIC_VALUE_UNIT_MEMORY_MEGABYTES: + return std::round((bytes_val / 1024. / 1024.) * 10.) / 10.; // round to 1 decimal + default: + return 0; + } + return 0; +} -class metrics_collector +class metrics_converter { public: - metrics_collector(sinsp* inspector, uint32_t flags, bool convert_memory_to_mb); + metrics_converter() = default; - /*! - \brief Method to fill up m_metrics_buffer with metrics; refreshes m_metrics with up-to-date metrics on each call - */ - void snapshot(); + virtual std::string convert_metric_to_text(metrics_v2 metric); - /*! - \brief Method to get a const reference to m_metrics vector - */ - const std::vector& get_metrics() const; + virtual void convert_metric_to_unit_convention(metrics_v2& metric) = 0; +}; + +// Subclass for Prometheus-specific metric conversion +class prometheus_metrics_converter : public metrics_converter +{ +public: + prometheus_metrics_converter() = default; /*! \brief Method to convert a metrics_v2 metric to the text-based Prometheus exposition format. @@ -140,7 +176,7 @@ class metrics_collector * w/ a `prometheus_metric_name_fully_qualified` - optional components prepended to and unit appended to. * 3-lines including # HELP and # TYPE lines followed by the metric line, raw metric name always present as label. */ - std::string convert_metric_to_prometheus_text(metrics_v2 metric, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", std::map const_labels = {}); + std::string convert_metric_to_text(metrics_v2 metric, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", std::map const_labels = {}); /*! \brief Method to convert a software version like metric_name to the text-based Prometheus exposition format. @@ -165,44 +201,53 @@ class metrics_collector * w/ a `prometheus_metric_name_fully_qualified` - optional components prepended to and unit appended to. * 3-lines including # HELP and # TYPE lines followed by the metric line, raw metric name always present as label. */ - std::string convert_metric_to_prometheus_text(std::string_view metric_name, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", std::map const_labels = {}); + std::string convert_metric_to_text(std::string_view metric_name, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", std::map const_labels = {}); /*! - \brief Method to convert memory units; tied to metrics_v2 definitions + \brief Method to convert metric units to Prometheus base units. todo, not yet implemented. + * + * \note metrics names w/ unit suffix shall be changed within this method, conforming to libs native metrics names, + * not Prometheus, `convert_metric_to_text` takes care of final metric name convertion to Prometheus text format. + * As a consequence `metric.unit` always matches the metric name unit suffix if applicable. */ - template - static double convert_memory(metrics_v2_value_unit source_unit, metrics_v2_value_unit dest_unit, T val) - { - double factor = 1; - switch(source_unit) - { - case METRIC_VALUE_UNIT_MEMORY_BYTES: - factor = 1; - break; - case METRIC_VALUE_UNIT_MEMORY_KIBIBYTES: - factor = 1024.; - break; - case METRIC_VALUE_UNIT_MEMORY_MEGABYTES: - factor = 1024. * 1024.; - break; - default: - return 0; - } + void convert_metric_to_unit_convention(metrics_v2& metric) override; +}; - double bytes_val = val * factor; - switch(dest_unit) - { - case METRIC_VALUE_UNIT_MEMORY_BYTES: - return bytes_val; - case METRIC_VALUE_UNIT_MEMORY_KIBIBYTES: - return std::round((bytes_val / 1024.) * 10.) / 10.; // round to 1 decimal - case METRIC_VALUE_UNIT_MEMORY_MEGABYTES: - return std::round((bytes_val / 1024. / 1024.) * 10.) / 10.; // round to 1 decimal - default: - return 0; - } - return 0; - } +// Subclass for output_rule-specific metric conversion +class output_rule_metrics_converter : public metrics_converter +{ +public: + output_rule_metrics_converter() = default; + + /*! + \brief Method to convert metric units of memory-related metrics to mb + * + * \note metrics names w/ unit suffix shall be changed within this method, conforming to libs native metrics names. + * As a consequence `metric.unit` always matches the metric name unit suffix if applicable. + * + */ + void convert_metric_to_unit_convention(metrics_v2& metric) override; +}; + +class libs_metrics_collector +{ +public: + libs_metrics_collector(sinsp* inspector, uint32_t flags); + + /*! + \brief Method to fill up m_metrics_buffer with metrics; refreshes m_metrics with up-to-date metrics on each call + */ + void snapshot(); + + /*! + \brief Method to get a const reference to m_metrics vector + */ + const std::vector& get_metrics() const; + + /*! + \brief Method to get a non-const reference to m_metrics vector + */ + std::vector& get_metrics(); /*! \brief Method to create a new metrics_v2 @@ -216,22 +261,21 @@ class metrics_collector metric.type = type; metric.unit = unit; metric.metric_type = metric_type; - set_new_metric(metric, type, val); + set_metric_value(metric, type, val); return metric; } private: sinsp* m_inspector; uint32_t m_metrics_flags = METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS; - bool m_convert_memory_to_mb = true; std::vector m_metrics; - void 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); - void get_cpu_usage_and_total_procs(double start_time, double &cpu_usage_perc, double &cpu_usage_perc_total_host, uint32_t &procs_running_host); - uint64_t get_container_memory_usage() const; + void get_rss_vsz_pss_total_memory_and_open_fds(uint32_t &rss, uint32_t &vsz, uint32_t &pss, uint64_t &host_memory_used, uint64_t &host_open_fds); + void get_cpu_usage_and_total_procs(double start_time, double &cpu_usage_perc, double &host_cpu_usage_perc, uint32_t &host_procs_running); + uint64_t get_container_memory_used() const; template - static void set_new_metric(metrics_v2& metric, metrics_v2_value_type type, T val) + static void set_metric_value(metrics_v2& metric, metrics_v2_value_type type, T val) { switch (type) { @@ -262,6 +306,6 @@ class metrics_collector } }; -} // namespace libsinsp::metrics +} // namespace libs::metrics #endif diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index 585ded7a60..2ccbd7707f 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -21,7 +21,7 @@ limitations under the License. #include "sinsp_with_test_input.h" #include -TEST_F(sinsp_with_test_input, sinsp_metrics_collector) +TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_prometheus) { m_inspector.set_sinsp_stats_v2_enabled(); // Extra call to verify that we don't fail @@ -32,18 +32,119 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) /* Snapshot current metrics and get the updated metrics_snapshot buffer */ uint32_t test_metrics_flags = (METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); - bool convert_memory_to_mb = true; - auto metrics_collector = std::make_unique(&m_inspector, test_metrics_flags, convert_memory_to_mb); - metrics_collector->snapshot(); - auto metrics_snapshot = metrics_collector->get_metrics(); + auto libs_metrics_collector = std::make_unique(&m_inspector, test_metrics_flags); + auto prometheus_metrics_converter = std::make_unique(); + + libs_metrics_collector->snapshot(); + auto metrics_snapshot = libs_metrics_collector->get_metrics(); + ASSERT_EQ(metrics_snapshot.size(), 28); + + /* Test prometheus_metrics_converter->convert_metric_to_text */ + std::string prometheus_text; + std::string prometheus_text_substring; + for (const auto& metric: metrics_snapshot) + { + if (strncmp(metric.name, "n_missing_container_images", 17) == 0) + { + // This resembles the Falco client use case + + // Falco output_rule metrics prepends either `falco.` or `scap.` to a single metric, see https://falco.org/docs/metrics/ + // Use same strings for `prometheus_subsystem`, but instead of `.` we use `_` delimiter to conform with Prometheus naming conventions + append the unit + prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco", {{"example_key1", "example1"},{"example_key2", "example2"}}); + prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ +# TYPE testns_falco_n_missing_container_images_total gauge +testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1",example_key2="example2"} 0 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); + // Test only one const_labels + prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco", {{"example_key1", "example1"}}); + prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ +# TYPE testns_falco_n_missing_container_images_total gauge +testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1"} 0 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); + // Test no const_labels + prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco"); + prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ +# TYPE testns_falco_n_missing_container_images_total gauge +testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); + // Test no prometheus_subsytem + prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns"); + prometheus_text_substring = R"(# HELP testns_n_missing_container_images_total https://falco.org/docs/metrics/ +# TYPE testns_n_missing_container_images_total gauge +testns_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); + // Test no prometheus_namespace + prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric); + prometheus_text_substring = R"(# HELP n_missing_container_images_total https://falco.org/docs/metrics/ +# TYPE n_missing_container_images_total gauge +n_missing_container_images_total{raw_name="n_missing_container_images"} 0 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); + // Test no prometheus_namespace, but prometheus_subsytem + prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "", "falco"); + prometheus_text_substring = R"(# HELP falco_n_missing_container_images_total https://falco.org/docs/metrics/ +# TYPE falco_n_missing_container_images_total gauge +falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); + } else if (strncmp(metric.name, "memory_rss_kb", 16) == 0) + { + // Test that libs native metric unit suffix was removed and replaced by the Prometheus specific unit suffix naming convention + // todo adjust once base units are implemented + prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco"); + printf("%s", prometheus_text.c_str()); + prometheus_text_substring = R"(# HELP testns_falco_memory_rss_kibibytes https://falco.org/docs/metrics/ +# TYPE testns_falco_memory_rss_kibibytes gauge +testns_falco_memory_rss_kibibytes{raw_name="memory_rss_kb"} )"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); + } + } + + // Test global wrapper base metrics + prometheus_text = prometheus_metrics_converter->convert_metric_to_text("kernel_release", "testns", "falco", {{"kernel_release", "6.6.7-200.fc39.x86_64"}}); + prometheus_text_substring = R"(# HELP testns_falco_kernel_release_info https://falco.org/docs/metrics/ +# TYPE testns_falco_kernel_release_info gauge +testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7-200.fc39.x86_64"} 1 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_GT(prometheus_text.length(), 8); +} + +TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_output_rule) +{ + m_inspector.set_sinsp_stats_v2_enabled(); + // Extra call to verify that we don't fail + m_inspector.set_sinsp_stats_v2_enabled(); + DEFAULT_TREE + auto evt = generate_random_event(p2_t1_tid); + ASSERT_EQ(get_field_as_string(evt, "proc.nthreads"), "3"); + + /* Snapshot current metrics and get the updated metrics_snapshot buffer */ + uint32_t test_metrics_flags = (METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); + auto libs_metrics_collector = std::make_unique(&m_inspector, test_metrics_flags); + auto output_rule_metrics_converter = std::make_unique(); + /* Multiple calls */ - metrics_collector->snapshot(); - metrics_collector->snapshot(); - metrics_snapshot = metrics_collector->get_metrics(); + libs_metrics_collector->snapshot(); + auto metrics_snapshot = libs_metrics_collector->get_metrics(); + libs_metrics_collector->snapshot(); + libs_metrics_collector->snapshot(); + metrics_snapshot = libs_metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 28); /* These names should always be available, note that we currently can't check for the merged scap stats metrics here */ - std::unordered_set minimal_metrics_names = {"cpu_usage_perc", "memory_rss", "open_fds_host", \ + std::unordered_set minimal_metrics_names = {"cpu_usage_perc", "memory_rss_kb", "host_open_fds", \ "n_threads", "n_fds", "n_added_fds", "n_added_threads", "n_removed_threads", "n_containers"}; for(const auto& metric_name : minimal_metrics_names) @@ -64,17 +165,19 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) } /* Assert successful memory unit changes and sanity check some values to be greater than 0 */ - const std::vector metrics_names_memory = {"memory_rss", "memory_vsz", "memory_pss", "container_memory_used", "memory_used_host"}; + const std::vector metrics_names_memory = {"memory_rss_mb", "memory_vsz_mb", "memory_pss_mb", "container_memory_used_mb", "host_memory_used_mb"}; const std::vector metrics_names_values_gt = {"n_threads", "n_fds", "n_added_threads"}; uint32_t success_memory_cnt = 0; uint32_t success_values_cnt = 0; - for (const auto& metric: metrics_snapshot) + for (auto& metric: metrics_snapshot) { + // This resembles the Falco client use case and would be called if `convert_memory_to_mb` is set to true + output_rule_metrics_converter->convert_metric_to_unit_convention(metric); if (std::find(metrics_names_memory.begin(), metrics_names_memory.end(), metric.name) != metrics_names_memory.end()) { ASSERT_EQ(metric.unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES); ASSERT_EQ(metric.type, METRIC_VALUE_TYPE_D); - if (strncmp(metric.name, "memory_used_host", 17) == 0 || strncmp(metric.name, "memory_rss", 11) == 0 ) + if (strncmp(metric.name, "host_memory_used_mb", 20) == 0 || strncmp(metric.name, "memory_rss_mb", 14) == 0 ) { ASSERT_GT(metric.value.d, 0); // Just making sure we don't get a high value due to an unitialized variables @@ -97,121 +200,57 @@ TEST_F(sinsp_with_test_input, sinsp_metrics_collector) ASSERT_EQ(success_values_cnt, metrics_names_values_gt.size()); /* Empty call */ - metrics_collector = std::make_unique(&m_inspector, 0, convert_memory_to_mb); - metrics_collector->snapshot(); - metrics_snapshot = metrics_collector->get_metrics(); + libs_metrics_collector = std::make_unique(&m_inspector, 0); + libs_metrics_collector->snapshot(); + metrics_snapshot = libs_metrics_collector->get_metrics(); ASSERT_TRUE(metrics_snapshot.empty()); /* Sanity check empty inspector */ test_metrics_flags = (METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); - metrics_collector = std::make_unique(nullptr, test_metrics_flags, convert_memory_to_mb); - metrics_collector->snapshot(); - metrics_snapshot = metrics_collector->get_metrics(); + libs_metrics_collector = std::make_unique(nullptr, test_metrics_flags); + libs_metrics_collector->snapshot(); + metrics_snapshot = libs_metrics_collector->get_metrics(); ASSERT_TRUE(metrics_snapshot.empty()); /* Some sanity checks for selective flags */ test_metrics_flags = 0; test_metrics_flags |= METRICS_V2_KERNEL_COUNTERS; // 20, but can't test it here it's 0 test_metrics_flags |= METRICS_V2_LIBBPF_STATS; // 21 (x86_64 machine), but can't test it here it's 0 - metrics_collector = std::make_unique(&m_inspector, test_metrics_flags, convert_memory_to_mb); - metrics_collector->snapshot(); - metrics_snapshot = metrics_collector->get_metrics(); + libs_metrics_collector = std::make_unique(&m_inspector, test_metrics_flags); + libs_metrics_collector->snapshot(); + metrics_snapshot = libs_metrics_collector->get_metrics(); ASSERT_TRUE(metrics_snapshot.empty()); test_metrics_flags = 0; test_metrics_flags |= METRICS_V2_RESOURCE_UTILIZATION; - metrics_collector = std::make_unique(&m_inspector, test_metrics_flags, convert_memory_to_mb); - metrics_collector->snapshot(); - metrics_snapshot = metrics_collector->get_metrics(); + libs_metrics_collector = std::make_unique(&m_inspector, test_metrics_flags); + libs_metrics_collector->snapshot(); + metrics_snapshot = libs_metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 9); test_metrics_flags = 0; test_metrics_flags |= METRICS_V2_STATE_COUNTERS; - metrics_collector = std::make_unique(&m_inspector, test_metrics_flags, convert_memory_to_mb); - metrics_collector->snapshot(); - metrics_snapshot = metrics_collector->get_metrics(); + libs_metrics_collector = std::make_unique(&m_inspector, test_metrics_flags); + libs_metrics_collector->snapshot(); + metrics_snapshot = libs_metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 19); test_metrics_flags = (METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); - metrics_collector = std::make_unique(&m_inspector, test_metrics_flags, convert_memory_to_mb); - metrics_collector->snapshot(); - metrics_snapshot = metrics_collector->get_metrics(); + libs_metrics_collector = std::make_unique(&m_inspector, test_metrics_flags); + libs_metrics_collector->snapshot(); + metrics_snapshot = libs_metrics_collector->get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 28); +} - /* Test public convert_memory method */ - double converted_memory = metrics_collector->convert_memory(METRIC_VALUE_UNIT_MEMORY_BYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, (uint64_t)52428800); +TEST(sinsp_libs_metrics, sinsp_libs_metrics_convert_units) +{ + /* Test public libs::metrics::convert_memory method */ + double converted_memory = libs::metrics::convert_memory(METRIC_VALUE_UNIT_MEMORY_BYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, (uint64_t)52428800); ASSERT_EQ(converted_memory, 50); - converted_memory = metrics_collector->convert_memory(METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, (uint64_t)51200); + converted_memory = libs::metrics::convert_memory(METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, (uint64_t)51200); ASSERT_EQ(converted_memory, 50); - converted_memory = metrics_collector->convert_memory(METRIC_VALUE_UNIT_MEMORY_MEGABYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, (uint64_t)50); + converted_memory = libs::metrics::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) - { - if (strncmp(metric.name, "n_missing_container_images", 17) == 0) - { - // This resembles the Falco client use case - - // Falco output_rule metrics prepends either `falco.` or `scap.` to a single metric, see https://falco.org/docs/metrics/ - // Use same strings for `prometheus_subsystem`, but instead of `.` we use `_` delimiter to conform with Prometheus naming conventions + append the unit - std::string prometheus_text = metrics_collector->convert_metric_to_prometheus_text(metric, "testns", "falco", {{"example_key1", "example1"},{"example_key2", "example2"}}); - std::string prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ -# TYPE testns_falco_n_missing_container_images_total gauge -testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1",example_key2="example2"} 0 -)"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); - // Test only one const_labels - prometheus_text = metrics_collector->convert_metric_to_prometheus_text(metric, "testns", "falco", {{"example_key1", "example1"}}); - prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ -# TYPE testns_falco_n_missing_container_images_total gauge -testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1"} 0 -)"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); - // Test no const_labels - prometheus_text = metrics_collector->convert_metric_to_prometheus_text(metric, "testns", "falco"); - prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ -# TYPE testns_falco_n_missing_container_images_total gauge -testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 -)"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); - // Test no prometheus_subsytem - prometheus_text = metrics_collector->convert_metric_to_prometheus_text(metric, "testns"); - prometheus_text_substring = R"(# HELP testns_n_missing_container_images_total https://falco.org/docs/metrics/ -# TYPE testns_n_missing_container_images_total gauge -testns_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 -)"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); - // Test no prometheus_namespace - prometheus_text = metrics_collector->convert_metric_to_prometheus_text(metric); - prometheus_text_substring = R"(# HELP n_missing_container_images_total https://falco.org/docs/metrics/ -# TYPE n_missing_container_images_total gauge -n_missing_container_images_total{raw_name="n_missing_container_images"} 0 -)"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); - // Test no prometheus_namespace, but prometheus_subsytem - prometheus_text = metrics_collector->convert_metric_to_prometheus_text(metric, "", "falco"); - prometheus_text_substring = R"(# HELP falco_n_missing_container_images_total https://falco.org/docs/metrics/ -# TYPE falco_n_missing_container_images_total gauge -falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 -)"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); - } - } - - std::string prometheus_text = metrics_collector->convert_metric_to_prometheus_text("kernel_release", "testns", "falco", {{"kernel_release", "6.6.7-200.fc39.x86_64"}}); - std::string prometheus_text_substring = R"(# HELP testns_falco_kernel_release_info https://falco.org/docs/metrics/ -# TYPE testns_falco_kernel_release_info gauge -testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7-200.fc39.x86_64"} 1 -)"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); } + #endif From bcb3368ad1e5b49944f94dc049e95c18b3302cb3 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Thu, 22 Feb 2024 20:33:31 +0000 Subject: [PATCH 15/22] cleanup(libsinsp/metrics_collector): const correction Co-authored-by: Samuel Gaist Signed-off-by: Melissa Kilby --- userspace/libsinsp/metrics_collector.cpp | 12 ++++++------ userspace/libsinsp/metrics_collector.h | 13 ++++++------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index 38b6e930b1..24671c27c7 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -80,7 +80,7 @@ static const char *const metrics_metric_type_name_mappings_prometheus[] = { namespace libs::metrics { -std::string metrics_converter::convert_metric_to_text(metrics_v2 metric) +std::string metrics_converter::convert_metric_to_text(metrics_v2 metric) const { std::string metric_text = std::string(metric.name) + " "; switch (metric.type) @@ -113,12 +113,12 @@ std::string metrics_converter::convert_metric_to_text(metrics_v2 metric) return metric_text; } -void metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) +void metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) const { return; } -void output_rule_metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) +void output_rule_metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) const { switch (metric.unit) { @@ -155,7 +155,7 @@ void output_rule_metrics_converter::convert_metric_to_unit_convention(metrics_v2 } } -std::string prometheus_metrics_converter::convert_metric_to_text(metrics_v2 metric, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, std::map const_labels) +std::string prometheus_metrics_converter::convert_metric_to_text(metrics_v2 metric, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, const std::map& const_labels) const { // Create `prometheus_metric_name_fully_qualified` std::string prometheus_metric_name_fully_qualified; @@ -213,7 +213,7 @@ std::string prometheus_metrics_converter::convert_metric_to_text(metrics_v2 metr return prometheus_text; } -std::string prometheus_metrics_converter::convert_metric_to_text(std::string_view metric_name, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, std::map const_labels) +std::string prometheus_metrics_converter::convert_metric_to_text(std::string_view metric_name, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, const std::map& const_labels) const { // Create `prometheus_metric_name_fully_qualified` std::string prometheus_metric_name_fully_qualified; @@ -240,7 +240,7 @@ std::string prometheus_metrics_converter::convert_metric_to_text(std::string_vie return prometheus_text; } -void prometheus_metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) +void prometheus_metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) const { // todo return; diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index 84068a06ff..2e65bd6bcf 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -115,7 +115,6 @@ static double convert_memory(metrics_v2_value_unit source_unit, metrics_v2_value default: return 0; } - return 0; } class metrics_converter @@ -123,9 +122,9 @@ class metrics_converter public: metrics_converter() = default; - virtual std::string convert_metric_to_text(metrics_v2 metric); + virtual std::string convert_metric_to_text(metrics_v2 metric) const; - virtual void convert_metric_to_unit_convention(metrics_v2& metric) = 0; + virtual void convert_metric_to_unit_convention(metrics_v2& metric) const = 0; }; // Subclass for Prometheus-specific metric conversion @@ -176,7 +175,7 @@ class prometheus_metrics_converter : public metrics_converter * w/ a `prometheus_metric_name_fully_qualified` - optional components prepended to and unit appended to. * 3-lines including # HELP and # TYPE lines followed by the metric line, raw metric name always present as label. */ - std::string convert_metric_to_text(metrics_v2 metric, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", std::map const_labels = {}); + std::string convert_metric_to_text(metrics_v2 metric, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", const std::map& const_labels = {}) const; /*! \brief Method to convert a software version like metric_name to the text-based Prometheus exposition format. @@ -201,7 +200,7 @@ class prometheus_metrics_converter : public metrics_converter * w/ a `prometheus_metric_name_fully_qualified` - optional components prepended to and unit appended to. * 3-lines including # HELP and # TYPE lines followed by the metric line, raw metric name always present as label. */ - std::string convert_metric_to_text(std::string_view metric_name, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", std::map const_labels = {}); + std::string convert_metric_to_text(std::string_view metric_name, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", const std::map& const_labels = {}) const; /*! \brief Method to convert metric units to Prometheus base units. todo, not yet implemented. @@ -210,7 +209,7 @@ class prometheus_metrics_converter : public metrics_converter * not Prometheus, `convert_metric_to_text` takes care of final metric name convertion to Prometheus text format. * As a consequence `metric.unit` always matches the metric name unit suffix if applicable. */ - void convert_metric_to_unit_convention(metrics_v2& metric) override; + void convert_metric_to_unit_convention(metrics_v2& metric) const override; }; // Subclass for output_rule-specific metric conversion @@ -226,7 +225,7 @@ class output_rule_metrics_converter : public metrics_converter * As a consequence `metric.unit` always matches the metric name unit suffix if applicable. * */ - void convert_metric_to_unit_convention(metrics_v2& metric) override; + void convert_metric_to_unit_convention(metrics_v2& metric) const override; }; class libs_metrics_collector From a2b4e1c48040bb11b1c3c30ca08ced453007030e Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Thu, 22 Feb 2024 20:55:05 +0000 Subject: [PATCH 16/22] chore: adopt new get thread_manager style in metrics Signed-off-by: Melissa Kilby --- userspace/libsinsp/metrics_collector.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index 24671c27c7..f11e1e919f 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -600,10 +600,11 @@ void libs_metrics_collector::snapshot() { uint64_t n_fds = 0; uint64_t n_threads = 0; - if (m_inspector->m_thread_manager) + auto thread_manager = m_inspector->m_thread_manager.get(); + if (thread_manager) { - n_threads = m_inspector->m_thread_manager->get_thread_count(); - threadinfo_map_t* threadtable = m_inspector->m_thread_manager->get_threads(); + n_threads = thread_manager->get_thread_count(); + threadinfo_map_t* threadtable = thread_manager->get_threads(); if (threadtable) { threadtable->loop([&n_fds] (sinsp_threadinfo& tinfo) From b5a4831ab4af4a99bac36f740c4ff179ddaed2a6 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Thu, 7 Mar 2024 00:27:54 +0000 Subject: [PATCH 17/22] new(libsinsp/metrics): implement Prometheus convert_metric_to_unit_convention Honor Prometheus standards (https://prometheus.io/docs/practices/naming/ or https://prometheus.io/docs/practices/naming/#base-units), except keep libbpf stats metrics and timestamps in nanoseconds to avoid precision loss when converting them to seconds. Note that the standards are recommendations and not requirements, and not even cAdvisor always adheres to them. The Prometheus community acknowledges that the standards do not always fit the use case at hand. Signed-off-by: Melissa Kilby --- userspace/libpman/src/stats.c | 4 +- userspace/libscap/engine/bpf/scap_bpf.c | 4 +- userspace/libscap/metrics_v2.h | 10 +- userspace/libsinsp/metrics_collector.cpp | 73 ++++++--- userspace/libsinsp/metrics_collector.h | 23 ++- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 156 +++++++++++++++++-- 6 files changed, 215 insertions(+), 55 deletions(-) diff --git a/userspace/libpman/src/stats.c b/userspace/libpman/src/stats.c index 1289c0dbd1..5f5b150322 100644 --- a/userspace/libpman/src/stats.c +++ b/userspace/libpman/src/stats.c @@ -263,13 +263,13 @@ struct metrics_v2 *pman_get_metrics_v2(uint32_t flags, uint32_t *nstats, int32_t break; case RUN_TIME_NS: strlcat(g_state.stats[offset].name, modern_bpf_libbpf_stats_names[RUN_TIME_NS], sizeof(g_state.stats[offset].name)); - g_state.stats[stat].unit = METRIC_VALUE_UNIT_DURATION_NS; + g_state.stats[stat].unit = METRIC_VALUE_UNIT_TIME_NS_COUNT; g_state.stats[stat].metric_type = METRIC_VALUE_MONOTONIC; g_state.stats[offset].value.u64 = info.run_time_ns; break; case AVG_TIME_NS: strlcat(g_state.stats[offset].name, modern_bpf_libbpf_stats_names[AVG_TIME_NS], sizeof(g_state.stats[offset].name)); - g_state.stats[stat].unit = METRIC_VALUE_UNIT_DURATION_NS; + g_state.stats[stat].unit = METRIC_VALUE_UNIT_TIME_NS; g_state.stats[stat].metric_type = METRIC_VALUE_NON_MONOTONIC_CURRENT; g_state.stats[offset].value.u64 = 0; if(info.run_cnt > 0) diff --git a/userspace/libscap/engine/bpf/scap_bpf.c b/userspace/libscap/engine/bpf/scap_bpf.c index 0b0dde0763..8995205cc3 100644 --- a/userspace/libscap/engine/bpf/scap_bpf.c +++ b/userspace/libscap/engine/bpf/scap_bpf.c @@ -1833,13 +1833,13 @@ const struct metrics_v2* scap_bpf_get_stats_v2(struct scap_engine_handle engine, case RUN_TIME_NS: strlcat(stats[offset].name, bpf_libbpf_stats_names[RUN_TIME_NS], sizeof(stats[offset].name)); stats[offset].value.u64 = info.run_time_ns; - stats[offset].unit = METRIC_VALUE_UNIT_DURATION_NS; + stats[offset].unit = METRIC_VALUE_UNIT_TIME_NS_COUNT; stats[offset].metric_type = METRIC_VALUE_MONOTONIC; break; case AVG_TIME_NS: strlcat(stats[offset].name, bpf_libbpf_stats_names[AVG_TIME_NS], sizeof(stats[offset].name)); stats[offset].value.u64 = 0; - stats[offset].unit = METRIC_VALUE_UNIT_DURATION_NS; + stats[offset].unit = METRIC_VALUE_UNIT_TIME_NS; stats[offset].metric_type = METRIC_VALUE_NON_MONOTONIC_CURRENT; if (info.run_cnt > 0) { diff --git a/userspace/libscap/metrics_v2.h b/userspace/libscap/metrics_v2.h index a33666cff7..4d200d940d 100644 --- a/userspace/libscap/metrics_v2.h +++ b/userspace/libscap/metrics_v2.h @@ -38,6 +38,7 @@ extern "C" { #define METRICS_V2_RESOURCE_UTILIZATION (1 << 2) #define METRICS_V2_STATE_COUNTERS (1 << 3) #define METRICS_V2_RULE_COUNTERS (1 << 4) +#define METRICS_V2_MISC (1 << 5) typedef union metrics_v2_value { uint32_t u32; @@ -61,13 +62,16 @@ typedef enum metrics_v2_value_type{ typedef enum metrics_v2_value_unit{ METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_UNIT_PERC, METRIC_VALUE_UNIT_RATIO, + METRIC_VALUE_UNIT_PERC, METRIC_VALUE_UNIT_MEMORY_BYTES, METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, - METRIC_VALUE_UNIT_DURATION_NS, - METRIC_VALUE_UNIT_DURATION_S, + METRIC_VALUE_UNIT_TIME_NS, + METRIC_VALUE_UNIT_TIME_S, + METRIC_VALUE_UNIT_TIME_NS_COUNT, + METRIC_VALUE_UNIT_TIME_S_COUNT, + METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS, }metrics_v2_value_unit; typedef enum metrics_v2_metric_type{ diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index f11e1e919f..d60652bcb4 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -25,7 +25,10 @@ limitations under the License. #include #include -static re2::RE2 s_libs_units_suffix("(_kb|_bytes|_perc|_ns)", re2::RE2::POSIX); +static re2::RE2 s_libs_metrics_units_suffix_pre_prometheus_text_conversion("(_kb|_bytes|_mb|_perc|_percentage|_ratio|_ns|_ts|_sec|_total)", re2::RE2::POSIX); +static re2::RE2 s_libs_metrics_units_memory_suffix("(_kb|_bytes)", re2::RE2::POSIX); +static re2::RE2 s_libs_metrics_units_perc_suffix("(_perc)", re2::RE2::POSIX); +static re2::RE2 s_libs_metrics_banned_prometheus_naming_characters("(\\.)", re2::RE2::POSIX); static const char *const sinsp_stats_v2_resource_utilization_names[] = { [SINSP_RESOURCE_UTILIZATION_CPU_PERC] = "cpu_usage_perc", @@ -59,16 +62,19 @@ static const char *const sinsp_stats_v2_resource_utilization_names[] = { }; // For simplicity, needs to stay in sync w/ typedef enum metrics_v2_value_unit -// https://prometheus.io/docs/practices/naming/ +// https://prometheus.io/docs/practices/naming/ or https://prometheus.io/docs/practices/naming/#base-units. static const char *const metrics_unit_name_mappings_prometheus[] = { [METRIC_VALUE_UNIT_COUNT] = "total", - [METRIC_VALUE_UNIT_PERC] = "percentage", [METRIC_VALUE_UNIT_RATIO] = "ratio", + [METRIC_VALUE_UNIT_PERC] = "percentage", [METRIC_VALUE_UNIT_MEMORY_BYTES] = "bytes", [METRIC_VALUE_UNIT_MEMORY_KIBIBYTES] = "kibibytes", [METRIC_VALUE_UNIT_MEMORY_MEGABYTES] = "megabytes", - [METRIC_VALUE_UNIT_DURATION_NS] = "duration_nanoseconds", - [METRIC_VALUE_UNIT_DURATION_S] = "duration_seconds", + [METRIC_VALUE_UNIT_TIME_NS] = "nanoseconds", + [METRIC_VALUE_UNIT_TIME_S] = "seconds", + [METRIC_VALUE_UNIT_TIME_NS_COUNT] = "nanoseconds_total", + [METRIC_VALUE_UNIT_TIME_S_COUNT] = "seconds_total", + [METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS] = "timestamp_nanoseconds", }; // For simplicity, needs to stay in sync w/ typedef enum metrics_v2_metric_type @@ -120,38 +126,26 @@ void metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) co void output_rule_metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) const { - switch (metric.unit) + if(metric.unit == METRIC_VALUE_UNIT_MEMORY_BYTES || metric.unit == METRIC_VALUE_UNIT_MEMORY_KIBIBYTES) { - case METRIC_VALUE_UNIT_MEMORY_BYTES: - case METRIC_VALUE_UNIT_MEMORY_KIBIBYTES: - switch (metric.type) - { - case METRIC_VALUE_TYPE_U32: + if(metric.type == METRIC_VALUE_TYPE_U32) { metric.value.d = libs::metrics::convert_memory(metric.unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, metric.value.u32); std::string metric_name_str(metric.name); - RE2::GlobalReplace(&metric_name_str, s_libs_units_suffix, "_mb"); + RE2::GlobalReplace(&metric_name_str, s_libs_metrics_units_memory_suffix, "_mb"); strlcpy(metric.name, metric_name_str.c_str(), METRIC_NAME_MAX); metric.type = METRIC_VALUE_TYPE_D; metric.unit = METRIC_VALUE_UNIT_MEMORY_MEGABYTES; - break; } - case METRIC_VALUE_TYPE_U64: + else if(metric.type == METRIC_VALUE_TYPE_U64) { metric.value.d = libs::metrics::convert_memory(metric.unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, metric.value.u64); std::string metric_name_str(metric.name); - RE2::GlobalReplace(&metric_name_str, s_libs_units_suffix, "_mb"); + RE2::GlobalReplace(&metric_name_str, s_libs_metrics_units_memory_suffix, "_mb"); strlcpy(metric.name, metric_name_str.c_str(), METRIC_NAME_MAX); metric.type = METRIC_VALUE_TYPE_D; metric.unit = METRIC_VALUE_UNIT_MEMORY_MEGABYTES; - break; - } - default: - break; } - break; - default: - break; } } @@ -169,7 +163,8 @@ std::string prometheus_metrics_converter::convert_metric_to_text(metrics_v2 metr } prometheus_metric_name_fully_qualified += std::string(metric.name) + "_"; // Remove native libs unit suffixes if applicable. - RE2::GlobalReplace(&prometheus_metric_name_fully_qualified, s_libs_units_suffix, ""); + RE2::GlobalReplace(&prometheus_metric_name_fully_qualified, s_libs_metrics_units_suffix_pre_prometheus_text_conversion, ""); + RE2::GlobalReplace(&prometheus_metric_name_fully_qualified, s_libs_metrics_banned_prometheus_naming_characters, "_"); prometheus_metric_name_fully_qualified += std::string(metrics_unit_name_mappings_prometheus[metric.unit]); // Create the complete 3-lines text-based Prometheus exposition format https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md @@ -242,8 +237,36 @@ std::string prometheus_metrics_converter::convert_metric_to_text(std::string_vie void prometheus_metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) const { - // todo - return; + if(metric.unit == METRIC_VALUE_UNIT_MEMORY_BYTES || metric.unit == METRIC_VALUE_UNIT_MEMORY_KIBIBYTES) + { + if(metric.type == METRIC_VALUE_TYPE_U32) + { + metric.value.d = libs::metrics::convert_memory(metric.unit, METRIC_VALUE_UNIT_MEMORY_BYTES, metric.value.u32); + std::string metric_name_str(metric.name); + RE2::GlobalReplace(&metric_name_str, s_libs_metrics_units_memory_suffix, "_bytes"); + strlcpy(metric.name, metric_name_str.c_str(), METRIC_NAME_MAX); + metric.type = METRIC_VALUE_TYPE_D; + metric.unit = METRIC_VALUE_UNIT_MEMORY_BYTES; + } + else if(metric.type == METRIC_VALUE_TYPE_U64) + { + metric.value.d = libs::metrics::convert_memory(metric.unit, METRIC_VALUE_UNIT_MEMORY_BYTES, metric.value.u64); + std::string metric_name_str(metric.name); + RE2::GlobalReplace(&metric_name_str, s_libs_metrics_units_memory_suffix, "_bytes"); + strlcpy(metric.name, metric_name_str.c_str(), METRIC_NAME_MAX); + metric.type = METRIC_VALUE_TYPE_D; + metric.unit = METRIC_VALUE_UNIT_MEMORY_BYTES; + } + } + else if(metric.unit == METRIC_VALUE_UNIT_PERC && metric.type == METRIC_VALUE_TYPE_D) + { + metric.value.d = metric.value.d / 100.0; + std::string metric_name_str(metric.name); + RE2::GlobalReplace(&metric_name_str, s_libs_metrics_units_perc_suffix, "_ratio"); + strlcpy(metric.name, metric_name_str.c_str(), METRIC_NAME_MAX); + metric.type = METRIC_VALUE_TYPE_D; + metric.unit = METRIC_VALUE_UNIT_RATIO; + } } void libs_metrics_collector::get_rss_vsz_pss_total_memory_and_open_fds(uint32_t &rss, uint32_t &vsz, uint32_t &pss, uint64_t &host_memory_used, uint64_t &host_open_fds) diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index 2e65bd6bcf..713ee922c6 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -178,7 +178,7 @@ class prometheus_metrics_converter : public metrics_converter std::string convert_metric_to_text(metrics_v2 metric, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", const std::map& const_labels = {}) const; /*! - \brief Method to convert a software version like metric_name to the text-based Prometheus exposition format. + \brief Overloaded method to convert a pseudo-metric / software version like metric_name to the text-based Prometheus exposition format. * * Note: Instead of using const_labels, which is a rare use case according to * https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels, @@ -203,11 +203,18 @@ class prometheus_metrics_converter : public metrics_converter std::string convert_metric_to_text(std::string_view metric_name, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", const std::map& const_labels = {}) const; /*! - \brief Method to convert metric units to Prometheus base units. todo, not yet implemented. - * - * \note metrics names w/ unit suffix shall be changed within this method, conforming to libs native metrics names, - * not Prometheus, `convert_metric_to_text` takes care of final metric name convertion to Prometheus text format. - * As a consequence `metric.unit` always matches the metric name unit suffix if applicable. + * \brief Method to convert metric units to Prometheus base units. + * + * \note Metric names shall be updated within this method, and the respective Prometheus-compliant + * unit suffix shall be added. Prometheus compliance means every metric name has a unit suffix, see + * https://prometheus.io/docs/practices/naming/ or https://prometheus.io/docs/practices/naming/#base-units. + * We conform to the best practices except for keeping libbpf stats metrics and timestamps in nanoseconds + * to avoid precision loss when converting them to seconds. + * Please note that, for example, even cAdvisor sometimes deviates from the standards, e.g., + * `container_memory_rss` instead of `container_memory_rss_bytes`. + * `metric.unit` is also modified and always matches the metric name unit suffix. + * + * In summary, effectively for Falco/libs, it just means converting all memory to bytes and CPU usage to a ratio. */ void convert_metric_to_unit_convention(metrics_v2& metric) const override; }; @@ -221,8 +228,8 @@ class output_rule_metrics_converter : public metrics_converter /*! \brief Method to convert metric units of memory-related metrics to mb * - * \note metrics names w/ unit suffix shall be changed within this method, conforming to libs native metrics names. - * As a consequence `metric.unit` always matches the metric name unit suffix if applicable. + * \note metrics names w/ unit suffix shall be updated within this method. + * `metric.unit` is also modified and always matches the metric name unit suffix if applicable. * */ void convert_metric_to_unit_convention(metrics_v2& metric) const override; diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index 2ccbd7707f..c87fc7e76b 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -42,8 +42,20 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_prometheus) /* Test prometheus_metrics_converter->convert_metric_to_text */ std::string prometheus_text; std::string prometheus_text_substring; - for (const auto& metric: metrics_snapshot) + std::string metrics_names_all_str_post_unit_conversion_pre_prometheus_text_conversion = ""; + + for (auto& metric: metrics_snapshot) { + prometheus_metrics_converter->convert_metric_to_unit_convention(metric); + if (!metrics_names_all_str_post_unit_conversion_pre_prometheus_text_conversion.empty()) + { + metrics_names_all_str_post_unit_conversion_pre_prometheus_text_conversion += " "; + } + metrics_names_all_str_post_unit_conversion_pre_prometheus_text_conversion += metric.name; + // Since unit testing is very limited here just also print it for manual inspection if needed + prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco"); + printf("%s", prometheus_text.c_str()); + if (strncmp(metric.name, "n_missing_container_images", 17) == 0) { // This resembles the Falco client use case @@ -56,7 +68,6 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_prometheus) testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1",example_key2="example2"} 0 )"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); // Test only one const_labels prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco", {{"example_key1", "example1"}}); prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ @@ -64,7 +75,6 @@ testns_falco_n_missing_container_images_total{raw_name="n_missing_container_imag testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1"} 0 )"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); // Test no const_labels prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco"); prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ @@ -72,7 +82,6 @@ testns_falco_n_missing_container_images_total{raw_name="n_missing_container_imag testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 )"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); // Test no prometheus_subsytem prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns"); prometheus_text_substring = R"(# HELP testns_n_missing_container_images_total https://falco.org/docs/metrics/ @@ -80,7 +89,6 @@ testns_falco_n_missing_container_images_total{raw_name="n_missing_container_imag testns_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 )"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); // Test no prometheus_namespace prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric); prometheus_text_substring = R"(# HELP n_missing_container_images_total https://falco.org/docs/metrics/ @@ -88,7 +96,6 @@ testns_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 n_missing_container_images_total{raw_name="n_missing_container_images"} 0 )"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); // Test no prometheus_namespace, but prometheus_subsytem prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "", "falco"); prometheus_text_substring = R"(# HELP falco_n_missing_container_images_total https://falco.org/docs/metrics/ @@ -96,29 +103,148 @@ n_missing_container_images_total{raw_name="n_missing_container_images"} 0 falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 )"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); - } else if (strncmp(metric.name, "memory_rss_kb", 16) == 0) + } else if (strncmp(metric.name, "memory_rss_bytes", 17) == 0) { // Test that libs native metric unit suffix was removed and replaced by the Prometheus specific unit suffix naming convention // todo adjust once base units are implemented prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco"); - printf("%s", prometheus_text.c_str()); - prometheus_text_substring = R"(# HELP testns_falco_memory_rss_kibibytes https://falco.org/docs/metrics/ -# TYPE testns_falco_memory_rss_kibibytes gauge -testns_falco_memory_rss_kibibytes{raw_name="memory_rss_kb"} )"; + prometheus_text_substring = R"(# HELP testns_falco_memory_rss_bytes https://falco.org/docs/metrics/ +# TYPE testns_falco_memory_rss_bytes gauge +testns_falco_memory_rss_bytes{raw_name="memory_rss_bytes"} )"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); } } - // Test global wrapper base metrics + ASSERT_EQ(metrics_names_all_str_post_unit_conversion_pre_prometheus_text_conversion, + "cpu_usage_ratio memory_rss_bytes memory_vsz_bytes memory_pss_bytes container_memory_used_bytes host_cpu_usage_ratio host_procs_running host_memory_used_bytes host_open_fds n_threads n_fds n_noncached_fd_lookups n_cached_fd_lookups n_failed_fd_lookups n_added_fds n_removed_fds n_stored_evts n_store_evts_drops n_retrieved_evts n_retrieve_evts_drops n_noncached_thread_lookups n_cached_thread_lookups n_failed_thread_lookups n_added_threads n_removed_threads n_drops_full_threadtable n_missing_container_images n_containers"); + + // Test global wrapper base metrics (pseudo metrics) prometheus_text = prometheus_metrics_converter->convert_metric_to_text("kernel_release", "testns", "falco", {{"kernel_release", "6.6.7-200.fc39.x86_64"}}); prometheus_text_substring = R"(# HELP testns_falco_kernel_release_info https://falco.org/docs/metrics/ # TYPE testns_falco_kernel_release_info gauge testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7-200.fc39.x86_64"} 1 )"; + printf("%s", prometheus_text.c_str()); ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - ASSERT_GT(prometheus_text.length(), 8); + + // Another round of fake metric tests since we do not fetch real scap metrics, for example. + std::vector fake_metrics_snapshot; + fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("sys_enter.run_cnt", + METRICS_V2_LIBBPF_STATS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + 76435525241UL)); + + fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("sys_enter.run_time_ns", + METRICS_V2_LIBBPF_STATS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_TIME_NS_COUNT, + METRIC_VALUE_MONOTONIC, + 16269369826392UL)); + + fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("sys_enter.avg_time_ns", + METRICS_V2_LIBBPF_STATS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_TIME_NS, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + 203UL)); + + fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("n_drops", + METRICS_V2_KERNEL_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + 674200UL)); + + fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("n_drops_buffer_total", + METRICS_V2_KERNEL_COUNTERS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_MONOTONIC, + 5000UL)); + + // Simulate some derived metrics; critical for example for Falco consumer use cases + fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("duration_sec", + METRICS_V2_MISC, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_TIME_S_COUNT, + METRIC_VALUE_MONOTONIC, + 144UL)); + + fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("evt_rate_sec", + METRICS_V2_MISC, + METRIC_VALUE_TYPE_D, + METRIC_VALUE_UNIT_TIME_S, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + 126065.4)); + + // Timestamps while they always go up should still be regarded as gauge from a Prometheus perspective + // https://www.robustperception.io/are-increasing-timestamps-counters-or-gauges/ + fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("host_boot_ts", + METRICS_V2_MISC, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS, + METRIC_VALUE_NON_MONOTONIC_CURRENT, + 1708753667000000000UL)); + + for (auto& metric: fake_metrics_snapshot) + { + prometheus_metrics_converter->convert_metric_to_unit_convention(metric); + prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco"); + printf("%s", prometheus_text.c_str()); + if (strncmp(metric.name, "sys_enter.run_cnt", 18) == 0) + { + prometheus_text_substring = R"(# HELP testns_falco_sys_enter_run_cnt_total https://falco.org/docs/metrics/ +# TYPE testns_falco_sys_enter_run_cnt_total counter +testns_falco_sys_enter_run_cnt_total{raw_name="sys_enter.run_cnt"} 76435525241 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + } else if (strncmp(metric.name, "sys_enter.run_time_ns", 22) == 0) + { + prometheus_text_substring = R"(# HELP testns_falco_sys_enter_run_time_nanoseconds_total https://falco.org/docs/metrics/ +# TYPE testns_falco_sys_enter_run_time_nanoseconds_total counter +testns_falco_sys_enter_run_time_nanoseconds_total{raw_name="sys_enter.run_time_ns"} 16269369826392 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + } else if (strncmp(metric.name, "sys_enter.avg_time_ns", 22) == 0) + { + prometheus_text_substring = R"(# HELP testns_falco_sys_enter_avg_time_nanoseconds https://falco.org/docs/metrics/ +# TYPE testns_falco_sys_enter_avg_time_nanoseconds gauge +testns_falco_sys_enter_avg_time_nanoseconds{raw_name="sys_enter.avg_time_ns"} 203 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + } else if (strncmp(metric.name, "n_drops_buffer_total", 21) == 0) + { + prometheus_text_substring = R"(# HELP testns_falco_n_drops_buffer_total https://falco.org/docs/metrics/ +# TYPE testns_falco_n_drops_buffer_total counter +testns_falco_n_drops_buffer_total{raw_name="n_drops_buffer_total"} 5000 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + } else if (strncmp(metric.name, "duration_sec", 13) == 0) + { + prometheus_text_substring = R"(# HELP testns_falco_duration_seconds_total https://falco.org/docs/metrics/ +# TYPE testns_falco_duration_seconds_total counter +testns_falco_duration_seconds_total{raw_name="duration_sec"} 144 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + } else if (strncmp(metric.name, "evt_rate_sec", 13) == 0) + { + prometheus_text_substring = R"(# HELP testns_falco_evt_rate_seconds https://falco.org/docs/metrics/ +# TYPE testns_falco_evt_rate_seconds gauge +testns_falco_evt_rate_seconds{raw_name="evt_rate_sec"} 126065.400000 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + } else if (strncmp(metric.name, "host_boot_ts", 13) == 0) + { + prometheus_text_substring = R"(# HELP testns_falco_host_boot_timestamp_nanoseconds https://falco.org/docs/metrics/ +# TYPE testns_falco_host_boot_timestamp_nanoseconds gauge +testns_falco_host_boot_timestamp_nanoseconds{raw_name="host_boot_ts"} 1708753667000000000 +)"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + } + } + } TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_output_rule) From f034066bd8d5185705b15028f1d9f5ec4c7f2092 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Thu, 7 Mar 2024 18:52:34 +0000 Subject: [PATCH 18/22] cleanup(libsinsp/metrics): apply reviewers suggestions + cleanup Co-authored-by: Federico Aponte Signed-off-by: Melissa Kilby --- userspace/libsinsp/metrics_collector.cpp | 4 +- userspace/libsinsp/metrics_collector.h | 11 ++-- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 60 ++++++++++---------- 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index d60652bcb4..1cac5bfd8f 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -86,7 +86,7 @@ static const char *const metrics_metric_type_name_mappings_prometheus[] = { namespace libs::metrics { -std::string metrics_converter::convert_metric_to_text(metrics_v2 metric) const +std::string metrics_converter::convert_metric_to_text(const metrics_v2& metric) const { std::string metric_text = std::string(metric.name) + " "; switch (metric.type) @@ -149,7 +149,7 @@ void output_rule_metrics_converter::convert_metric_to_unit_convention(metrics_v2 } } -std::string prometheus_metrics_converter::convert_metric_to_text(metrics_v2 metric, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, const std::map& const_labels) const +std::string prometheus_metrics_converter::convert_metric_to_text(const metrics_v2& metric, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, const std::map& const_labels) const { // Create `prometheus_metric_name_fully_qualified` std::string prometheus_metric_name_fully_qualified; diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index 713ee922c6..0883e45e60 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -85,7 +85,7 @@ namespace libs::metrics { template -static double convert_memory(metrics_v2_value_unit source_unit, metrics_v2_value_unit dest_unit, T val) +double convert_memory(metrics_v2_value_unit source_unit, metrics_v2_value_unit dest_unit, T val) { double factor = 1; switch(source_unit) @@ -120,9 +120,8 @@ static double convert_memory(metrics_v2_value_unit source_unit, metrics_v2_value class metrics_converter { public: - metrics_converter() = default; - virtual std::string convert_metric_to_text(metrics_v2 metric) const; + virtual std::string convert_metric_to_text(const metrics_v2& metric) const; virtual void convert_metric_to_unit_convention(metrics_v2& metric) const = 0; }; @@ -131,7 +130,6 @@ class metrics_converter class prometheus_metrics_converter : public metrics_converter { public: - prometheus_metrics_converter() = default; /*! \brief Method to convert a metrics_v2 metric to the text-based Prometheus exposition format. @@ -175,7 +173,7 @@ class prometheus_metrics_converter : public metrics_converter * w/ a `prometheus_metric_name_fully_qualified` - optional components prepended to and unit appended to. * 3-lines including # HELP and # TYPE lines followed by the metric line, raw metric name always present as label. */ - std::string convert_metric_to_text(metrics_v2 metric, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", const std::map& const_labels = {}) const; + std::string convert_metric_to_text(const metrics_v2& metric, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", const std::map& const_labels = {}) const; /*! \brief Overloaded method to convert a pseudo-metric / software version like metric_name to the text-based Prometheus exposition format. @@ -223,7 +221,6 @@ class prometheus_metrics_converter : public metrics_converter class output_rule_metrics_converter : public metrics_converter { public: - output_rule_metrics_converter() = default; /*! \brief Method to convert metric units of memory-related metrics to mb @@ -259,7 +256,7 @@ class libs_metrics_collector \brief Method to create a new metrics_v2 */ template - const metrics_v2 new_metric(const char* name, uint32_t flags, metrics_v2_value_type type, metrics_v2_value_unit unit, metrics_v2_metric_type metric_type, T val) + metrics_v2 new_metric(const char* name, uint32_t flags, metrics_v2_value_type type, metrics_v2_value_unit unit, metrics_v2_metric_type metric_type, T val) { metrics_v2 metric; strlcpy(metric.name, name, METRIC_NAME_MAX); diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index c87fc7e76b..f788530d5e 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -42,7 +42,7 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_prometheus) /* Test prometheus_metrics_converter->convert_metric_to_text */ std::string prometheus_text; std::string prometheus_text_substring; - std::string metrics_names_all_str_post_unit_conversion_pre_prometheus_text_conversion = ""; + std::string metrics_names_all_str_post_unit_conversion_pre_prometheus_text_conversion; for (auto& metric: metrics_snapshot) { @@ -56,7 +56,7 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_prometheus) prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco"); printf("%s", prometheus_text.c_str()); - if (strncmp(metric.name, "n_missing_container_images", 17) == 0) + if (strncmp(metric.name, "n_missing_container_images", strlen(metric.name)) == 0) { // This resembles the Falco client use case @@ -67,43 +67,43 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_prometheus) # TYPE testns_falco_n_missing_container_images_total gauge testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1",example_key2="example2"} 0 )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; // Test only one const_labels prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco", {{"example_key1", "example1"}}); prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE testns_falco_n_missing_container_images_total gauge testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1"} 0 )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; // Test no const_labels prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco"); prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE testns_falco_n_missing_container_images_total gauge testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; // Test no prometheus_subsytem prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns"); prometheus_text_substring = R"(# HELP testns_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE testns_n_missing_container_images_total gauge testns_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; // Test no prometheus_namespace prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric); prometheus_text_substring = R"(# HELP n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE n_missing_container_images_total gauge n_missing_container_images_total{raw_name="n_missing_container_images"} 0 )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; // Test no prometheus_namespace, but prometheus_subsytem prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "", "falco"); prometheus_text_substring = R"(# HELP falco_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE falco_n_missing_container_images_total gauge falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - } else if (strncmp(metric.name, "memory_rss_bytes", 17) == 0) + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; + } else if (strncmp(metric.name, "memory_rss_bytes", strlen(metric.name)) == 0) { // Test that libs native metric unit suffix was removed and replaced by the Prometheus specific unit suffix naming convention // todo adjust once base units are implemented @@ -111,7 +111,7 @@ falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 prometheus_text_substring = R"(# HELP testns_falco_memory_rss_bytes https://falco.org/docs/metrics/ # TYPE testns_falco_memory_rss_bytes gauge testns_falco_memory_rss_bytes{raw_name="memory_rss_bytes"} )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; } } @@ -125,7 +125,7 @@ testns_falco_memory_rss_bytes{raw_name="memory_rss_bytes"} )"; testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7-200.fc39.x86_64"} 1 )"; printf("%s", prometheus_text.c_str()); - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; // Another round of fake metric tests since we do not fetch real scap metrics, for example. std::vector fake_metrics_snapshot; @@ -193,55 +193,55 @@ testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7 prometheus_metrics_converter->convert_metric_to_unit_convention(metric); prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco"); printf("%s", prometheus_text.c_str()); - if (strncmp(metric.name, "sys_enter.run_cnt", 18) == 0) + if (strncmp(metric.name, "sys_enter.run_cnt", strlen(metric.name)) == 0) { prometheus_text_substring = R"(# HELP testns_falco_sys_enter_run_cnt_total https://falco.org/docs/metrics/ # TYPE testns_falco_sys_enter_run_cnt_total counter testns_falco_sys_enter_run_cnt_total{raw_name="sys_enter.run_cnt"} 76435525241 )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - } else if (strncmp(metric.name, "sys_enter.run_time_ns", 22) == 0) + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; + } else if (strncmp(metric.name, "sys_enter.run_time_ns", strlen(metric.name)) == 0) { prometheus_text_substring = R"(# HELP testns_falco_sys_enter_run_time_nanoseconds_total https://falco.org/docs/metrics/ # TYPE testns_falco_sys_enter_run_time_nanoseconds_total counter testns_falco_sys_enter_run_time_nanoseconds_total{raw_name="sys_enter.run_time_ns"} 16269369826392 )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - } else if (strncmp(metric.name, "sys_enter.avg_time_ns", 22) == 0) + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; + } else if (strncmp(metric.name, "sys_enter.avg_time_ns", strlen(metric.name)) == 0) { prometheus_text_substring = R"(# HELP testns_falco_sys_enter_avg_time_nanoseconds https://falco.org/docs/metrics/ # TYPE testns_falco_sys_enter_avg_time_nanoseconds gauge testns_falco_sys_enter_avg_time_nanoseconds{raw_name="sys_enter.avg_time_ns"} 203 )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - } else if (strncmp(metric.name, "n_drops_buffer_total", 21) == 0) + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; + } else if (strncmp(metric.name, "n_drops_buffer_total", strlen(metric.name)) == 0 && strlen(metric.name) == 21) // avoid clash with "n_drops" metric name { prometheus_text_substring = R"(# HELP testns_falco_n_drops_buffer_total https://falco.org/docs/metrics/ # TYPE testns_falco_n_drops_buffer_total counter testns_falco_n_drops_buffer_total{raw_name="n_drops_buffer_total"} 5000 )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - } else if (strncmp(metric.name, "duration_sec", 13) == 0) + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; + } else if (strncmp(metric.name, "duration_sec", strlen(metric.name)) == 0) { prometheus_text_substring = R"(# HELP testns_falco_duration_seconds_total https://falco.org/docs/metrics/ # TYPE testns_falco_duration_seconds_total counter testns_falco_duration_seconds_total{raw_name="duration_sec"} 144 )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - } else if (strncmp(metric.name, "evt_rate_sec", 13) == 0) + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; + } else if (strncmp(metric.name, "evt_rate_sec", strlen(metric.name)) == 0) { prometheus_text_substring = R"(# HELP testns_falco_evt_rate_seconds https://falco.org/docs/metrics/ # TYPE testns_falco_evt_rate_seconds gauge testns_falco_evt_rate_seconds{raw_name="evt_rate_sec"} 126065.400000 )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; - } else if (strncmp(metric.name, "host_boot_ts", 13) == 0) + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; + } else if (strncmp(metric.name, "host_boot_ts", strlen(metric.name)) == 0) { prometheus_text_substring = R"(# HELP testns_falco_host_boot_timestamp_nanoseconds https://falco.org/docs/metrics/ # TYPE testns_falco_host_boot_timestamp_nanoseconds gauge testns_falco_host_boot_timestamp_nanoseconds{raw_name="host_boot_ts"} 1708753667000000000 )"; - ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text"; + ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; } } @@ -275,10 +275,10 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_output_rule) for(const auto& metric_name : minimal_metrics_names) { - uint32_t i = 0; + int i = 0; for (const auto& metric: metrics_snapshot) { - if(metric_name.compare(metric.name) == 0) + if(metric_name == metric.name) { break; } @@ -293,8 +293,8 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_output_rule) /* Assert successful memory unit changes and sanity check some values to be greater than 0 */ const std::vector metrics_names_memory = {"memory_rss_mb", "memory_vsz_mb", "memory_pss_mb", "container_memory_used_mb", "host_memory_used_mb"}; const std::vector metrics_names_values_gt = {"n_threads", "n_fds", "n_added_threads"}; - uint32_t success_memory_cnt = 0; - uint32_t success_values_cnt = 0; + int success_memory_cnt = 0; + int success_values_cnt = 0; for (auto& metric: metrics_snapshot) { // This resembles the Falco client use case and would be called if `convert_memory_to_mb` is set to true @@ -303,7 +303,7 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_output_rule) { ASSERT_EQ(metric.unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES); ASSERT_EQ(metric.type, METRIC_VALUE_TYPE_D); - if (strncmp(metric.name, "host_memory_used_mb", 20) == 0 || strncmp(metric.name, "memory_rss_mb", 14) == 0 ) + if (strncmp(metric.name, "host_memory_used_mb", strlen(metric.name)) == 0 || strncmp(metric.name, "memory_rss_mb", strlen(metric.name)) == 0) { ASSERT_GT(metric.value.d, 0); // Just making sure we don't get a high value due to an unitialized variables From 9c482ff5b8d93f04dbfd8c3a88485435195103a6 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Thu, 7 Mar 2024 22:45:38 +0000 Subject: [PATCH 19/22] cleanup(libsinsp/metrics): apply reviewers suggestions Co-authored-by: Federico Aponte Signed-off-by: Melissa Kilby --- userspace/libsinsp/metrics_collector.cpp | 4 +- userspace/libsinsp/metrics_collector.h | 5 +- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 104 +++++++++---------- 3 files changed, 57 insertions(+), 56 deletions(-) diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index 1cac5bfd8f..42491b6dbe 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -149,7 +149,7 @@ void output_rule_metrics_converter::convert_metric_to_unit_convention(metrics_v2 } } -std::string prometheus_metrics_converter::convert_metric_to_text(const metrics_v2& metric, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, const std::map& const_labels) const +std::string prometheus_metrics_converter::convert_metric_to_text_prometheus(const metrics_v2& metric, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, const std::map& const_labels) const { // Create `prometheus_metric_name_fully_qualified` std::string prometheus_metric_name_fully_qualified; @@ -208,7 +208,7 @@ std::string prometheus_metrics_converter::convert_metric_to_text(const metrics_v return prometheus_text; } -std::string prometheus_metrics_converter::convert_metric_to_text(std::string_view metric_name, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, const std::map& const_labels) const +std::string prometheus_metrics_converter::convert_metric_to_text_prometheus(std::string_view metric_name, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, const std::map& const_labels) const { // Create `prometheus_metric_name_fully_qualified` std::string prometheus_metric_name_fully_qualified; diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index 0883e45e60..c816bf1bf4 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -120,6 +120,7 @@ double convert_memory(metrics_v2_value_unit source_unit, metrics_v2_value_unit d class metrics_converter { public: + virtual ~metrics_converter() = default; virtual std::string convert_metric_to_text(const metrics_v2& metric) const; @@ -173,7 +174,7 @@ class prometheus_metrics_converter : public metrics_converter * w/ a `prometheus_metric_name_fully_qualified` - optional components prepended to and unit appended to. * 3-lines including # HELP and # TYPE lines followed by the metric line, raw metric name always present as label. */ - std::string convert_metric_to_text(const metrics_v2& metric, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", const std::map& const_labels = {}) const; + std::string convert_metric_to_text_prometheus(const metrics_v2& metric, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", const std::map& const_labels = {}) const; /*! \brief Overloaded method to convert a pseudo-metric / software version like metric_name to the text-based Prometheus exposition format. @@ -198,7 +199,7 @@ class prometheus_metrics_converter : public metrics_converter * w/ a `prometheus_metric_name_fully_qualified` - optional components prepended to and unit appended to. * 3-lines including # HELP and # TYPE lines followed by the metric line, raw metric name always present as label. */ - std::string convert_metric_to_text(std::string_view metric_name, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", const std::map& const_labels = {}) const; + std::string convert_metric_to_text_prometheus(std::string_view metric_name, std::string_view prometheus_namespace = "", std::string_view prometheus_subsystem = "", const std::map& const_labels = {}) const; /*! * \brief Method to convert metric units to Prometheus base units. diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index f788530d5e..98aeaaf4e6 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -32,28 +32,28 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_prometheus) /* Snapshot current metrics and get the updated metrics_snapshot buffer */ uint32_t test_metrics_flags = (METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); - auto libs_metrics_collector = std::make_unique(&m_inspector, test_metrics_flags); - auto prometheus_metrics_converter = std::make_unique(); + libs::metrics::libs_metrics_collector libs_metrics_collector(&m_inspector, test_metrics_flags); + libs::metrics::prometheus_metrics_converter prometheus_metrics_converter; - libs_metrics_collector->snapshot(); - auto metrics_snapshot = libs_metrics_collector->get_metrics(); + libs_metrics_collector.snapshot(); + auto metrics_snapshot = libs_metrics_collector.get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 28); - /* Test prometheus_metrics_converter->convert_metric_to_text */ + /* Test prometheus_metrics_converter.convert_metric_to_text_prometheus */ std::string prometheus_text; std::string prometheus_text_substring; std::string metrics_names_all_str_post_unit_conversion_pre_prometheus_text_conversion; for (auto& metric: metrics_snapshot) { - prometheus_metrics_converter->convert_metric_to_unit_convention(metric); + prometheus_metrics_converter.convert_metric_to_unit_convention(metric); if (!metrics_names_all_str_post_unit_conversion_pre_prometheus_text_conversion.empty()) { metrics_names_all_str_post_unit_conversion_pre_prometheus_text_conversion += " "; } metrics_names_all_str_post_unit_conversion_pre_prometheus_text_conversion += metric.name; // Since unit testing is very limited here just also print it for manual inspection if needed - prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco"); + prometheus_text = prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "testns", "falco"); printf("%s", prometheus_text.c_str()); if (strncmp(metric.name, "n_missing_container_images", strlen(metric.name)) == 0) @@ -62,42 +62,42 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_prometheus) // Falco output_rule metrics prepends either `falco.` or `scap.` to a single metric, see https://falco.org/docs/metrics/ // Use same strings for `prometheus_subsystem`, but instead of `.` we use `_` delimiter to conform with Prometheus naming conventions + append the unit - prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco", {{"example_key1", "example1"},{"example_key2", "example2"}}); + prometheus_text = prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "testns", "falco", {{"example_key1", "example1"},{"example_key2", "example2"}}); prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE testns_falco_n_missing_container_images_total gauge testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1",example_key2="example2"} 0 )"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; // Test only one const_labels - prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco", {{"example_key1", "example1"}}); + prometheus_text = prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "testns", "falco", {{"example_key1", "example1"}}); prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE testns_falco_n_missing_container_images_total gauge testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images",example_key1="example1"} 0 )"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; // Test no const_labels - prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco"); + prometheus_text = prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "testns", "falco"); prometheus_text_substring = R"(# HELP testns_falco_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE testns_falco_n_missing_container_images_total gauge testns_falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 )"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; // Test no prometheus_subsytem - prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns"); + prometheus_text = prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "testns"); prometheus_text_substring = R"(# HELP testns_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE testns_n_missing_container_images_total gauge testns_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 )"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; // Test no prometheus_namespace - prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric); + prometheus_text = prometheus_metrics_converter.convert_metric_to_text_prometheus(metric); prometheus_text_substring = R"(# HELP n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE n_missing_container_images_total gauge n_missing_container_images_total{raw_name="n_missing_container_images"} 0 )"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; // Test no prometheus_namespace, but prometheus_subsytem - prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "", "falco"); + prometheus_text = prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "", "falco"); prometheus_text_substring = R"(# HELP falco_n_missing_container_images_total https://falco.org/docs/metrics/ # TYPE falco_n_missing_container_images_total gauge falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 @@ -107,7 +107,7 @@ falco_n_missing_container_images_total{raw_name="n_missing_container_images"} 0 { // Test that libs native metric unit suffix was removed and replaced by the Prometheus specific unit suffix naming convention // todo adjust once base units are implemented - prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco"); + prometheus_text = prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "testns", "falco"); prometheus_text_substring = R"(# HELP testns_falco_memory_rss_bytes https://falco.org/docs/metrics/ # TYPE testns_falco_memory_rss_bytes gauge testns_falco_memory_rss_bytes{raw_name="memory_rss_bytes"} )"; @@ -119,7 +119,7 @@ testns_falco_memory_rss_bytes{raw_name="memory_rss_bytes"} )"; "cpu_usage_ratio memory_rss_bytes memory_vsz_bytes memory_pss_bytes container_memory_used_bytes host_cpu_usage_ratio host_procs_running host_memory_used_bytes host_open_fds n_threads n_fds n_noncached_fd_lookups n_cached_fd_lookups n_failed_fd_lookups n_added_fds n_removed_fds n_stored_evts n_store_evts_drops n_retrieved_evts n_retrieve_evts_drops n_noncached_thread_lookups n_cached_thread_lookups n_failed_thread_lookups n_added_threads n_removed_threads n_drops_full_threadtable n_missing_container_images n_containers"); // Test global wrapper base metrics (pseudo metrics) - prometheus_text = prometheus_metrics_converter->convert_metric_to_text("kernel_release", "testns", "falco", {{"kernel_release", "6.6.7-200.fc39.x86_64"}}); + prometheus_text = prometheus_metrics_converter.convert_metric_to_text_prometheus("kernel_release", "testns", "falco", {{"kernel_release", "6.6.7-200.fc39.x86_64"}}); prometheus_text_substring = R"(# HELP testns_falco_kernel_release_info https://falco.org/docs/metrics/ # TYPE testns_falco_kernel_release_info gauge testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7-200.fc39.x86_64"} 1 @@ -129,35 +129,35 @@ testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7 // Another round of fake metric tests since we do not fetch real scap metrics, for example. std::vector fake_metrics_snapshot; - fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("sys_enter.run_cnt", + fake_metrics_snapshot.emplace_back(libs_metrics_collector.new_metric("sys_enter.run_cnt", METRICS_V2_LIBBPF_STATS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, 76435525241UL)); - fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("sys_enter.run_time_ns", + fake_metrics_snapshot.emplace_back(libs_metrics_collector.new_metric("sys_enter.run_time_ns", METRICS_V2_LIBBPF_STATS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_TIME_NS_COUNT, METRIC_VALUE_MONOTONIC, 16269369826392UL)); - fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("sys_enter.avg_time_ns", + fake_metrics_snapshot.emplace_back(libs_metrics_collector.new_metric("sys_enter.avg_time_ns", METRICS_V2_LIBBPF_STATS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_TIME_NS, METRIC_VALUE_NON_MONOTONIC_CURRENT, 203UL)); - fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("n_drops", + fake_metrics_snapshot.emplace_back(libs_metrics_collector.new_metric("n_drops", METRICS_V2_KERNEL_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, METRIC_VALUE_MONOTONIC, 674200UL)); - fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("n_drops_buffer_total", + fake_metrics_snapshot.emplace_back(libs_metrics_collector.new_metric("n_drops_buffer_total", METRICS_V2_KERNEL_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, @@ -165,14 +165,14 @@ testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7 5000UL)); // Simulate some derived metrics; critical for example for Falco consumer use cases - fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("duration_sec", + fake_metrics_snapshot.emplace_back(libs_metrics_collector.new_metric("duration_sec", METRICS_V2_MISC, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_TIME_S_COUNT, METRIC_VALUE_MONOTONIC, 144UL)); - fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("evt_rate_sec", + fake_metrics_snapshot.emplace_back(libs_metrics_collector.new_metric("evt_rate_sec", METRICS_V2_MISC, METRIC_VALUE_TYPE_D, METRIC_VALUE_UNIT_TIME_S, @@ -181,7 +181,7 @@ testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7 // Timestamps while they always go up should still be regarded as gauge from a Prometheus perspective // https://www.robustperception.io/are-increasing-timestamps-counters-or-gauges/ - fake_metrics_snapshot.emplace_back(libs_metrics_collector->new_metric("host_boot_ts", + fake_metrics_snapshot.emplace_back(libs_metrics_collector.new_metric("host_boot_ts", METRICS_V2_MISC, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS, @@ -190,8 +190,8 @@ testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7 for (auto& metric: fake_metrics_snapshot) { - prometheus_metrics_converter->convert_metric_to_unit_convention(metric); - prometheus_text = prometheus_metrics_converter->convert_metric_to_text(metric, "testns", "falco"); + prometheus_metrics_converter.convert_metric_to_unit_convention(metric); + prometheus_text = prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "testns", "falco"); printf("%s", prometheus_text.c_str()); if (strncmp(metric.name, "sys_enter.run_cnt", strlen(metric.name)) == 0) { @@ -258,15 +258,15 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_output_rule) /* Snapshot current metrics and get the updated metrics_snapshot buffer */ uint32_t test_metrics_flags = (METRICS_V2_KERNEL_COUNTERS | METRICS_V2_LIBBPF_STATS | METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); - auto libs_metrics_collector = std::make_unique(&m_inspector, test_metrics_flags); - auto output_rule_metrics_converter = std::make_unique(); + libs::metrics::libs_metrics_collector libs_metrics_collector(&m_inspector, test_metrics_flags); + libs::metrics::output_rule_metrics_converter output_rule_metrics_converter; /* Multiple calls */ - libs_metrics_collector->snapshot(); - auto metrics_snapshot = libs_metrics_collector->get_metrics(); - libs_metrics_collector->snapshot(); - libs_metrics_collector->snapshot(); - metrics_snapshot = libs_metrics_collector->get_metrics(); + libs_metrics_collector.snapshot(); + auto metrics_snapshot = libs_metrics_collector.get_metrics(); + libs_metrics_collector.snapshot(); + libs_metrics_collector.snapshot(); + metrics_snapshot = libs_metrics_collector.get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 28); /* These names should always be available, note that we currently can't check for the merged scap stats metrics here */ @@ -275,7 +275,7 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_output_rule) for(const auto& metric_name : minimal_metrics_names) { - int i = 0; + size_t i = 0; for (const auto& metric: metrics_snapshot) { if(metric_name == metric.name) @@ -298,7 +298,7 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_output_rule) for (auto& metric: metrics_snapshot) { // This resembles the Falco client use case and would be called if `convert_memory_to_mb` is set to true - output_rule_metrics_converter->convert_metric_to_unit_convention(metric); + output_rule_metrics_converter.convert_metric_to_unit_convention(metric); if (std::find(metrics_names_memory.begin(), metrics_names_memory.end(), metric.name) != metrics_names_memory.end()) { ASSERT_EQ(metric.unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES); @@ -326,45 +326,45 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_output_rule) ASSERT_EQ(success_values_cnt, metrics_names_values_gt.size()); /* Empty call */ - libs_metrics_collector = std::make_unique(&m_inspector, 0); - libs_metrics_collector->snapshot(); - metrics_snapshot = libs_metrics_collector->get_metrics(); + libs::metrics::libs_metrics_collector libs_metrics_collector2(&m_inspector, 0); + libs_metrics_collector2.snapshot(); + metrics_snapshot = libs_metrics_collector2.get_metrics(); ASSERT_TRUE(metrics_snapshot.empty()); /* Sanity check empty inspector */ test_metrics_flags = (METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); - libs_metrics_collector = std::make_unique(nullptr, test_metrics_flags); - libs_metrics_collector->snapshot(); - metrics_snapshot = libs_metrics_collector->get_metrics(); + libs::metrics::libs_metrics_collector libs_metrics_collector3(nullptr, test_metrics_flags); + libs_metrics_collector3.snapshot(); + metrics_snapshot = libs_metrics_collector3.get_metrics(); ASSERT_TRUE(metrics_snapshot.empty()); /* Some sanity checks for selective flags */ test_metrics_flags = 0; test_metrics_flags |= METRICS_V2_KERNEL_COUNTERS; // 20, but can't test it here it's 0 test_metrics_flags |= METRICS_V2_LIBBPF_STATS; // 21 (x86_64 machine), but can't test it here it's 0 - libs_metrics_collector = std::make_unique(&m_inspector, test_metrics_flags); - libs_metrics_collector->snapshot(); - metrics_snapshot = libs_metrics_collector->get_metrics(); + libs::metrics::libs_metrics_collector libs_metrics_collector4(&m_inspector, test_metrics_flags); + libs_metrics_collector4.snapshot(); + metrics_snapshot = libs_metrics_collector4.get_metrics(); ASSERT_TRUE(metrics_snapshot.empty()); test_metrics_flags = 0; test_metrics_flags |= METRICS_V2_RESOURCE_UTILIZATION; - libs_metrics_collector = std::make_unique(&m_inspector, test_metrics_flags); - libs_metrics_collector->snapshot(); - metrics_snapshot = libs_metrics_collector->get_metrics(); + libs::metrics::libs_metrics_collector libs_metrics_collector5(&m_inspector, test_metrics_flags); + libs_metrics_collector5.snapshot(); + metrics_snapshot = libs_metrics_collector5.get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 9); test_metrics_flags = 0; test_metrics_flags |= METRICS_V2_STATE_COUNTERS; - libs_metrics_collector = std::make_unique(&m_inspector, test_metrics_flags); - libs_metrics_collector->snapshot(); - metrics_snapshot = libs_metrics_collector->get_metrics(); + libs::metrics::libs_metrics_collector libs_metrics_collector6(&m_inspector, test_metrics_flags); + libs_metrics_collector6.snapshot(); + metrics_snapshot = libs_metrics_collector6.get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 19); test_metrics_flags = (METRICS_V2_RESOURCE_UTILIZATION | METRICS_V2_STATE_COUNTERS); - libs_metrics_collector = std::make_unique(&m_inspector, test_metrics_flags); - libs_metrics_collector->snapshot(); - metrics_snapshot = libs_metrics_collector->get_metrics(); + libs::metrics::libs_metrics_collector libs_metrics_collector7(&m_inspector, test_metrics_flags); + libs_metrics_collector7.snapshot(); + metrics_snapshot = libs_metrics_collector7.get_metrics(); ASSERT_EQ(metrics_snapshot.size(), 28); } From dbfcfad4cca47257abcd8b2b62176209dbfa18e9 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Fri, 8 Mar 2024 16:41:03 +0000 Subject: [PATCH 20/22] chore: use cerr information prints in metrics unit tests Signed-off-by: Melissa Kilby --- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index 98aeaaf4e6..7adfeac109 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -54,7 +54,7 @@ TEST_F(sinsp_with_test_input, sinsp_libs_metrics_collector_prometheus) metrics_names_all_str_post_unit_conversion_pre_prometheus_text_conversion += metric.name; // Since unit testing is very limited here just also print it for manual inspection if needed prometheus_text = prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "testns", "falco"); - printf("%s", prometheus_text.c_str()); + std::cerr << prometheus_text; if (strncmp(metric.name, "n_missing_container_images", strlen(metric.name)) == 0) { @@ -124,7 +124,7 @@ testns_falco_memory_rss_bytes{raw_name="memory_rss_bytes"} )"; # TYPE testns_falco_kernel_release_info gauge testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7-200.fc39.x86_64"} 1 )"; - printf("%s", prometheus_text.c_str()); + std::cerr << prometheus_text; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; // Another round of fake metric tests since we do not fetch real scap metrics, for example. @@ -192,7 +192,7 @@ testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7 { prometheus_metrics_converter.convert_metric_to_unit_convention(metric); prometheus_text = prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "testns", "falco"); - printf("%s", prometheus_text.c_str()); + std::cerr << prometheus_text; if (strncmp(metric.name, "sys_enter.run_cnt", strlen(metric.name)) == 0) { prometheus_text_substring = R"(# HELP testns_falco_sys_enter_run_cnt_total https://falco.org/docs/metrics/ @@ -214,7 +214,7 @@ testns_falco_sys_enter_run_time_nanoseconds_total{raw_name="sys_enter.run_time_n testns_falco_sys_enter_avg_time_nanoseconds{raw_name="sys_enter.avg_time_ns"} 203 )"; ASSERT_TRUE(prometheus_text.find(prometheus_text_substring) != std::string::npos) << "Substring not found in prometheus_text got\n" << prometheus_text; - } else if (strncmp(metric.name, "n_drops_buffer_total", strlen(metric.name)) == 0 && strlen(metric.name) == 21) // avoid clash with "n_drops" metric name + } else if (strncmp(metric.name, "n_drops_buffer_total", strlen(metric.name)) == 0 && strlen(metric.name) == 20) // avoid clash with "n_drops" metric name { prometheus_text_substring = R"(# HELP testns_falco_n_drops_buffer_total https://falco.org/docs/metrics/ # TYPE testns_falco_n_drops_buffer_total counter From 33a34ca4e168261a73cd479349d1b01a2f6e3808 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Fri, 8 Mar 2024 16:41:32 +0000 Subject: [PATCH 21/22] cleanup(metrics): code deduplication and simplification Co-authored-by: Samuel Gaist Signed-off-by: Melissa Kilby --- userspace/libscap/metrics_v2.h | 10 +- userspace/libsinsp/metrics_collector.cpp | 185 +++++++++-------------- 2 files changed, 79 insertions(+), 116 deletions(-) diff --git a/userspace/libscap/metrics_v2.h b/userspace/libscap/metrics_v2.h index 4d200d940d..6088a0a897 100644 --- a/userspace/libscap/metrics_v2.h +++ b/userspace/libscap/metrics_v2.h @@ -48,7 +48,7 @@ typedef union metrics_v2_value { double d; float f; int i; -}metrics_v2_value; +} metrics_v2_value; typedef enum metrics_v2_value_type{ METRIC_VALUE_TYPE_U32, @@ -58,7 +58,7 @@ typedef enum metrics_v2_value_type{ METRIC_VALUE_TYPE_D, METRIC_VALUE_TYPE_F, METRIC_VALUE_TYPE_I, -}metrics_v2_value_type; +} metrics_v2_value_type; typedef enum metrics_v2_value_unit{ METRIC_VALUE_UNIT_COUNT, @@ -72,12 +72,12 @@ typedef enum metrics_v2_value_unit{ METRIC_VALUE_UNIT_TIME_NS_COUNT, METRIC_VALUE_UNIT_TIME_S_COUNT, METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS, -}metrics_v2_value_unit; +} metrics_v2_value_unit; typedef enum metrics_v2_metric_type{ METRIC_VALUE_MONOTONIC, METRIC_VALUE_NON_MONOTONIC_CURRENT, -}metrics_v2_metric_type; +} metrics_v2_metric_type; /*! \brief Metrics schema, used for libscap and libsinsp metrics about an in progress capture. @@ -92,7 +92,7 @@ typedef struct metrics_v2 metrics_v2_value value; metrics_v2_value_type type; metrics_v2_value_unit unit; -}metrics_v2; +} metrics_v2; #ifdef __cplusplus } diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index 42491b6dbe..413c050bf6 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -86,177 +86,140 @@ static const char *const metrics_metric_type_name_mappings_prometheus[] = { namespace libs::metrics { -std::string metrics_converter::convert_metric_to_text(const metrics_v2& metric) const +std::string metric_value_to_text(const metrics_v2& metric) { - std::string metric_text = std::string(metric.name) + " "; + std::string value_text; switch (metric.type) { case METRIC_VALUE_TYPE_U32: - metric_text += std::to_string(metric.value.u32); + value_text = std::to_string(metric.value.u32); break; case METRIC_VALUE_TYPE_S32: - metric_text += std::to_string(metric.value.s32); + value_text = std::to_string(metric.value.s32); break; case METRIC_VALUE_TYPE_U64: - metric_text += std::to_string(metric.value.u64); + value_text = std::to_string(metric.value.u64); break; case METRIC_VALUE_TYPE_S64: - metric_text += std::to_string(metric.value.s64); + value_text = std::to_string(metric.value.s64); break; case METRIC_VALUE_TYPE_D: - metric_text += std::to_string(metric.value.d); + value_text = std::to_string(metric.value.d); break; case METRIC_VALUE_TYPE_F: - metric_text += std::to_string(metric.value.f); + value_text = std::to_string(metric.value.f); break; case METRIC_VALUE_TYPE_I: - metric_text += std::to_string(metric.value.i); - break; - default: + value_text = std::to_string(metric.value.i); break; } - metric_text += "\n"; - return metric_text; + return value_text; +} + +std::string prometheus_qualifier(std::string_view prometheus_namespace, std::string_view prometheus_subsystem) +{ + std::string qualifier; + if (!prometheus_namespace.empty()) + { + qualifier += std::string(prometheus_namespace) + "_"; + } + if (!prometheus_subsystem.empty()) + { + qualifier += std::string(prometheus_subsystem) + "_"; + } + return qualifier; +} + + +std::string prometheus_exposition_text(std::string_view metric_qualified_name, std::string_view metric_name, std::string_view metric_type_name, std::string_view metric_value, const std::map& const_labels) +{ + std::string fqn(metric_qualified_name); + std::string prometheus_text = "# HELP " + fqn + " https://falco.org/docs/metrics/\n"; + prometheus_text += "# TYPE " + fqn + " " + std::string(metric_type_name) + "\n"; + prometheus_text += fqn; + prometheus_text += "{raw_name=\"" + std::string(metric_name) + "\"" ; + for (const auto& [key, value] : const_labels) + { + prometheus_text += "," + key + "=\"" + value + "\"" ; + } + prometheus_text += "} "; // white space at the end important! + prometheus_text += std::string(metric_value); + prometheus_text += "\n"; + return prometheus_text; +} + +std::string metrics_converter::convert_metric_to_text(const metrics_v2& metric) const +{ + return std::string(metric.name) + " " + metric_value_to_text(metric) + "\n"; } -void metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) const +void metrics_converter::convert_metric_to_unit_convention(metrics_v2& /*metric*/) const { - return; + // Default does nothing } void output_rule_metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) const { - if(metric.unit == METRIC_VALUE_UNIT_MEMORY_BYTES || metric.unit == METRIC_VALUE_UNIT_MEMORY_KIBIBYTES) + if((metric.unit == METRIC_VALUE_UNIT_MEMORY_BYTES || metric.unit == METRIC_VALUE_UNIT_MEMORY_KIBIBYTES) && + (metric.type == METRIC_VALUE_TYPE_U32 || metric.type == METRIC_VALUE_TYPE_U64)) { if(metric.type == METRIC_VALUE_TYPE_U32) { metric.value.d = libs::metrics::convert_memory(metric.unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, metric.value.u32); - std::string metric_name_str(metric.name); - RE2::GlobalReplace(&metric_name_str, s_libs_metrics_units_memory_suffix, "_mb"); - strlcpy(metric.name, metric_name_str.c_str(), METRIC_NAME_MAX); - metric.type = METRIC_VALUE_TYPE_D; - metric.unit = METRIC_VALUE_UNIT_MEMORY_MEGABYTES; } else if(metric.type == METRIC_VALUE_TYPE_U64) { metric.value.d = libs::metrics::convert_memory(metric.unit, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, metric.value.u64); - std::string metric_name_str(metric.name); - RE2::GlobalReplace(&metric_name_str, s_libs_metrics_units_memory_suffix, "_mb"); - strlcpy(metric.name, metric_name_str.c_str(), METRIC_NAME_MAX); - metric.type = METRIC_VALUE_TYPE_D; - metric.unit = METRIC_VALUE_UNIT_MEMORY_MEGABYTES; } + std::string metric_name_str(metric.name); + RE2::GlobalReplace(&metric_name_str, s_libs_metrics_units_memory_suffix, "_mb"); + strlcpy(metric.name, metric_name_str.c_str(), METRIC_NAME_MAX); + metric.type = METRIC_VALUE_TYPE_D; + metric.unit = METRIC_VALUE_UNIT_MEMORY_MEGABYTES; } } std::string prometheus_metrics_converter::convert_metric_to_text_prometheus(const metrics_v2& metric, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, const std::map& const_labels) const { - // Create `prometheus_metric_name_fully_qualified` - std::string prometheus_metric_name_fully_qualified; - if (!prometheus_namespace.empty()) - { - prometheus_metric_name_fully_qualified += std::string(prometheus_namespace) + "_"; - } - if (!prometheus_subsystem.empty()) - { - prometheus_metric_name_fully_qualified += std::string(prometheus_subsystem) + "_"; - } - prometheus_metric_name_fully_qualified += std::string(metric.name) + "_"; + std::string prometheus_metric_name_fully_qualified = prometheus_qualifier(prometheus_namespace, prometheus_subsystem) + std::string(metric.name) + "_"; // Remove native libs unit suffixes if applicable. RE2::GlobalReplace(&prometheus_metric_name_fully_qualified, s_libs_metrics_units_suffix_pre_prometheus_text_conversion, ""); RE2::GlobalReplace(&prometheus_metric_name_fully_qualified, s_libs_metrics_banned_prometheus_naming_characters, "_"); prometheus_metric_name_fully_qualified += std::string(metrics_unit_name_mappings_prometheus[metric.unit]); - - // Create the complete 3-lines text-based Prometheus exposition format https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md - std::string prometheus_text = "# HELP " + prometheus_metric_name_fully_qualified + " https://falco.org/docs/metrics/\n"; - prometheus_text += "# TYPE " + prometheus_metric_name_fully_qualified + " " + std::string(metrics_metric_type_name_mappings_prometheus[metric.metric_type]) + "\n"; - prometheus_text += prometheus_metric_name_fully_qualified; - prometheus_text += "{raw_name=\"" + std::string(metric.name) + "\"" ; - for (const auto& [key, value] : const_labels) - { - prometheus_text += "," + key + "=\"" + value + "\"" ; - } - prometheus_text += "} "; // 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 += "\n"; - return prometheus_text; + return prometheus_exposition_text(prometheus_metric_name_fully_qualified, + metric.name, + metrics_metric_type_name_mappings_prometheus[metric.metric_type], + metric_value_to_text(metric), + const_labels); } std::string prometheus_metrics_converter::convert_metric_to_text_prometheus(std::string_view metric_name, std::string_view prometheus_namespace, std::string_view prometheus_subsystem, const std::map& const_labels) const { - // Create `prometheus_metric_name_fully_qualified` - std::string prometheus_metric_name_fully_qualified; - if (!prometheus_namespace.empty()) - { - prometheus_metric_name_fully_qualified += std::string(prometheus_namespace) + "_"; - } - if (!prometheus_subsystem.empty()) - { - prometheus_metric_name_fully_qualified += std::string(prometheus_subsystem) + "_"; - } - prometheus_metric_name_fully_qualified += std::string(metric_name) + "_info"; - - // Create the complete 3-lines text-based Prometheus exposition format https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md - std::string prometheus_text = "# HELP " + prometheus_metric_name_fully_qualified + " https://falco.org/docs/metrics/\n"; - prometheus_text += "# TYPE " + prometheus_metric_name_fully_qualified + " gauge\n"; - prometheus_text += prometheus_metric_name_fully_qualified; - prometheus_text += "{raw_name=\"" + std::string(metric_name) + "\"" ; - for (const auto& [key, value] : const_labels) - { - prometheus_text += "," + key + "=\"" + value + "\"" ; - } - prometheus_text += "} 1\n"; - return prometheus_text; + return prometheus_exposition_text(prometheus_qualifier(prometheus_namespace, prometheus_subsystem) + std::string(metric_name) + "_info", + metric_name, + "gauge", + "1", + const_labels); } void prometheus_metrics_converter::convert_metric_to_unit_convention(metrics_v2& metric) const { - if(metric.unit == METRIC_VALUE_UNIT_MEMORY_BYTES || metric.unit == METRIC_VALUE_UNIT_MEMORY_KIBIBYTES) + if((metric.unit == METRIC_VALUE_UNIT_MEMORY_BYTES || metric.unit == METRIC_VALUE_UNIT_MEMORY_KIBIBYTES) && + (metric.type == METRIC_VALUE_TYPE_U32 || metric.type == METRIC_VALUE_TYPE_U64)) { if(metric.type == METRIC_VALUE_TYPE_U32) { metric.value.d = libs::metrics::convert_memory(metric.unit, METRIC_VALUE_UNIT_MEMORY_BYTES, metric.value.u32); - std::string metric_name_str(metric.name); - RE2::GlobalReplace(&metric_name_str, s_libs_metrics_units_memory_suffix, "_bytes"); - strlcpy(metric.name, metric_name_str.c_str(), METRIC_NAME_MAX); - metric.type = METRIC_VALUE_TYPE_D; - metric.unit = METRIC_VALUE_UNIT_MEMORY_BYTES; } else if(metric.type == METRIC_VALUE_TYPE_U64) { metric.value.d = libs::metrics::convert_memory(metric.unit, METRIC_VALUE_UNIT_MEMORY_BYTES, metric.value.u64); - std::string metric_name_str(metric.name); - RE2::GlobalReplace(&metric_name_str, s_libs_metrics_units_memory_suffix, "_bytes"); - strlcpy(metric.name, metric_name_str.c_str(), METRIC_NAME_MAX); - metric.type = METRIC_VALUE_TYPE_D; - metric.unit = METRIC_VALUE_UNIT_MEMORY_BYTES; } + std::string metric_name_str(metric.name); + RE2::GlobalReplace(&metric_name_str, s_libs_metrics_units_memory_suffix, "_bytes"); + strlcpy(metric.name, metric_name_str.c_str(), METRIC_NAME_MAX); + metric.type = METRIC_VALUE_TYPE_D; + metric.unit = METRIC_VALUE_UNIT_MEMORY_BYTES; } else if(metric.unit == METRIC_VALUE_UNIT_PERC && metric.type == METRIC_VALUE_TYPE_D) { From 2c3092e194d17682c359d9a807fb97b351418ac0 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Wed, 13 Mar 2024 00:28:05 +0000 Subject: [PATCH 22/22] cleanup(metrics): apply reviewers suggestions Co-authored-by: Federico Di Pierro Signed-off-by: Melissa Kilby --- userspace/libpman/src/stats.c | 9 ++- userspace/libscap/engine/bpf/scap_bpf.c | 9 ++- .../libscap/engine/gvisor/scap_gvisor.cpp | 2 +- userspace/libscap/engine/kmod/scap_kmod.c | 2 +- .../engine/source_plugin/source_plugin.c | 2 +- userspace/libscap/metrics_v2.h | 7 +- userspace/libsinsp/metrics_collector.cpp | 74 +++++++++++-------- userspace/libsinsp/test/sinsp_metrics.ut.cpp | 16 ++-- 8 files changed, 70 insertions(+), 51 deletions(-) diff --git a/userspace/libpman/src/stats.c b/userspace/libpman/src/stats.c index 5f5b150322..815de86b90 100644 --- a/userspace/libpman/src/stats.c +++ b/userspace/libpman/src/stats.c @@ -175,7 +175,7 @@ struct metrics_v2 *pman_get_metrics_v2(uint32_t flags, uint32_t *nstats, int32_t g_state.stats[stat].type = METRIC_VALUE_TYPE_U64; g_state.stats[stat].flags = METRICS_V2_KERNEL_COUNTERS; g_state.stats[stat].unit = METRIC_VALUE_UNIT_COUNT; - g_state.stats[stat].metric_type = METRIC_VALUE_MONOTONIC; + g_state.stats[stat].metric_type = METRIC_VALUE_METRIC_TYPE_MONOTONIC; g_state.stats[stat].value.u64 = 0; strlcpy(g_state.stats[stat].name, modern_bpf_kernel_counters_stats_names[stat], METRIC_NAME_MAX); } @@ -258,19 +258,19 @@ struct metrics_v2 *pman_get_metrics_v2(uint32_t flags, uint32_t *nstats, int32_t strlcat(g_state.stats[offset].name, modern_bpf_libbpf_stats_names[RUN_CNT], sizeof(g_state.stats[offset].name)); g_state.stats[stat].flags = METRICS_V2_KERNEL_COUNTERS; g_state.stats[stat].unit = METRIC_VALUE_UNIT_COUNT; - g_state.stats[stat].metric_type = METRIC_VALUE_MONOTONIC; + g_state.stats[stat].metric_type = METRIC_VALUE_METRIC_TYPE_MONOTONIC; g_state.stats[offset].value.u64 = info.run_cnt; break; case RUN_TIME_NS: strlcat(g_state.stats[offset].name, modern_bpf_libbpf_stats_names[RUN_TIME_NS], sizeof(g_state.stats[offset].name)); g_state.stats[stat].unit = METRIC_VALUE_UNIT_TIME_NS_COUNT; - g_state.stats[stat].metric_type = METRIC_VALUE_MONOTONIC; + g_state.stats[stat].metric_type = METRIC_VALUE_METRIC_TYPE_MONOTONIC; g_state.stats[offset].value.u64 = info.run_time_ns; break; case AVG_TIME_NS: strlcat(g_state.stats[offset].name, modern_bpf_libbpf_stats_names[AVG_TIME_NS], sizeof(g_state.stats[offset].name)); g_state.stats[stat].unit = METRIC_VALUE_UNIT_TIME_NS; - g_state.stats[stat].metric_type = METRIC_VALUE_NON_MONOTONIC_CURRENT; + g_state.stats[stat].metric_type = METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT; g_state.stats[offset].value.u64 = 0; if(info.run_cnt > 0) { @@ -278,6 +278,7 @@ struct metrics_v2 *pman_get_metrics_v2(uint32_t flags, uint32_t *nstats, int32_t } break; default: + ASSERT(false); break; } offset++; diff --git a/userspace/libscap/engine/bpf/scap_bpf.c b/userspace/libscap/engine/bpf/scap_bpf.c index 8995205cc3..60d794f39e 100644 --- a/userspace/libscap/engine/bpf/scap_bpf.c +++ b/userspace/libscap/engine/bpf/scap_bpf.c @@ -1731,7 +1731,7 @@ const struct metrics_v2* scap_bpf_get_stats_v2(struct scap_engine_handle engine, { stats[stat].type = METRIC_VALUE_TYPE_U64; stats[stat].flags = METRICS_V2_KERNEL_COUNTERS; - stats[stat].metric_type = METRIC_VALUE_MONOTONIC; + stats[stat].metric_type = METRIC_VALUE_METRIC_TYPE_MONOTONIC; stats[stat].unit = METRIC_VALUE_UNIT_COUNT; stats[stat].value.u64 = 0; strlcpy(stats[stat].name, bpf_kernel_counters_stats_names[stat], METRIC_NAME_MAX); @@ -1828,25 +1828,26 @@ const struct metrics_v2* scap_bpf_get_stats_v2(struct scap_engine_handle engine, strlcat(stats[offset].name, bpf_libbpf_stats_names[RUN_CNT], sizeof(stats[offset].name)); stats[offset].value.u64 = info.run_cnt; stats[offset].unit = METRIC_VALUE_UNIT_COUNT; - stats[offset].metric_type = METRIC_VALUE_MONOTONIC; + stats[offset].metric_type = METRIC_VALUE_METRIC_TYPE_MONOTONIC; break; case RUN_TIME_NS: strlcat(stats[offset].name, bpf_libbpf_stats_names[RUN_TIME_NS], sizeof(stats[offset].name)); stats[offset].value.u64 = info.run_time_ns; stats[offset].unit = METRIC_VALUE_UNIT_TIME_NS_COUNT; - stats[offset].metric_type = METRIC_VALUE_MONOTONIC; + stats[offset].metric_type = METRIC_VALUE_METRIC_TYPE_MONOTONIC; break; case AVG_TIME_NS: strlcat(stats[offset].name, bpf_libbpf_stats_names[AVG_TIME_NS], sizeof(stats[offset].name)); stats[offset].value.u64 = 0; stats[offset].unit = METRIC_VALUE_UNIT_TIME_NS; - stats[offset].metric_type = METRIC_VALUE_NON_MONOTONIC_CURRENT; + stats[offset].metric_type = METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT; if (info.run_cnt > 0) { stats[offset].value.u64 = info.run_time_ns / info.run_cnt; } break; default: + ASSERT(false); break; } offset++; diff --git a/userspace/libscap/engine/gvisor/scap_gvisor.cpp b/userspace/libscap/engine/gvisor/scap_gvisor.cpp index 5f89ebf093..19919f858d 100644 --- a/userspace/libscap/engine/gvisor/scap_gvisor.cpp +++ b/userspace/libscap/engine/gvisor/scap_gvisor.cpp @@ -434,7 +434,7 @@ const metrics_v2* engine::get_stats_v2(uint32_t flags, uint32_t* nstats, int32_t { stats[stat].type = METRIC_VALUE_TYPE_U64; stats[stat].unit = METRIC_VALUE_UNIT_COUNT; - stats[stat].metric_type = METRIC_VALUE_MONOTONIC; + stats[stat].metric_type = METRIC_VALUE_METRIC_TYPE_MONOTONIC; stats[stat].value.u64 = 0; strlcpy(stats[stat].name, gvisor_counters_stats_names[stat], METRIC_NAME_MAX); } diff --git a/userspace/libscap/engine/kmod/scap_kmod.c b/userspace/libscap/engine/kmod/scap_kmod.c index 136727efb7..aa2cdde46a 100644 --- a/userspace/libscap/engine/kmod/scap_kmod.c +++ b/userspace/libscap/engine/kmod/scap_kmod.c @@ -600,7 +600,7 @@ const struct metrics_v2* scap_kmod_get_stats_v2(struct scap_engine_handle engine stats[stat].type = METRIC_VALUE_TYPE_U64; stats[stat].flags = METRICS_V2_KERNEL_COUNTERS; stats[stat].unit = METRIC_VALUE_UNIT_COUNT; - stats[stat].metric_type = METRIC_VALUE_MONOTONIC; + stats[stat].metric_type = METRIC_VALUE_METRIC_TYPE_MONOTONIC; stats[stat].value.u64 = 0; strlcpy(stats[stat].name, kmod_kernel_counters_stats_names[stat], METRIC_NAME_MAX); } diff --git a/userspace/libscap/engine/source_plugin/source_plugin.c b/userspace/libscap/engine/source_plugin/source_plugin.c index 5853371ef4..760c7645fb 100644 --- a/userspace/libscap/engine/source_plugin/source_plugin.c +++ b/userspace/libscap/engine/source_plugin/source_plugin.c @@ -292,7 +292,7 @@ const struct metrics_v2* get_source_plugin_stats_v2(struct scap_engine_handle en stats[stat].type = METRIC_VALUE_TYPE_U64; stats[stat].value.u64 = 0; stats[stat].unit = METRIC_VALUE_UNIT_COUNT; - stats[stat].metric_type = METRIC_VALUE_MONOTONIC; + stats[stat].metric_type = METRIC_VALUE_METRIC_TYPE_MONOTONIC; strlcpy(stats[stat].name, source_plugin_counters_stats_names[stat], METRIC_NAME_MAX); } stats[N_EVTS].value.u64 = handle->m_nevts; diff --git a/userspace/libscap/metrics_v2.h b/userspace/libscap/metrics_v2.h index 6088a0a897..10f17b1958 100644 --- a/userspace/libscap/metrics_v2.h +++ b/userspace/libscap/metrics_v2.h @@ -58,6 +58,7 @@ typedef enum metrics_v2_value_type{ METRIC_VALUE_TYPE_D, METRIC_VALUE_TYPE_F, METRIC_VALUE_TYPE_I, + METRIC_VALUE_TYPE_MAX, } metrics_v2_value_type; typedef enum metrics_v2_value_unit{ @@ -72,11 +73,13 @@ typedef enum metrics_v2_value_unit{ METRIC_VALUE_UNIT_TIME_NS_COUNT, METRIC_VALUE_UNIT_TIME_S_COUNT, METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS, + METRIC_VALUE_UNIT_MAX, } metrics_v2_value_unit; typedef enum metrics_v2_metric_type{ - METRIC_VALUE_MONOTONIC, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_MAX, } metrics_v2_metric_type; /*! diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index 413c050bf6..bacce9435b 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -61,6 +61,8 @@ static const char *const sinsp_stats_v2_resource_utilization_names[] = { [SINSP_STATS_V2_N_CONTAINERS] = "n_containers", }; +static_assert(sizeof(sinsp_stats_v2_resource_utilization_names) / sizeof(sinsp_stats_v2_resource_utilization_names[0]) == SINSP_MAX_STATS_V2, "sinsp_stats_v2_resource_utilization_names array size does not match expected size"); + // For simplicity, needs to stay in sync w/ typedef enum metrics_v2_value_unit // https://prometheus.io/docs/practices/naming/ or https://prometheus.io/docs/practices/naming/#base-units. static const char *const metrics_unit_name_mappings_prometheus[] = { @@ -77,11 +79,13 @@ static const char *const metrics_unit_name_mappings_prometheus[] = { [METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS] = "timestamp_nanoseconds", }; +static_assert(sizeof(metrics_unit_name_mappings_prometheus) / sizeof(metrics_unit_name_mappings_prometheus[0]) == METRIC_VALUE_UNIT_MAX, "metrics_unit_name_mappings_prometheus array size does not match expected size"); + // For simplicity, needs to stay in sync w/ typedef enum metrics_v2_metric_type // https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md static const char *const metrics_metric_type_name_mappings_prometheus[] = { - [METRIC_VALUE_MONOTONIC] = "counter", - [METRIC_VALUE_NON_MONOTONIC_CURRENT] = "gauge", + [METRIC_VALUE_METRIC_TYPE_MONOTONIC] = "counter", + [METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT] = "gauge", }; namespace libs::metrics { @@ -112,6 +116,8 @@ std::string metric_value_to_text(const metrics_v2& metric) case METRIC_VALUE_TYPE_I: value_text = std::to_string(metric.value.i); break; + default: + break; } return value_text; } @@ -242,6 +248,7 @@ void libs_metrics_collector::get_rss_vsz_pss_total_memory_and_open_fds(uint32_t * Get memory usage of the agent itself (referred to as calling process meaning /proc/self/) */ + // No need for scap_get_host_root since we look at the agents' own process, accessible from it's own pid namespace (if applicable) f = fopen("/proc/self/status", "r"); if(!f) { @@ -262,6 +269,7 @@ void libs_metrics_collector::get_rss_vsz_pss_total_memory_and_open_fds(uint32_t } fclose(f); + // No need for scap_get_host_root since we look at the agents' own process, accessible from it's own pid namespace (if applicable) f = fopen("/proc/self/smaps_rollup", "r"); if(!f) { @@ -283,6 +291,7 @@ void libs_metrics_collector::get_rss_vsz_pss_total_memory_and_open_fds(uint32_t * Get total host memory usage */ + // Using scap_get_host_root since we look at the memory usage of the underlying host snprintf(filepath, sizeof(filepath), "%s/proc/meminfo", scap_get_host_root()); f = fopen(filepath, "r"); if(!f) @@ -320,6 +329,7 @@ void libs_metrics_collector::get_rss_vsz_pss_total_memory_and_open_fds(uint32_t * File descriptor is a data structure used by a program to get a handle on a file */ + // Using scap_get_host_root since we look at the total open fds of the underlying host snprintf(filepath, sizeof(filepath), "%s/proc/sys/fs/file-nr", scap_get_host_root()); f = fopen(filepath, "r"); if(!f) @@ -361,6 +371,7 @@ void libs_metrics_collector::get_cpu_usage_and_total_procs(double start_time, do * /proc/uptime offers higher precision w/ 2 decimals. */ + // Using scap_get_host_root since we look at the uptime of the underlying host snprintf(filepath, sizeof(filepath), "%s/proc/uptime", scap_get_host_root()); f = fopen(filepath, "r"); if(!f) @@ -402,6 +413,7 @@ void libs_metrics_collector::get_cpu_usage_and_total_procs(double start_time, do * Get total host CPU usage (all CPUs) as percentage and retrieve number of procs currently running. */ + // Using scap_get_host_root since we look at the total CPU usage of the underlying host snprintf(filepath, sizeof(filepath), "%s/proc/stat", scap_get_host_root()); f = fopen(filepath, "r"); if(!f) @@ -447,6 +459,8 @@ uint64_t libs_metrics_collector::get_container_memory_used() const const char* filepath = getenv(SINSP_AGENT_CGROUP_MEM_PATH_ENV_VAR); if (filepath == nullptr) { + // No need for scap_get_host_root since we look at the container pid namespace (if applicable) + // Known collison for VM memory usage, but this default value is configurable filepath = "/sys/fs/cgroup/memory/memory.usage_in_bytes"; } @@ -511,35 +525,35 @@ void libs_metrics_collector::snapshot() METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_D, METRIC_VALUE_UNIT_PERC, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, cpu_usage_perc)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_RSS], METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, rss)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_VSZ], METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, vsz)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_MEMORY_PSS], METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, pss)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_CONTAINER_MEMORY], METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_MEMORY_BYTES, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, container_memory_used)); // Resource utilization / load indicators of the underlying host @@ -547,28 +561,28 @@ void libs_metrics_collector::snapshot() METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_D, METRIC_VALUE_UNIT_PERC, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, host_cpu_usage_perc)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_HOST_PROCS], METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, host_procs_running)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_HOST_MEMORY], METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, host_memory_used)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_RESOURCE_UTILIZATION_HOST_FDS], METRICS_V2_RESOURCE_UTILIZATION, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, host_open_fds)); } @@ -609,132 +623,132 @@ void libs_metrics_collector::snapshot() METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, n_threads)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_FDS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, n_fds)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_FD_LOOKUPS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_noncached_fd_lookups)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_FD_LOOKUPS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_cached_fd_lookups)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_FD_LOOKUPS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_failed_fd_lookups)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_FDS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_added_fds)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_FDS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_removed_fds)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORED_EVTS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_stored_evts)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_STORE_EVTS_DROPS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_store_evts_drops)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVED_EVTS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_retrieved_evts)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_RETRIEVE_EVTS_DROPS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_retrieve_evts_drops)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_NONCACHED_THREAD_LOOKUPS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_noncached_thread_lookups)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_CACHED_THREAD_LOOKUPS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_cached_thread_lookups)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_FAILED_THREAD_LOOKUPS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_failed_thread_lookups)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_ADDED_THREADS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_added_threads)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_REMOVED_THREADS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_removed_threads)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_DROPS_FULL_THREADTABLE], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, sinsp_stats_v2->m_n_drops_full_threadtable)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_MISSING_CONTAINER_IMAGES], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, sinsp_stats_v2->m_n_missing_container_images)); m_metrics.emplace_back(new_metric(sinsp_stats_v2_resource_utilization_names[SINSP_STATS_V2_N_CONTAINERS], METRICS_V2_STATE_COUNTERS, METRIC_VALUE_TYPE_U32, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, sinsp_stats_v2->m_n_containers)); } } diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index 7adfeac109..049b9a67eb 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -133,35 +133,35 @@ testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7 METRICS_V2_LIBBPF_STATS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, 76435525241UL)); fake_metrics_snapshot.emplace_back(libs_metrics_collector.new_metric("sys_enter.run_time_ns", METRICS_V2_LIBBPF_STATS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_TIME_NS_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, 16269369826392UL)); fake_metrics_snapshot.emplace_back(libs_metrics_collector.new_metric("sys_enter.avg_time_ns", METRICS_V2_LIBBPF_STATS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_TIME_NS, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, 203UL)); fake_metrics_snapshot.emplace_back(libs_metrics_collector.new_metric("n_drops", METRICS_V2_KERNEL_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, 674200UL)); fake_metrics_snapshot.emplace_back(libs_metrics_collector.new_metric("n_drops_buffer_total", METRICS_V2_KERNEL_COUNTERS, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, 5000UL)); // Simulate some derived metrics; critical for example for Falco consumer use cases @@ -169,14 +169,14 @@ testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7 METRICS_V2_MISC, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_TIME_S_COUNT, - METRIC_VALUE_MONOTONIC, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, 144UL)); fake_metrics_snapshot.emplace_back(libs_metrics_collector.new_metric("evt_rate_sec", METRICS_V2_MISC, METRIC_VALUE_TYPE_D, METRIC_VALUE_UNIT_TIME_S, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, 126065.4)); // Timestamps while they always go up should still be regarded as gauge from a Prometheus perspective @@ -185,7 +185,7 @@ testns_falco_kernel_release_info{raw_name="kernel_release",kernel_release="6.6.7 METRICS_V2_MISC, METRIC_VALUE_TYPE_U64, METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS, - METRIC_VALUE_NON_MONOTONIC_CURRENT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, 1708753667000000000UL)); for (auto& metric: fake_metrics_snapshot)