From cd54b8915594cb2d09d118e9e99aca6035e0702a Mon Sep 17 00:00:00 2001 From: Gianmatteo Palmieri Date: Mon, 1 Jul 2024 16:44:51 +0200 Subject: [PATCH] refactor(libscap): move linux metrics collection logic to scap platform Signed-off-by: Gianmatteo Palmieri --- userspace/libscap/CMakeLists.txt | 4 + userspace/libscap/linux/scap_linux_platform.c | 243 ++++++++++++++++ userspace/libscap/scap_platform.c | 29 ++ userspace/libscap/scap_platform_impl.h | 9 + userspace/libsinsp/CMakeLists.txt | 5 - userspace/libsinsp/metrics_collector.cpp | 271 ++---------------- userspace/libsinsp/metrics_collector.h | 15 +- userspace/libsinsp/test/plugins.ut.cpp | 5 - userspace/libsinsp/test/sinsp_metrics.ut.cpp | 14 +- 9 files changed, 307 insertions(+), 288 deletions(-) diff --git a/userspace/libscap/CMakeLists.txt b/userspace/libscap/CMakeLists.txt index 604a6cfa6d..cda72c6fad 100644 --- a/userspace/libscap/CMakeLists.txt +++ b/userspace/libscap/CMakeLists.txt @@ -55,6 +55,10 @@ if (DEFINED SCAP_BPF_PROGS_TAIL_CALLED_MAX) add_definitions(-DBPF_PROGS_TAIL_CALLED_MAX=${SCAP_BPF_PROGS_TAIL_CALLED_MAX}) endif() +if(NOT DEFINED SCAP_AGENT_CGROUP_MEM_PATH_ENV_VAR) + set(SCAP_AGENT_CGROUP_MEM_PATH_ENV_VAR "AGENT_CGROUP_MEM_PATH") +endif() +add_definitions(-DSCAP_AGENT_CGROUP_MEM_PATH_ENV_VAR="${SCAP_AGENT_CGROUP_MEM_PATH_ENV_VAR}") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scap_strl_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/scap_strl_config.h) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scap_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/scap_config.h) diff --git a/userspace/libscap/linux/scap_linux_platform.c b/userspace/libscap/linux/scap_linux_platform.c index 80b70ae734..db148b47a2 100644 --- a/userspace/libscap/linux/scap_linux_platform.c +++ b/userspace/libscap/linux/scap_linux_platform.c @@ -30,7 +30,9 @@ limitations under the License. #include #include #include +#include #include +#include static int32_t scap_linux_close_platform(struct scap_platform* platform) { @@ -121,6 +123,246 @@ static const struct scap_platform_vtable scap_linux_platform_vtable = { .free_platform = scap_linux_free_platform, }; +static void scap_linux_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]; + char line[512]; + + /* + * 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) + { + 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); + + // 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) + { + 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 + */ + + // 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) + { + 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); + *host_memory_used = 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 + */ + + // 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) + { + return; + } + int matched_fds = fscanf(f, "%" SCNu64, host_open_fds); + fclose(f); + + if (matched_fds != 1) { + return; + } +} + +static void scap_linux_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]; + 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) + { + hz = 100; + } +#endif + /* Current uptime of the host machine in seconds. + * /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) + { + return; + } + + double machine_uptime_sec = 0; + int matched_uptime = fscanf(f, "%lf", &machine_uptime_sec); + fclose(f); + + if (matched_uptime != 1) { + 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 = 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. + */ + + // 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) + { + 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, host_procs_running); + break; + } + } + fclose(f); + uint64_t sum = user + nice + system + idle + iowait + irq + softirq; + if (sum > 0) + { + *host_cpu_usage_perc = 100.0 - ((idle * 100.0) / sum); + *host_cpu_usage_perc = round(*host_cpu_usage_perc * 10.0) / 10.0; // round to 1 decimal + } +} + +static void scap_linux_get_container_memory_used(uint64_t *container_memory_used) +{ + /* 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. + */ + const char* filepath = getenv(SCAP_AGENT_CGROUP_MEM_PATH_ENV_VAR); + if (filepath == NULL) + { + // No need for scap_get_host_root since we look at the container pid namespace (if applicable) + // Known collision for VM memory usage, but this default value is configurable + filepath = "/sys/fs/cgroup/memory/memory.usage_in_bytes"; + } + + FILE* f = fopen(filepath, "r"); + if(!f) + { + return; + } + + /* memory size returned in bytes */ + int fscanf_matched = fscanf(f, "%" SCNu64, container_memory_used); + if (fscanf_matched != 1) + { + *container_memory_used = 0; + } + + fclose(f); + + return; +} + +struct scap_metrics_vtable scap_linux_metrics_vtable = { + .get_rss_vsz_pss_total_memory_and_open_fds = scap_linux_get_rss_vsz_pss_total_memory_and_open_fds, + .get_cpu_usage_and_total_procs = scap_linux_get_cpu_usage_and_total_procs, + .get_container_memory_used = scap_linux_get_container_memory_used, +}; + struct scap_platform* scap_linux_alloc_platform(proc_entry_callback proc_callback, void* proc_callback_context) { struct scap_linux_platform* platform = calloc(1, sizeof(*platform)); @@ -132,6 +374,7 @@ struct scap_platform* scap_linux_alloc_platform(proc_entry_callback proc_callbac struct scap_platform* generic = &platform->m_generic; generic->m_vtable = &scap_linux_platform_vtable; + generic->m_metrics_vtable = &scap_linux_metrics_vtable; init_proclist(&generic->m_proclist, proc_callback, proc_callback_context); diff --git a/userspace/libscap/scap_platform.c b/userspace/libscap/scap_platform.c index 410d56a075..507a0903a5 100644 --- a/userspace/libscap/scap_platform.c +++ b/userspace/libscap/scap_platform.c @@ -70,6 +70,34 @@ struct scap_platform_vtable scap_generic_platform_vtable = { .free_platform = scap_generic_free_platform, }; +static void scap_generic_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) +{ + *rss = 0; + *vsz = 0; + *pss = 0; + *host_memory_used = 0; + *host_open_fds = 0; +} + +static void scap_generic_get_cpu_usage_and_total_procs(double start_time, double *cpu_usage_perc, double *host_cpu_usage_perc, uint32_t *host_procs_running) +{ + *cpu_usage_perc = 0; + *host_cpu_usage_perc = 0; + *host_procs_running = 0; +} + +static void scap_generic_get_container_memory_used(uint64_t *container_memory_used) +{ + *container_memory_used = 0; + return; +} + +struct scap_metrics_vtable scap_generic_metrics_vtable = { + .get_rss_vsz_pss_total_memory_and_open_fds = scap_generic_get_rss_vsz_pss_total_memory_and_open_fds, + .get_cpu_usage_and_total_procs = scap_generic_get_cpu_usage_and_total_procs, + .get_container_memory_used = scap_generic_get_container_memory_used, +}; + struct scap_platform* scap_generic_alloc_platform(proc_entry_callback proc_callback, void* proc_callback_context) { struct scap_platform* platform = calloc(1, sizeof(*platform)); @@ -80,6 +108,7 @@ struct scap_platform* scap_generic_alloc_platform(proc_entry_callback proc_callb } platform->m_vtable = &scap_generic_platform_vtable; + platform->m_metrics_vtable = &scap_generic_metrics_vtable; init_proclist(&platform->m_proclist, proc_callback, proc_callback_context); diff --git a/userspace/libscap/scap_platform_impl.h b/userspace/libscap/scap_platform_impl.h index 402ebdd51d..a69c7fe447 100644 --- a/userspace/libscap/scap_platform_impl.h +++ b/userspace/libscap/scap_platform_impl.h @@ -76,6 +76,13 @@ struct scap_platform_vtable void (*free_platform)(struct scap_platform* platform); }; +struct scap_metrics_vtable +{ + 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); + void (*get_container_memory_used)(uint64_t *container_memory_used); +}; + // the parts of the platform struct shared across all implementations // this *must* be the first member of all implementations // (the pointers are cast back&forth between the two) @@ -89,6 +96,8 @@ struct scap_platform scap_agent_info m_agent_info; scap_machine_info m_machine_info; struct ppm_proclist_info* m_driver_procinfo; + + const struct scap_metrics_vtable* m_metrics_vtable; }; #ifdef __cplusplus diff --git a/userspace/libsinsp/CMakeLists.txt b/userspace/libsinsp/CMakeLists.txt index 5d9ebacd9b..1578dd51a7 100644 --- a/userspace/libsinsp/CMakeLists.txt +++ b/userspace/libsinsp/CMakeLists.txt @@ -301,11 +301,6 @@ if (BUILD_LIBSINSP_EXAMPLES) add_subdirectory(sinsp_debug) endif() -if(NOT DEFINED SINSP_AGENT_CGROUP_MEM_PATH_ENV_VAR) - set(SINSP_AGENT_CGROUP_MEM_PATH_ENV_VAR "AGENT_CGROUP_MEM_PATH") -endif() -add_definitions(-DSINSP_AGENT_CGROUP_MEM_PATH_ENV_VAR="${SINSP_AGENT_CGROUP_MEM_PATH_ENV_VAR}") - # Build our pkg-config "Libs:" flags. For now, loop over SINSP_PKGCONFIG_LIBRARIES. If # we ever start using pkg_search_module or pkg_check_modules in cmake/modules # we could add each module to our "Requires:" line instead. We might need to diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index f8872f61d1..d85eaca616 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -16,8 +16,6 @@ limitations under the License. */ -#ifdef __linux__ - #include #include #include @@ -34,17 +32,17 @@ static re2::RE2 s_libs_metrics_banned_prometheus_naming_characters("(\\.)", re2: // 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[] = { - [METRIC_VALUE_UNIT_COUNT] = "total", - [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_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", + "total", + "ratio", + "percentage", + "bytes", + "kibibytes", + "megabytes", + "nanoseconds", + "seconds", + "nanoseconds_total", + "seconds_total", + "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"); @@ -52,8 +50,8 @@ static_assert(sizeof(metrics_unit_name_mappings_prometheus) / sizeof(metrics_uni // 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_METRIC_TYPE_MONOTONIC] = "counter", - [METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT] = "gauge", + "counter", + "gauge", }; namespace libs::metrics { @@ -207,210 +205,15 @@ void prometheus_metrics_converter::convert_metric_to_unit_convention(metrics_v2& } } -void libs_resource_utilization::get_rss_vsz_pss_total_memory_and_open_fds() -{ - FILE* f; - char filepath[512]; - char line[512]; - - /* - * 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) - { - return; - } - - while(fgets(line, sizeof(line), f) != nullptr) - { - if(strncmp(line, "VmSize:", 7) == 0) - { - sscanf(line, "VmSize: %" SCNu32, &m_vsz); /* memory size returned in kb */ - } - else if(strncmp(line, "VmRSS:", 6) == 0) - { - sscanf(line, "VmRSS: %" SCNu32, &m_rss); /* memory size returned in kb */ - } - } - 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) - { - ASSERT(false); - return; - } - - while(fgets(line, sizeof(line), f) != NULL) - { - if(strncmp(line, "Pss:", 4) == 0) - { - sscanf(line, "Pss: %" SCNu32, &m_pss); /* memory size returned in kb */ - break; - } - } - fclose(f); - - /* - * 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) - { - 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); - m_host_memory_used = 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 - */ - - // 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) - { - ASSERT(false); - return; - } - int matched_fds = fscanf(f, "%" SCNu64, &m_host_open_fds); - fclose(f); - - if (matched_fds != 1) { - ASSERT(false); - return; - } -} - -void libs_resource_utilization::get_cpu_usage_and_total_procs(double start_time) +libs_resource_utilization::libs_resource_utilization(sinsp* inspector, double start_time) { - 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. - */ - - // 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) - { - 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) - { - m_cpu_usage_perc = (double)100.0 * (user_sec + system_sec) / elapsed_sec; - m_cpu_usage_perc = std::round(m_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. - */ + auto metrics_vtable = inspector->get_scap_platform()->m_metrics_vtable; - // 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) - { - 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, &m_host_procs_running); - break; - } - } - fclose(f); - auto sum = user + nice + system + idle + iowait + irq + softirq; - if (sum > 0) + if(metrics_vtable) { - m_host_cpu_usage_perc = 100.0 - ((idle * 100.0) / sum); - m_host_cpu_usage_perc = std::round(m_host_cpu_usage_perc * 10.0) / 10.0; // round to 1 decimal + metrics_vtable->get_rss_vsz_pss_total_memory_and_open_fds(&m_rss, &m_vsz, &m_pss, &m_host_memory_used, &m_host_open_fds); + metrics_vtable->get_cpu_usage_and_total_procs(start_time, &m_cpu_usage_perc, &m_host_cpu_usage_perc, &m_host_procs_running); + metrics_vtable->get_container_memory_used(&m_container_memory_used); } } @@ -475,39 +278,6 @@ std::vector libs_resource_utilization::to_metrics() return metrics; } -void libs_resource_utilization::get_container_memory_used() -{ - /* 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. - */ - 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 collision for VM memory usage, but this default value is configurable - filepath = "/sys/fs/cgroup/memory/memory.usage_in_bytes"; - } - - FILE* f = fopen(filepath, "r"); - if(!f) - { - return; - } - - /* memory size returned in bytes */ - int fscanf_matched = fscanf(f, "%" SCNu64, &m_container_memory_used); - if (fscanf_matched != 1) - { - m_container_memory_used = 0; - } - - fclose(f); -} - libs_state_counters::libs_state_counters(const std::shared_ptr& sinsp_stats_v2, sinsp_thread_manager* thread_manager) : m_sinsp_stats_v2(sinsp_stats_v2), m_n_fds(0), m_n_threads(0) { if (thread_manager != nullptr) { @@ -685,7 +455,7 @@ void libs_metrics_collector::snapshot() if((m_metrics_flags & METRICS_V2_RESOURCE_UTILIZATION)) { const scap_agent_info* agent_info = m_inspector->get_agent_info(); - libs_resource_utilization resource_utilization(agent_info->start_time); + libs_resource_utilization resource_utilization(m_inspector, agent_info->start_time); std::vector ru_metrics = resource_utilization.to_metrics(); m_metrics.insert(m_metrics.end(), ru_metrics.begin(), ru_metrics.end()); } @@ -736,4 +506,3 @@ libs_metrics_collector::libs_metrics_collector(sinsp* inspector, uint32_t flags) } // namespace libs::metrics -#endif diff --git a/userspace/libsinsp/metrics_collector.h b/userspace/libsinsp/metrics_collector.h index a5077c4c43..d7ccdc3dad 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -57,8 +57,6 @@ struct sinsp_stats_v2 uint32_t m_n_containers; ///< Number of containers (cgroups) currently cached by sinsp_container_manager, hijacked sinsp_container_manager::remove_inactive_containers() -> every flush snapshot update, unit: count. }; -#ifdef __linux__ - namespace libs::metrics { @@ -272,20 +270,11 @@ class libsinsp_metrics class libs_resource_utilization : libsinsp_metrics { public: - libs_resource_utilization(double start_time) - { - get_cpu_usage_and_total_procs(start_time); - get_rss_vsz_pss_total_memory_and_open_fds(); - get_container_memory_used(); - } + libs_resource_utilization(sinsp* inspector, double start_time); std::vector to_metrics() override; private: - void get_cpu_usage_and_total_procs(double start_time); - void get_rss_vsz_pss_total_memory_and_open_fds(); - void get_container_memory_used(); - double m_cpu_usage_perc{}; ///< Current CPU usage, `ps` util like calculation for the calling process (/proc/self), unit: percentage of one CPU. uint32_t m_rss{}; ///< Current RSS (Resident Set Size), calculated based on /proc/self/status info, unit: kb. @@ -358,5 +347,3 @@ class libs_metrics_collector }; } // namespace libs::metrics - -#endif diff --git a/userspace/libsinsp/test/plugins.ut.cpp b/userspace/libsinsp/test/plugins.ut.cpp index 1821ddc35d..0333818420 100644 --- a/userspace/libsinsp/test/plugins.ut.cpp +++ b/userspace/libsinsp/test/plugins.ut.cpp @@ -18,7 +18,6 @@ limitations under the License. #include #include -#include #include #include "test_utils.h" @@ -885,8 +884,6 @@ TEST(sinsp_plugin, plugin_set_config) libsinsp_logger()->remove_callback_log(); } -#ifdef __linux__ - TEST_F(sinsp_with_test_input, plugin_metrics) { uint32_t test_metrics_flags = (METRICS_V2_PLUGINS); @@ -918,5 +915,3 @@ TEST_F(sinsp_with_test_input, plugin_metrics) ASSERT_EQ(metrics_snapshot.back().value.u64, events); } - -#endif diff --git a/userspace/libsinsp/test/sinsp_metrics.ut.cpp b/userspace/libsinsp/test/sinsp_metrics.ut.cpp index cf5b38a68a..ad3f1ddf09 100644 --- a/userspace/libsinsp/test/sinsp_metrics.ut.cpp +++ b/userspace/libsinsp/test/sinsp_metrics.ut.cpp @@ -15,7 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -#ifdef __linux__ #include #include "sinsp_with_test_input.h" @@ -297,16 +296,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", 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 - ASSERT_LT(metric.value.d, 1000000); - success_memory_cnt++; - } else - { - success_memory_cnt++; - } + success_memory_cnt++; } if (std::find(metrics_names_values_gt.begin(), metrics_names_values_gt.end(), metric.name) != metrics_names_values_gt.end()) { @@ -372,5 +362,3 @@ TEST(sinsp_libs_metrics, sinsp_libs_metrics_convert_units) converted_memory = libs::metrics::convert_memory(METRIC_VALUE_UNIT_MEMORY_MEGABYTES, METRIC_VALUE_UNIT_MEMORY_MEGABYTES, (uint64_t)50); ASSERT_EQ(converted_memory, 50); } - -#endif