Skip to content

in_podman_metrics: fix multiple cgroup v2 issues#11719

Open
stondo wants to merge 2 commits into
fluent:masterfrom
stondo:fix/podman-metrics-cgroupv2
Open

in_podman_metrics: fix multiple cgroup v2 issues#11719
stondo wants to merge 2 commits into
fluent:masterfrom
stondo:fix/podman-metrics-cgroupv2

Conversation

@stondo
Copy link
Copy Markdown

@stondo stondo commented Apr 15, 2026

Summary

Fix four cgroup v2 bugs in the in_podman_metrics input plugin that caused
most container metrics to be absent or incorrect on systems using cgroup v2
(unified hierarchy).

All four bugs are confirmed on an ARM64 embedded device running
Fluent Bit 4.2.0/5.0.2 with Podman and cgroup v2 unified hierarchy.

Bugs fixed

1. CPU counter division (incorrect unit conversion)

create_counter() divides raw CPU values by 1,000,000,000 (nanoseconds)
unconditionally. This is correct for cgroup v1 (cpuacct.usage reports
nanoseconds) but wrong for cgroup v2 (cpu.stat reports usage_usec
and user_usec in microseconds).

On v2, integer division truncates all values below 1e9 usec (~16.7 min of
CPU time) to zero. In practice, container_cpu_usage_seconds_total and
container_cpu_user_seconds_total always read 0.

Fix: Check ctx->cgroup_version and use the correct divisor:
1e9 for v1 (nanoseconds), 1e6 for v2 (microseconds).

2. RSS memory key name (wrong key for v2)

STAT_KEY_RSS is defined as "rss", which is correct for cgroup v1
memory.stat. However, cgroup v2 memory.stat does not have a rss
field; the equivalent is anon (anonymous memory pages).

Result: container_memory_rss gauge is never reported for any
container on v2, with a [warn] rss not found in .../memory.stat log
message emitted per container per scrape.

Fix: Add V2_STAT_KEY_RSS "anon" and use it in
fill_counters_with_sysfs_data_v2().

3. memory.max "max" keyword (parse failure)

cgroup v2 memory.max contains the literal string "max" when the
memory limit is unlimited (no limit set). read_from_file() uses
fscanf(fp, "%lu", &value) which fails to parse "max", returning
UINT64_MAX and logging a spurious warning per affected container per
scrape.

Result: container_spec_memory_limit_bytes is missing for
containers without an explicit memory limit. Warning spam in logs.

Fix: Add read_from_sysfs_or_max() helper that parses the "max"
keyword and returns 0 (unlimited), matching the convention used by
cAdvisor and other container metric exporters.

4. PID fallback path typo (singular vs. plural)

V2_SYSFS_FILE_PIDS_ALT is defined as "containers/cgroup.procs"
(plural), but the actual cgroup v2 subdirectory is
"container/cgroup.procs" (singular).

On v2, cgroup.procs at the scope level is empty for all containers.
Processes live only in the container/cgroup.procs subdirectory. The
plugin correctly tries the alt path, but the typo means it always fails.

Result: PID lookup fails for all containers, which prevents
get_net_data_from_proc() from being called. All four
container_network_* metrics are completely absent.

Fix: Change "containers/cgroup.procs" to "container/cgroup.procs".

Before/After (gw-cloud-connector container, ARM64 device)

Metric Before After
container_cpu_usage_seconds_total 0 449
container_cpu_user_seconds_total 0 145
container_memory_rss MISSING 12,472,320
container_spec_memory_limit_bytes MISSING 1,048,576,000
container_network_receive_bytes_total MISSING 3,229,233
container_network_transmit_bytes_total MISSING 4,721,901

After the fix, all 10 metric types are successfully emitted for all 9
containers, with zero warnings in the log.

Testing

Tested on:

  • ARM64 (Cortex-A7) embedded device, 4-core, 4 GB RAM
  • Yocto Scarthgap (kernel 6.6), cgroup v2 unified hierarchy
  • Podman 5.x with 9 containers (3 infra, 3 service, 3 app)
  • Fluent Bit 4.2.0 and verified patch applies cleanly to 5.0.2/5.0.3

Verified:

  • All 10 metric types present in Prometheus output
  • CPU values match raw cpu.stat divided by 1e6
  • RSS values match anon field in memory.stat
  • Memory limit correctly reports 0 for unlimited and real values for limited
  • Network metrics present for all containers with non-loopback interfaces
  • Zero warnings in journal log after fix (previously ~45 warnings per scrape)
  • No regression: cgroup v1 code path is unchanged

