From 9e3fb93a363cf3d5d1a6521519269eee9738b84d Mon Sep 17 00:00:00 2001 From: Gianmatteo Palmieri Date: Wed, 2 Oct 2024 16:13:16 +0200 Subject: [PATCH] fix(libsinsp): enable metrics collector on all platforms Signed-off-by: Gianmatteo Palmieri --- userspace/libsinsp/CMakeLists.txt | 7 + .../libsinsp/linux/resource_utilization.cpp | 283 +++++++++++++++ .../libsinsp/linux/resource_utilization.h | 42 +++ userspace/libsinsp/metrics_collector.cpp | 323 ++---------------- userspace/libsinsp/metrics_collector.h | 48 +-- userspace/libsinsp/test/plugins.ut.cpp | 4 - userspace/libsinsp/threadinfo.h | 2 + 7 files changed, 359 insertions(+), 350 deletions(-) create mode 100644 userspace/libsinsp/linux/resource_utilization.cpp create mode 100644 userspace/libsinsp/linux/resource_utilization.h diff --git a/userspace/libsinsp/CMakeLists.txt b/userspace/libsinsp/CMakeLists.txt index 9a0404f7e2..ccfcce0ef8 100644 --- a/userspace/libsinsp/CMakeLists.txt +++ b/userspace/libsinsp/CMakeLists.txt @@ -110,6 +110,13 @@ add_library( events/sinsp_events_ppm_sc.cpp ) +if(NOT WIN32 + AND NOT APPLE + AND NOT EMSCRIPTEN +) + target_sources(sinsp PRIVATE linux/resource_utilization.cpp) +endif() + if(ENABLE_THREAD_POOL AND NOT EMSCRIPTEN) target_sources(sinsp PRIVATE sinsp_thread_pool_bs.cpp) endif() diff --git a/userspace/libsinsp/linux/resource_utilization.cpp b/userspace/libsinsp/linux/resource_utilization.cpp new file mode 100644 index 0000000000..e0ddd57440 --- /dev/null +++ b/userspace/libsinsp/linux/resource_utilization.cpp @@ -0,0 +1,283 @@ +#include + +#include + +void linux_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 linux_resource_utilization::get_cpu_usage_and_total_procs(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. + */ + + // 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) { + 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 + } +} + +std::vector linux_resource_utilization::to_metrics() { + std::vector metrics; + metrics.emplace_back(new_metric("cpu_usage_perc", + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_D, + METRIC_VALUE_UNIT_PERC, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, + m_cpu_usage_perc)); + metrics.emplace_back(new_metric("memory_rss_kb", + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, + m_rss)); + metrics.emplace_back(new_metric("memory_vsz_kb", + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, + m_vsz)); + metrics.emplace_back(new_metric("memory_pss_kb", + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, + m_pss)); + metrics.emplace_back(new_metric("container_memory_used_bytes", + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_MEMORY_BYTES, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, + m_container_memory_used)); + metrics.emplace_back(new_metric("host_cpu_usage_perc", + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_D, + METRIC_VALUE_UNIT_PERC, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, + m_host_cpu_usage_perc)); + metrics.emplace_back(new_metric("host_memory_used_kb", + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, + m_host_memory_used)); + metrics.emplace_back(new_metric("host_procs_running", + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U32, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, + m_host_procs_running)); + metrics.emplace_back(new_metric("host_open_fds", + METRICS_V2_RESOURCE_UTILIZATION, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_COUNT, + METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, + m_host_open_fds)); + + return metrics; +} + +void linux_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); +} diff --git a/userspace/libsinsp/linux/resource_utilization.h b/userspace/libsinsp/linux/resource_utilization.h new file mode 100644 index 0000000000..e44585c471 --- /dev/null +++ b/userspace/libsinsp/linux/resource_utilization.h @@ -0,0 +1,42 @@ +#include + +class linux_resource_utilization : libs::metrics::libsinsp_metrics { +public: + linux_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(); + } + + std::vector to_metrics(); + +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. + uint32_t m_vsz{}; ///< Current VSZ (Virtual Memory Size), calculated based on /proc/self/status + ///< info, unit: kb. + uint32_t m_pss{}; ///< Current PSS (Proportional Set Size), calculated based on + ///< /proc/self/smaps_rollup info, unit: kb. + + uint64_t m_container_memory_used{}; ///< Cgroup current memory used, default Kubernetes + ///< /sys/fs/cgroup/memory/memory.usage_in_bytes, unit: + ///< bytes. + + double m_host_cpu_usage_perc{}; ///< Current total host CPU usage (all CPUs), calculated based + ///< on ${HOST_ROOT}/proc/stat info, unit: percentage. + uint64_t m_host_memory_used{}; ///< Current total memory used out of available host memory, + ///< calculated based on ${HOST_ROOT}/proc/meminfo info, unit: + ///< kb. + uint32_t m_host_procs_running{}; ///< Number of processes currently running on CPUs on the + ///< host, retrieved from ${HOST_ROOT}/proc/stat line + ///< `procs_running`, unit: count. + uint64_t m_host_open_fds{}; ///< Number of allocated fds on the host, retrieved from + ///< ${HOST_ROOT}/proc/sys/fs/file-nr, unit: count. +}; diff --git a/userspace/libsinsp/metrics_collector.cpp b/userspace/libsinsp/metrics_collector.cpp index e5e64d8289..b99614bb46 100644 --- a/userspace/libsinsp/metrics_collector.cpp +++ b/userspace/libsinsp/metrics_collector.cpp @@ -16,16 +16,16 @@ limitations under the License. */ -#ifdef __linux__ - #include #include #include #include -#include -#include #include +#ifdef __linux__ +#include +#endif + 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); @@ -36,17 +36,17 @@ static re2::RE2 s_libs_metrics_units_perc_suffix("(_perc)", re2::RE2::POSIX); // 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) / @@ -57,8 +57,8 @@ static_assert(sizeof(metrics_unit_name_mappings_prometheus) / // 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 { @@ -247,286 +247,6 @@ 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) { - 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. - */ - - // 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) { - 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 - } -} - -std::vector libs_resource_utilization::to_metrics() { - std::vector metrics; - metrics.emplace_back(new_metric("cpu_usage_perc", - METRICS_V2_RESOURCE_UTILIZATION, - METRIC_VALUE_TYPE_D, - METRIC_VALUE_UNIT_PERC, - METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, - m_cpu_usage_perc)); - metrics.emplace_back(new_metric("memory_rss_kb", - METRICS_V2_RESOURCE_UTILIZATION, - METRIC_VALUE_TYPE_U32, - METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, - METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, - m_rss)); - metrics.emplace_back(new_metric("memory_vsz_kb", - METRICS_V2_RESOURCE_UTILIZATION, - METRIC_VALUE_TYPE_U32, - METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, - METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, - m_vsz)); - metrics.emplace_back(new_metric("memory_pss_kb", - METRICS_V2_RESOURCE_UTILIZATION, - METRIC_VALUE_TYPE_U32, - METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, - METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, - m_pss)); - metrics.emplace_back(new_metric("container_memory_used_bytes", - METRICS_V2_RESOURCE_UTILIZATION, - METRIC_VALUE_TYPE_U64, - METRIC_VALUE_UNIT_MEMORY_BYTES, - METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, - m_container_memory_used)); - metrics.emplace_back(new_metric("host_cpu_usage_perc", - METRICS_V2_RESOURCE_UTILIZATION, - METRIC_VALUE_TYPE_D, - METRIC_VALUE_UNIT_PERC, - METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, - m_host_cpu_usage_perc)); - metrics.emplace_back(new_metric("host_memory_used_kb", - METRICS_V2_RESOURCE_UTILIZATION, - METRIC_VALUE_TYPE_U32, - METRIC_VALUE_UNIT_MEMORY_KIBIBYTES, - METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, - m_host_memory_used)); - metrics.emplace_back(new_metric("host_procs_running", - METRICS_V2_RESOURCE_UTILIZATION, - METRIC_VALUE_TYPE_U32, - METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, - m_host_procs_running)); - metrics.emplace_back(new_metric("host_open_fds", - METRICS_V2_RESOURCE_UTILIZATION, - METRIC_VALUE_TYPE_U64, - METRIC_VALUE_UNIT_COUNT, - METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT, - m_host_open_fds)); - - 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), @@ -702,8 +422,13 @@ void libs_metrics_collector::snapshot() { * libsinsp metrics */ if((m_metrics_flags & METRICS_V2_RESOURCE_UTILIZATION)) { +#ifdef __linux__ const scap_agent_info* agent_info = m_inspector->get_agent_info(); - libs_resource_utilization resource_utilization(agent_info->start_time); + linux_resource_utilization resource_utilization(agent_info->start_time); +#else + libsinsp_metrics resource_utilization; +#endif + std::vector ru_metrics = resource_utilization.to_metrics(); m_metrics.insert(m_metrics.end(), ru_metrics.begin(), ru_metrics.end()); } @@ -744,5 +469,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 34669d4e73..133ce21bdb 100644 --- a/userspace/libsinsp/metrics_collector.h +++ b/userspace/libsinsp/metrics_collector.h @@ -26,6 +26,7 @@ limitations under the License. #include #include #include +#include struct sinsp_stats_v2 { ///@( @@ -63,8 +64,6 @@ struct sinsp_stats_v2 { ///< flush snapshot update, unit: count. }; -#ifdef __linux__ - namespace libs::metrics { template @@ -299,48 +298,7 @@ class libsinsp_metrics { libsinsp_metrics& operator=(const libsinsp_metrics&) = default; libsinsp_metrics& operator=(libsinsp_metrics&&) = delete; virtual ~libsinsp_metrics() = default; - virtual std::vector to_metrics() = 0; -}; - -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(); - } - - 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. - uint32_t m_vsz{}; ///< Current VSZ (Virtual Memory Size), calculated based on /proc/self/status - ///< info, unit: kb. - uint32_t m_pss{}; ///< Current PSS (Proportional Set Size), calculated based on - ///< /proc/self/smaps_rollup info, unit: kb. - - uint64_t m_container_memory_used{}; ///< Cgroup current memory used, default Kubernetes - ///< /sys/fs/cgroup/memory/memory.usage_in_bytes, unit: - ///< bytes. - - double m_host_cpu_usage_perc{}; ///< Current total host CPU usage (all CPUs), calculated based - ///< on ${HOST_ROOT}/proc/stat info, unit: percentage. - uint64_t m_host_memory_used{}; ///< Current total memory used out of available host memory, - ///< calculated based on ${HOST_ROOT}/proc/meminfo info, unit: - ///< kb. - uint32_t m_host_procs_running{}; ///< Number of processes currently running on CPUs on the - ///< host, retrieved from ${HOST_ROOT}/proc/stat line - ///< `procs_running`, unit: count. - uint64_t m_host_open_fds{}; ///< Number of allocated fds on the host, retrieved from - ///< ${HOST_ROOT}/proc/sys/fs/file-nr, unit: count. + virtual std::vector to_metrics() { return std::vector(); }; }; class libs_state_counters : libsinsp_metrics { @@ -389,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 3108057c9b..06a4abde57 100644 --- a/userspace/libsinsp/test/plugins.ut.cpp +++ b/userspace/libsinsp/test/plugins.ut.cpp @@ -1190,8 +1190,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); libs::metrics::libs_metrics_collector libs_metrics_collector(&m_inspector, test_metrics_flags); @@ -1228,8 +1226,6 @@ TEST_F(sinsp_with_test_input, plugin_metrics) { ASSERT_EQ(metrics_snapshot.back().value.u64, events); } -#endif - #if defined(ENABLE_THREAD_POOL) && !defined(__EMSCRIPTEN__) TEST_F(sinsp_with_test_input, plugin_routines) { diff --git a/userspace/libsinsp/threadinfo.h b/userspace/libsinsp/threadinfo.h index e03953fa05..aed22fff92 100644 --- a/userspace/libsinsp/threadinfo.h +++ b/userspace/libsinsp/threadinfo.h @@ -36,6 +36,8 @@ struct iovec { #include #include #include +#include +#include struct erase_fd_params { bool m_remove_from_table;