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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions plugins/in_podman_metrics/podman_metrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,15 @@ static int collect_container_data(struct flb_in_metrics *ctx)
metadata_token_start = strstr(metadata, JSON_SUBFIELD_IMAGE_NAME);
if (metadata_token_start) {
metadata_token_stop = strstr(metadata_token_start + JSON_SUBFIELD_SIZE_IMAGE_NAME+1, "\\\"");
metadata_token_size = metadata_token_stop - metadata_token_start - JSON_SUBFIELD_SIZE_IMAGE_NAME;

strncpy(image_name, metadata_token_start+JSON_SUBFIELD_SIZE_IMAGE_NAME, metadata_token_size);
image_name[metadata_token_size] = '\0';
if (metadata_token_stop) {
metadata_token_size = metadata_token_stop - metadata_token_start - JSON_SUBFIELD_SIZE_IMAGE_NAME;
strncpy(image_name, metadata_token_start+JSON_SUBFIELD_SIZE_IMAGE_NAME, metadata_token_size);
image_name[metadata_token_size] = '\0';
}
else {
strncpy(image_name, "unknown", IMAGE_NAME_SIZE - 1);
image_name[7] = '\0';
}

flb_plg_trace(ctx->ins, "Found image name %s", image_name);
add_container_to_list(ctx, id, name, image_name);
Expand Down Expand Up @@ -225,10 +230,19 @@ static int create_counter(struct flb_in_metrics *ctx, struct cmt_counter **count
return -1;
}

if (strcmp(metric_name, COUNTER_CPU) == 0 || strcmp(metric_name, COUNTER_CPU_USER) == 0) {
fvalue = fvalue / 1000000000;
flb_plg_trace(ctx->ins, "Converting %s from nanoseconds to seconds (%lu -> %lu)", metric_name, value, fvalue);

if (strcmp(metric_name, COUNTER_CPU) == 0 ||
strcmp(metric_name, COUNTER_CPU_USER) == 0) {
if (ctx->cgroup_version == CGROUP_V2) {
/* cgroup v2 cpu.stat reports in microseconds */
fvalue = fvalue / 1000000;
}
else {
/* cgroup v1 cpuacct reports in nanoseconds */
fvalue = fvalue / 1000000000;
}
flb_plg_trace(ctx->ins,
"Converting %s to seconds (%lu -> %lu)",
metric_name, value, fvalue);
}

labels = (char *[]){id, name, image_name, interface};
Expand Down
3 changes: 2 additions & 1 deletion plugins/in_podman_metrics/podman_metrics_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@

/* Key names in .stat files */
#define STAT_KEY_RSS "rss"
#define V2_STAT_KEY_RSS "anon"
#define STAT_KEY_CPU "usage_usec"
#define STAT_KEY_CPU_USER "user_usec"

Expand All @@ -106,7 +107,7 @@
#define V2_SYSFS_FILE_MEMORY_LIMIT "memory.max"
#define V2_SYSFS_FILE_CPU_STAT "cpu.stat"
#define V2_SYSFS_FILE_PIDS "cgroup.procs"
#define V2_SYSFS_FILE_PIDS_ALT "containers/cgroup.procs"
#define V2_SYSFS_FILE_PIDS_ALT "container/cgroup.procs"

/* Values used to construct counters/gauges names and descriptions */
#define COUNTER_PREFIX "container"
Expand Down
55 changes: 53 additions & 2 deletions plugins/in_podman_metrics/podman_metrics_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,54 @@ int fill_counters_with_sysfs_data_v1(struct flb_in_metrics *ctx)
return 0;
}

/*
* Read uint64_t value from sysfs file, with special handling for the "max"
* keyword used by cgroup v2 to indicate an unlimited resource.
* Returns 0 when file contains "max".
*/
static uint64_t read_from_sysfs_or_max(struct flb_in_metrics *ctx,
flb_sds_t dir,
flb_sds_t name)
{
char path[SYSFS_FILE_PATH_SIZE];
char buf[32];
uint64_t value = UINT64_MAX;
FILE *fp;
int c;

if (dir == NULL) {
return value;
}

snprintf(path, sizeof(path), "%s/%s", dir, name);

fp = fopen(path, "r");
if (!fp) {
flb_plg_warn(ctx->ins, "Failed to read %s", path);
return value;
}

if (fgets(buf, sizeof(buf), fp) != NULL) {
/* cgroup v2 uses "max" to indicate unlimited */
if (strncmp(buf, "max", 3) == 0) {
flb_plg_debug(ctx->ins, "%s: max (unlimited)", path);
fclose(fp);
return 0;
}
c = sscanf(buf, "%lu", &value);
if (c != 1) {
flb_plg_warn(ctx->ins,
"Failed to read a number from %s", path);
fclose(fp);
return UINT64_MAX;
}
}

Comment on lines +372 to +387
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Handle fgets() failure explicitly in read_from_sysfs_or_max.

When the read fails or file is empty, the function currently returns invalid value without a warning, which makes diagnosis harder.

🛠️ Suggested fix
-    if (fgets(buf, sizeof(buf), fp) != NULL) {
-        /* cgroup v2 uses "max" to indicate unlimited */
-        if (strncmp(buf, "max", 3) == 0) {
-            flb_plg_debug(ctx->ins, "%s: max (unlimited)", path);
-            fclose(fp);
-            return 0;
-        }
-        c = sscanf(buf, "%lu", &value);
-        if (c != 1) {
-            flb_plg_warn(ctx->ins,
-                         "Failed to read a number from %s", path);
-            fclose(fp);
-            return UINT64_MAX;
-        }
-    }
+    if (fgets(buf, sizeof(buf), fp) == NULL) {
+        flb_plg_warn(ctx->ins, "Failed to read a value from %s", path);
+        fclose(fp);
+        return UINT64_MAX;
+    }
+
+    /* cgroup v2 uses "max" to indicate unlimited */
+    if (strncmp(buf, "max", 3) == 0) {
+        flb_plg_debug(ctx->ins, "%s: max (unlimited)", path);
+        fclose(fp);
+        return 0;
+    }
+
+    c = sscanf(buf, "%lu", &value);
+    if (c != 1) {
+        flb_plg_warn(ctx->ins, "Failed to read a number from %s", path);
+        fclose(fp);
+        return UINT64_MAX;
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (fgets(buf, sizeof(buf), fp) != NULL) {
/* cgroup v2 uses "max" to indicate unlimited */
if (strncmp(buf, "max", 3) == 0) {
flb_plg_debug(ctx->ins, "%s: max (unlimited)", path);
fclose(fp);
return 0;
}
c = sscanf(buf, "%lu", &value);
if (c != 1) {
flb_plg_warn(ctx->ins,
"Failed to read a number from %s", path);
fclose(fp);
return UINT64_MAX;
}
}
if (fgets(buf, sizeof(buf), fp) == NULL) {
flb_plg_warn(ctx->ins, "Failed to read a value from %s", path);
fclose(fp);
return UINT64_MAX;
}
/* cgroup v2 uses "max" to indicate unlimited */
if (strncmp(buf, "max", 3) == 0) {
flb_plg_debug(ctx->ins, "%s: max (unlimited)", path);
fclose(fp);
return 0;
}
c = sscanf(buf, "%lu", &value);
if (c != 1) {
flb_plg_warn(ctx->ins, "Failed to read a number from %s", path);
fclose(fp);
return UINT64_MAX;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/in_podman_metrics/podman_metrics_data.c` around lines 372 - 387, The
function read_from_sysfs_or_max currently ignores fgets() failures/empty reads;
update it to explicitly handle fgets returning NULL by checking feof()/ferror(),
calling fclose(fp), logging a warning via flb_plg_warn (include path and reason
e.g., strerror(errno) or mention empty file), and returning UINT64_MAX; keep the
existing cgroup v2 "max" handling and successful-read path intact and reference
buf, fp, path, flb_plg_warn, and flb_plg_debug to locate the change.

fclose(fp);
flb_plg_debug(ctx->ins, "%s: %lu", path, value);
return value;
}

/*
* Iterate over previously created container list. For each entry, generate its
* path in sysfs system directory. From this path, grab data about container metrics
Expand All @@ -363,8 +411,11 @@ int fill_counters_with_sysfs_data_v2(struct flb_in_metrics *ctx)

cnt->memory_usage = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_MEMORY, NULL);
cnt->memory_max_usage = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_MAX_MEMORY, NULL);
cnt->rss = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_MEMORY_STAT, STAT_KEY_RSS);
cnt->memory_limit = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_MEMORY_LIMIT, NULL);
cnt->rss = get_data_from_sysfs(ctx, path,
V2_SYSFS_FILE_MEMORY_STAT,
V2_STAT_KEY_RSS);
cnt->memory_limit = read_from_sysfs_or_max(ctx, path,
V2_SYSFS_FILE_MEMORY_LIMIT);
cnt->cpu_user = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_CPU_STAT, STAT_KEY_CPU_USER);
cnt->cpu = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_CPU_STAT, STAT_KEY_CPU);
pid = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_PIDS, NULL);
Expand Down