Add per container CPU and MEM monitoring in the Docker plugin (issue #490)

This commit is contained in:
Nicolargo 2015-01-19 22:47:22 +01:00
parent 9b6e038a18
commit 6d32061754
2 changed files with 64 additions and 1 deletions

2
NEWS
View File

@ -18,7 +18,7 @@ Enhancements and news features:
* Refactor export module (CSV export option is now --export-csv). It is now possible to export stats from the Glances client mode (issue #463)
* The Web inteface is now based on BootStarp / RWD grid (issue #417, #366 and #461) Thanks to Nicolas Hart @nclsHart
* Add the RAID plugin (issue #447)
* Add the Docker plugin (issue #440)
* Add the Docker plugin (issue #440) with per container CPU and memory monitoring (issue #490)
* It is possible, through the configuration file, to define if an alarm should be logged or not (using the _log option) (issue #437)
* You can now set alarm for Disk IO
* API: add getAllLimits and getAllViews methods (issue#481)

View File

@ -33,6 +33,9 @@ except ImportError as e:
docker_tag = False
else:
docker_tag = True
import os
import re
import numbers
class Plugin(GlancesPlugin):
@ -140,14 +143,58 @@ class Plugin(GlancesPlugin):
# u'Names': [u'/webstack_nginx_1'],
# u'Id': u'b0da859e84eb4019cf1d965b15e9323006e510352c402d2f442ea632d61faaa5'}]
self.stats['containers'] = self.docker_client.containers()
# Get CPU and MEMORY stats for containers
for c in self.stats['containers']:
c['cpu'] = self.get_docker_cpu(c['Id'])
c['memory'] = self.get_docker_memory(c['Id'])
elif self.get_input() == 'snmp':
# Update stats using SNMP
# Not available
pass
logger.info(self.stats)
return self.stats
def get_docker_cpu(self, id):
"""Return the container CPU usage by reading /sys/fs/cgroup/...
Input: id is the full container id
Output: a dict {'total': 1.49, 'user': 0.65, 'system': 0.84}"""
ret = {}
# Read the stats
with open('/sys/fs/cgroup/cpuacct/docker/' + id + '/cpuacct.stat', 'r') as f:
for line in f:
m = re.search(r"(system|user)\s+(\d+)", line)
if m:
ret[m.group(1)] = int(m.group(2))
# Get the user ticks
ticks = self.get_user_ticks()
if isinstance(ret["system"], numbers.Number) and isinstance(ret["user"], numbers.Number):
ret["total"] = ret["system"] + ret["user"]
for k in ret.keys():
ret[k] = float(ret[k]) / ticks
# Return the stats
return ret
def get_docker_memory(self, id):
"""Return the container MEMORY usage by reading /sys/fs/cgroup/...
Input: id is the full container id
Output: a dict {'rss': 1015808, 'cache': 356352}"""
ret = {}
# Read the stats
with open('/sys/fs/cgroup/memory/docker/' + id + '/memory.stat', 'r') as f:
for line in f:
m = re.search(r"(rss|cache)\s+(\d+)", line)
if m:
ret[m.group(1)] = int(m.group(2))
# Return the stats
return ret
def get_user_ticks(self):
"""return the user ticks by reading the environment variable"""
return os.sysconf(os.sysconf_names['SC_CLK_TCK'])
def msg_curse(self, args=None):
"""Return the dict to display in the curse interface."""
# Init the return message
@ -175,6 +222,10 @@ class Plugin(GlancesPlugin):
ret.append(self.curse_add_line(msg))
msg = '{0:>26}'.format(_("Status"))
ret.append(self.curse_add_line(msg))
msg = '{0:>6}'.format(_("CPU%"))
ret.append(self.curse_add_line(msg))
msg = '{0:>6}'.format(_("MEM"))
ret.append(self.curse_add_line(msg))
msg = ' {0:8}'.format(_("Command"))
ret.append(self.curse_add_line(msg))
# Data
@ -196,6 +247,18 @@ class Plugin(GlancesPlugin):
msg = container['Status'].replace("minute", "min")
msg = '{0:>26}'.format(msg[0:25])
ret.append(self.curse_add_line(msg, status))
# CPU
try:
msg = '{0:>6.1f}'.format(container['cpu']['total'])
except KeyError:
msg = '{0:>6}'.format('?')
ret.append(self.curse_add_line(msg))
# MEM
try:
msg = '{0:>6}'.format(self.auto_unit(container['memory']['rss']))
except KeyError:
msg = '{0:>6}'.format('?')
ret.append(self.curse_add_line(msg))
# Command
msg = ' {0}'.format(container['Command'])
ret.append(self.curse_add_line(msg))