Fixes #7769

Summary by CodeRabbit

  • Bug Fixes
    • CPU metrics now convert correctly for both cgroup v1 and v2 so reported CPU times are accurate.
    • Memory limits on cgroup v2 are interpreted correctly, treating "unlimited" as such.
    • RSS handling updated for cgroup v2 to read the appropriate stat field.
    • Image-name extraction made more robust, defaulting to "unknown" when container metadata is incomplete.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 15, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a1dfb757-90f8-47c8-8122-8ad91599e4eb

📥 Commits

Reviewing files that changed from the base of the PR and between a35a87d and acaa540.

📒 Files selected for processing (3)
  • plugins/in_podman_metrics/podman_metrics.c
  • plugins/in_podman_metrics/podman_metrics_config.h
  • plugins/in_podman_metrics/podman_metrics_data.c
🚧 Files skipped from review as they are similar to previous changes (3)
  • plugins/in_podman_metrics/podman_metrics.c
  • plugins/in_podman_metrics/podman_metrics_data.c
  • plugins/in_podman_metrics/podman_metrics_config.h

📝 Walkthrough

Walkthrough

CPU unit conversion made cgroup-version-aware; image-name extraction defaults to "unknown" when metadata end-token is missing; added cgroup v2 RSS key and adjusted alternate PIDs path; introduced a sysfs reader that treats cgroup v2 "max" as unlimited (0) and is used for memory limits.

Changes

CPU & container parsing

Layer / File(s) Summary
CPU counter conversion & tracing
plugins/in_podman_metrics/podman_metrics.c
create_counter converts CPU counters (COUNTER_CPU, COUNTER_CPU_USER) using a cgroup-version-dependent divisor: 1,000,000 for CGROUP_V2 (microseconds→seconds) and 1,000,000,000 for cgroup v1; trace message wording adjusted.
Container image name extraction
plugins/in_podman_metrics/podman_metrics.c
collect_container_data copies image name from metadata only if metadata_token_stop is found; otherwise image_name is set to "unknown".

Configuration constants

Layer / File(s) Summary
cgroup v2 keys and alternate paths
plugins/in_podman_metrics/podman_metrics_config.h
Added V2_STAT_KEY_RSS = "anon" and changed V2_SYSFS_FILE_PIDS_ALT path from "containers/cgroup.procs" to "container/cgroup.procs".

Cgroup v2 sysfs handling

Layer / File(s) Summary
Sysfs reader handling "max" and v2 memory limits
plugins/in_podman_metrics/podman_metrics_data.c
Added static helper read_from_sysfs_or_max() that reads <dir>/<name>, returns 0 when contents begin with "max", and logs on open/read/parse failures. fill_counters_with_sysfs_data_v2 now uses this helper for cnt->memory_limit and reads RSS using V2_STAT_KEY_RSS.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

backport to v4.2.x

Suggested reviewers

  • edsiper
  • cosmo0920

Poem

🐇 I nibble code in fields of C,
I turn "max" to zero — hop with glee,
RSS and paths aligned just so,
CPU seconds now gently flow,
Metrics tidy — off I flee!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'in_podman_metrics: fix multiple cgroup v2 issues' accurately summarizes the main change: fixing multiple cgroup v2 compatibility bugs in the podman_metrics plugin.
Linked Issues check ✅ Passed The PR addresses all four coding objectives from issue #7769: CPU counter unit handling (1e9 for v1, 1e6 for v2), RSS memory key mapping (V2_STAT_KEY_RSS 'anon'), memory.max 'max' keyword parsing via read_from_sysfs_or_max(), and PID path typo fix (containers→container).
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the four cgroup v2 bugs documented in issue #7769; no extraneous modifications or unrelated changes were introduced.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
plugins/in_podman_metrics/podman_metrics.c (1)

122-123: Avoid hard-coded terminator index for "unknown".

Using a literal index is brittle; derive it from the string length for safer maintenance.

♻️ Suggested refactor
-                        strncpy(image_name, "unknown", IMAGE_NAME_SIZE - 1);
-                        image_name[7] = '\0';
+                        strncpy(image_name, "unknown", IMAGE_NAME_SIZE - 1);
+                        image_name[sizeof("unknown") - 1] = '\0';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/in_podman_metrics/podman_metrics.c` around lines 122 - 123, The code
in podman_metrics.c sets image_name to "unknown" then hard-codes image_name[7] =
'\0'; which is brittle; in the block that assigns image_name (use the same spot
that calls strncpy(image_name, "unknown", IMAGE_NAME_SIZE - 1)), replace the
fixed index with a derived terminator using the actual string length (e.g.,
size_t n = strlen("unknown"); if (n >= IMAGE_NAME_SIZE) n = IMAGE_NAME_SIZE - 1;
image_name[n] = '\0') or use a bounded formatting function like snprintf to
write and terminate safely; update the logic around image_name, IMAGE_NAME_SIZE,
and the strncpy call accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugins/in_podman_metrics/podman_metrics_data.c`:
- Around line 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.

