summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Hennion <nicolashennion@gmail.com>2024-01-02 17:16:30 +0000
committerBharath Vignesh J K <52282402+RazCrimson@users.noreply.github.com>2024-04-29 22:54:49 +0530
commit8edf6e70b5bfe304fd921ee2fcb3b4f87cd9cea4 (patch)
tree03d927dbbabeabd84a1fea31f9806b221f418c32
parentde69635d41efa38428e0779e2467632d2cafdede (diff)
Docker memory usage is incorrect
-rw-r--r--docs/aoa/containers.rst2
-rw-r--r--glances/outputs/static/js/components/plugin-containers.vue13
-rw-r--r--glances/plugins/containers/__init__.py18
-rw-r--r--glances/plugins/containers/engines/docker.py20
-rw-r--r--glances/plugins/containers/engines/podman.py4
5 files changed, 36 insertions, 21 deletions
diff --git a/docs/aoa/containers.rst b/docs/aoa/containers.rst
index 3750d3cf..591251cc 100644
--- a/docs/aoa/containers.rst
+++ b/docs/aoa/containers.rst
@@ -14,6 +14,8 @@ You can install this dependency using:
.. image:: ../_static/containers.png
+Note: Memory usage is compute as following "display memory usage = memory usage - inactive_file"
+
It is possible to define limits and actions from the configuration file
under the ``[containers]`` section:
diff --git a/glances/outputs/static/js/components/plugin-containers.vue b/glances/outputs/static/js/components/plugin-containers.vue
index 0470909d..ba9da77e 100644
--- a/glances/outputs/static/js/components/plugin-containers.vue
+++ b/glances/outputs/static/js/components/plugin-containers.vue
@@ -54,7 +54,7 @@
{{ $filters.number(container.cpu_percent, 1) }}
</div>
<div class="table-cell">
- {{ $filters.bytes(container.memory_usage) }}
+ {{ $filters.bytes(container.memory_usage_no_cache) }}
</div>
<div class="table-cell">
{{ $filters.bytes(container.limit) }}
@@ -112,14 +112,21 @@ export default {
const { sorter } = this;
const containers = (this.stats || []).map(
(containerData) => {
- // prettier-ignore
+ let memory_usage_no_cache = '?'
+ if (containerData.memory.usage != undefined) {
+ memory_usage_no_cache = containerData.memory.usage;
+ if (containerData.memory.inactive_file != undefined) {
+ memory_usage_no_cache = memory_usage_no_cache - containerData.memory.inactive_file;
+ }
+ }
+
return {
'id': containerData.id,
'name': containerData.name,
'status': containerData.status,
'uptime': containerData.uptime,
'cpu_percent': containerData.cpu.total,
- 'memory_usage': containerData.memory.usage != undefined ? containerData.memory.usage : '?',
+ 'memory_usage_no_cache': memory_usage_no_cache,
'limit': containerData.memory.limit != undefined ? containerData.memory.limit : '?',
'io_rx': containerData.io_rx != undefined ? containerData.io_rx : '?',
'io_wx': containerData.io_wx != undefined ? containerData.io_wx : '?',
diff --git a/glances/plugins/containers/__init__.py b/glances/plugins/containers/__init__.py
index 1cdce11a..6c0134f5 100644
--- a/glances/plugins/containers/__init__.py
+++ b/glances/plugins/containers/__init__.py
@@ -256,6 +256,10 @@ class PluginModel(GlancesPluginModel):
"""Return the user ticks by reading the environment variable."""
return os.sysconf(os.sysconf_names['SC_CLK_TCK'])
+ def memory_usage_no_cache(self, mem):
+ """Return the 'real' memory usage by removing inactive_file to usage"""
+ return mem['usage'] - (mem['inactive_file'] if 'inactive_file' in mem else 0)
+
def update_views(self):
"""Update stats views."""
# Call the father's method
@@ -281,11 +285,17 @@ class PluginModel(GlancesPluginModel):
if 'memory' in i and 'usage' in i['memory']:
# Looking for specific MEM container threshold in the conf file
alert = self.get_alert(
- i['memory']['usage'], maximum=i['memory']['limit'], header=i['name'] + '_mem', action_key=i['name']
+ self.memory_usage_no_cache(i['memory']),
+ maximum=i['memory']['limit'],
+ header=i['name'] + '_mem', action_key=i['name']
)
if alert == 'DEFAULT':
# Not found ? Get back to default MEM threshold value
- alert = self.get_alert(i['memory']['usage'], maximum=i['memory']['limit'], header='mem')
+ alert = self.get_alert(
+ self.memory_usage_no_cache(i['memory']),
+ maximum=i['memory']['limit'],
+ header='mem'
+ )
self.views[i[self.get_key()]]['mem']['decoration'] = alert
# Display Engine and Pod name ?
@@ -383,8 +393,8 @@ class PluginModel(GlancesPluginModel):
ret.append(self.curse_add_line(msg, self.get_views(item=container['name'], key='cpu', option='decoration')))
# MEM
try:
- msg = '{:>7}'.format(self.auto_unit(container['memory']['usage']))
- except (KeyError, TypeError):
+ msg = '{:>7}'.format(self.auto_unit(self.memory_usage_no_cache(container['memory'])))
+ except KeyError:
msg = '{:>7}'.format('_')
ret.append(self.curse_add_line(msg, self.get_views(item=container['name'], key='mem', option='decoration')))
try:
diff --git a/glances/plugins/containers/engines/docker.py b/glances/plugins/containers/engines/docker.py
index f77340b6..a76a0022 100644
--- a/glances/plugins/containers/engines/docker.py
+++ b/glances/plugins/containers/engines/docker.py
@@ -2,7 +2,7 @@
#
# This file is part of Glances.
#
-# SPDX-FileCopyrightText: 2022 Nicolas Hennion <nicolas@nicolargo.com>
+# SPDX-FileCopyrightText: 2023 Nicolas Hennion <nicolas@nicolargo.com>
#
# SPDX-License-Identifier: LGPL-3.0-only
#
@@ -29,7 +29,7 @@ else:
class DockerStatsFetcher:
- MANDATORY_MEMORY_FIELDS = ["usage", 'limit']
+ MANDATORY_MEMORY_FIELDS = ['usage', 'limit']
def __init__(self, container):
self._container = container
@@ -120,7 +120,7 @@ class DockerStatsFetcher:
def _get_memory_stats(self):
"""Return the container MEMORY.
- Output: a dict {'rss': 1015808, 'cache': 356352, 'usage': ..., 'max_usage': ...}
+ Output: a dict {'usage': ..., 'limit': ..., 'max_usage': ...}
"""
memory_stats = self._streamer.stats.get('memory_stats')
@@ -130,15 +130,11 @@ class DockerStatsFetcher:
return None
stats = {field: memory_stats[field] for field in self.MANDATORY_MEMORY_FIELDS}
- try:
- # Issue #1857 - Some stats are not always available in ['memory_stats']['stats']
- detailed_stats = memory_stats['stats']
- stats['rss'] = detailed_stats.get('rss') or detailed_stats.get('total_rss')
- stats['max_usage'] = detailed_stats.get('max_usage')
- stats['cache'] = detailed_stats.get('cache')
- except (KeyError, TypeError) as e:
- self._log_debug("Can't grab MEM usage", e) # stats do not have MEM information
- return None
+
+ # Optional field
+ stats['inactive_file'] = 0
+ if 'stats' in memory_stats:
+ stats['inactive_file'] = memory_stats['stats'].get('inactive_file', 0)
# Return the stats
return stats
diff --git a/glances/plugins/containers/engines/podman.py b/glances/plugins/containers/engines/podman.py
index 0b17c906..ab016a9e 100644
--- a/glances/plugins/containers/engines/podman.py
+++ b/glances/plugins/containers/engines/podman.py
@@ -139,7 +139,7 @@ class PodmanPodStatsFetcher:
def _get_memory_stats(self, stats):
"""Return the container MEMORY.
- Output: a dict {'rss': 1015808, 'cache': 356352, 'usage': ..., 'max_usage': ...}
+ Output: a dict {'usage': ..., 'limit': ...}
"""
if "MemUsage" not in stats or "/" not in stats["MemUsage"]:
self._log_debug("Missing MEM usage fields")
@@ -155,7 +155,7 @@ class PodmanPodStatsFetcher:
self._log_debug("Compute MEM usage failed", e)
return None
- return {"usage": usage, "limit": limit}
+ return {'usage': usage, 'limit': limit, 'inactive_file': 0}
def _get_network_stats(self, stats):
"""Return the container network usage using the Docker API (v1.0 or higher).