Skip to content

fix: report container-scoped CPU and memory metrics - #27389

Closed
superezzdev wants to merge 1 commit into
Graylog2:masterfrom
superezzdev:fix/container-scoped-cpu-and-memory-metrics
Closed

superezzdev wants to merge 1 commit into
Graylog2:masterfrom
superezzdev:fix/container-scoped-cpu-and-memory-metrics

Conversation

@superezzdev

Copy link
Copy Markdown

Fixes #27264

Description

When Graylog Server and Data Nodes run in containers, the Cluster Configuration page can show the host's CPU and memory instead of the resources available to that container.

This PR makes the resource metrics cgroup-aware while keeping the existing behavior for non-containerized deployments.

What changed

  • Graylog Server: CpuLoadGauge now uses OSHI's cgroup information to calculate CPU usage for the container. When cgroup information isn't available, it falls back to the existing OSHI CPU tick calculation.

  • Data Node: NodeMetricsCollector now uses the cgroup memory and CPU information returned by OpenSearch when a container has resource limits. This keeps memory total/used/free and CPU percentage scoped to the container instead of the host.

  • CPU sampling: MetricsCollector now keeps the same NodeMetricsCollector instance between runs so CPU usage can be calculated from consecutive samples.

  • Heap warning: OpensearchProcessImpl now also falls back to OSHI's CgroupInfo when the cgroup files can't be read directly. This avoids incorrect heap warnings in container environments where the direct /sys/fs/cgroup paths aren't available.

The existing host-level metrics remain the fallback when usable cgroup information isn't available.

Motivation

This was particularly noticeable when multiple Graylog/Data Node containers were running on the same host:

  • CPU usage was almost identical across containers because it was based on host-wide CPU statistics.
  • Data Nodes could report the host's memory limit instead of their own container limit.
  • Memory usage could appear extremely high because of filesystem cache.
  • In some container setups, the heap warning could use the wrong memory value and suggest increasing the heap unnecessarily.

The goal is to make the values shown in Cluster Configuration match the resources of the actual container.

How Has This Been Tested?

Added tests covering the new cgroup-based behavior and the existing fallbacks.

  • graylog2-server

    • CpuLoadGaugeTest.reportsContainerCpuLoadAfterTwoSamples
    • CpuLoadGaugeTest.reportsContainerCpuLoadWithUnlimitedQuota
  • data-node

    • NodeMetricsCollectorTest.getNodeMetricsWithCgroupMemory
    • NodeMetricsCollectorTest.getNodeMetricsWithUnlimitedCgroupMemory
    • NodeMetricsCollectorTest.getNodeMetricsWithCgroupCpu

Tests executed:

./mvnw test -pl :graylog2-server -Dtest=CpuLoadGaugeTest

./mvnw test -pl :data-node -am \
  -Dtest=NodeStatMetricsTest,NodeMetricsCollectorTest,OpensearchProcessImplTest

All relevant tests passed.

I also verified forbiddenapis and clean compilation across the reactor modules.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Refactoring (non-breaking change)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have requested a documentation update.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.

…ners

Fixes Graylog2#27264

In containerized environments (e.g. Docker), the Cluster Configuration
page displayed host-level CPU and memory figures rather than container-scoped
usage and limits. In addition, Data Nodes could display a false warning
about available memory exceeding heap size when direct cgroup filesystem reads
failed.

This change introduces container-aware metrics for both Graylog server
and OpenSearch data nodes:

- graylog2-server (CpuLoadGauge): Use OSHI's CgroupInfo to calculate
  container CPU usage deltas scaled by effective CPUs / CFS quota. Falls back
  to host CPU load ticks when not containerized.
- data-node (NodeMetricsCollector): Inspect OpenSearch cgroup memory
  (limit_in_bytes, usage_in_bytes) and cpuacct stats to report container-scoped
  memory (total, used, free, used_percent) and CPU percent across ticks.
- data-node (MetricsCollector): Retain NodeMetricsCollector instance across runs
  to track CPU usage deltas across consecutive samples.
- data-node (OpensearchProcessImpl): Add OSHI CgroupInfo fallback to
  getContainerMemory() to accurately detect container limits and eliminate
  false-positive heap warning notifications.
- Tests: Add unit tests for containerized CPU and memory reporting in both modules.
Copilot AI lite review requested due to automatic review settings September 14, 2026 18:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@CLAassistant

CLAassistant commented Sep 14, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@superezzdev

Copy link
Copy Markdown
Author

Hi @fpetersen-gl
Please review PR whenever you get time

Thankyou

@moesterheld moesterheld left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you very much for the contribution and the solid approach. I have one change request regarding the code and an additional request below.

If we use the existing metrics (and since this fixes wrong behavior, we should), this will definitely need an entry in UPGRADING.md. People will already use this for monitoring and alerting so this change might trigger alerts after updating.

Please add something along the lines of

### System CPU and Memory Metrics Now Reflect Container Limits When Containerized

When Graylog Server or Data Node runs in a container with cgroup CPU/memory limits configured (e.g. Docker `--memory`/`--cpus`, Kubernetes `resources.limits`), the `org.graylog2.system.cpu.percent` metric and the Data Node metrics `mem_total`, `mem_free`, `mem_total_used_bytes`, and `mem_total_used` now reflect the container's cgroup-scoped limits and usage instead of the underlying host's.

Previously, these metrics always reported host-level values, so a container with a memory limit well below the host's total RAM would show a low, misleadingly small "used" percentage. After upgrading, the same metrics scale to the container's actual limit, so used-percentage values can jump significantly even though nothing about the node's real memory or CPU pressure has changed. Review and, if necessary, adjust any dashboards or alert thresholds built against the old host-scaled values.

under ## Breaking changes

}
try {
final CgroupInfo cgroup = cgroupInfo();
if (cgroup != null && cgroup.isContainerized()) {

@moesterheld moesterheld Sep 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

cgroupInfo() will construct an additional SystemInfo every 5 seconds only for making the cgroup detection (on bare-metal systems). We should cache the result of the detection on the first run to avoid the overhead cost of SystemInfo construction (see SystemInfo javadoc).

@moesterheld

Copy link
Copy Markdown
Contributor

@superezzdev Thank you once more for your work. To include the changes in the upcoming 7.2 release, we have created a new pr (purely for procedural reasons) which includes your changes with your authorship intact and will address the found issues.

superseded by #27425

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cluster Configuration page shows host-level CPU/memory instead of container-scoped values

4 participants