---

Nitpick comments:
In `@plugins/in_podman_metrics/podman_metrics.c`:
- Around line 122-123: The code in podman_metrics.c sets image_name to "unknown"
then hard-codes image_name[7] = '\0'; which is brittle; in the block that
assigns image_name (use the same spot that calls strncpy(image_name, "unknown",
IMAGE_NAME_SIZE - 1)), replace the fixed index with a derived terminator using
the actual string length (e.g., size_t n = strlen("unknown"); if (n >=
IMAGE_NAME_SIZE) n = IMAGE_NAME_SIZE - 1; image_name[n] = '\0') or use a bounded
formatting function like snprintf to write and terminate safely; update the
logic around image_name, IMAGE_NAME_SIZE, and the strncpy call accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 11fd1877-05ab-4428-b4d0-5c5d7c213869

📥 Commits

Reviewing files that changed from the base of the PR and between 6c742a1 and 34b3477.

📒 Files selected for processing (3)
  • plugins/in_podman_metrics/podman_metrics.c
  • plugins/in_podman_metrics/podman_metrics_config.h
  • plugins/in_podman_metrics/podman_metrics_data.c

Comment thread plugins/in_podman_metrics/podman_metrics_data.c Outdated
@stondo
Copy link
Copy Markdown
Author

stondo commented May 12, 2026

Addressed both CodeRabbit review comments in commit a35a87d:

  • Actionable (podman_metrics_data.c): refactored read_from_sysfs_or_max() to guard-clause pattern — returns UINT64_MAX immediately when fgets() returns NULL, with a warning log including the path.
  • Nitpick (podman_metrics.c): replaced hard-coded image_name[7] = '\0' with image_name[sizeof("unknown") - 1] = '\0' so the index is derived from the string rather than being a magic literal.

@cosmo0920
Copy link
Copy Markdown
Contributor

The last comment does not have Signed-off line so we need to add it at first.

stondo added 2 commits May 18, 2026 11:14
Fix five bugs in the podman_metrics input plugin:

1. CPU counter division: cgroup v2 cpu.stat reports usage in
microseconds, not nanoseconds like cgroup v1 cpuacct.
Use the correct divisor (1e6) when converting to seconds.

2. RSS memory key: cgroup v2 memory.stat does not have a "rss"
field. The equivalent metric is "anon" (anonymous memory).
Add V2_STAT_KEY_RSS and use it in the v2 collection path.

3. memory.max "max" keyword: cgroup v2 uses the literal string
"max" in memory.max when the memory limit is unlimited.
read_from_file() fails to parse this with fscanf("%lu"),
causing spurious warnings. Add read_from_sysfs_or_max()
helper that returns 0 for "max" (unlimited).

4. PID alt path typo: V2_SYSFS_FILE_PIDS_ALT was set to
"containers/cgroup.procs" (plural) but the actual cgroup v2
subdirectory is "container/cgroup.procs" (singular). This
caused PID lookup to fail for all containers, which in turn
prevented all network metrics from being collected.

5. Image name NULL safety: when parsing container metadata JSON,
strstr() for the closing quote of the image name field can
return NULL if the metadata is malformed or truncated. The
result was used directly in pointer arithmetic and strncpy(),
causing undefined behaviour and potential crashes. Add a NULL
guard that falls back to image="unknown" when parsing fails.

GitHub issue fluent#7769.

Signed-off-by: stondo <stondo@gmail.com>
- read_from_sysfs_or_max: refactor to guard-clause pattern; return
  UINT64_MAX immediately when fgets() returns NULL instead of silently
  falling through and returning whatever value was last read.
- collect_container_data: use sizeof("unknown") - 1 instead of the
  magic literal 7 when NUL-terminating image_name after strncpy so the
  index stays correct if the fallback string ever changes.

Signed-off-by: Stefano Tondo <stondo@gmail.com>
@stondo stondo force-pushed the fix/podman-metrics-cgroupv2 branch from a35a87d to acaa540 Compare May 18, 2026 09:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Podman Metrics for cgroup v2

2 participants