From f23ceda96befb834b171ac56e4fc0cada82668ea Mon Sep 17 00:00:00 2001 From: Lukasz Zajaczkowski Date: Wed, 25 Jul 2018 11:37:14 +0200 Subject: [PATCH] Enable the system metrics in Docker environment Story: 2003093 Task: 23185 Change-Id: I9700a6fcb650fbcf983f2a4f145b430876f12429 --- conf.d/cpu.yaml | 6 +- conf.d/disk.yaml | 6 +- conf.d/load.yaml | 6 +- conf.d/memory.yaml | 6 +- docs/Plugins.md | 48 ++++++++++ monasca_agent/collector/checks_d/cpu.py | 6 ++ monasca_agent/collector/checks_d/disk.py | 102 +++++++++++---------- monasca_agent/collector/checks_d/load.py | 9 +- monasca_agent/collector/checks_d/memory.py | 6 ++ 9 files changed, 142 insertions(+), 53 deletions(-) diff --git a/conf.d/cpu.yaml b/conf.d/cpu.yaml index f7d1f245..b6a10821 100644 --- a/conf.d/cpu.yaml +++ b/conf.d/cpu.yaml @@ -1,7 +1,11 @@ # (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP init_config: - +# process_fs_path: (optional) STRING. It will set up the path of the process +# filesystem. By default it's set for: /proc directory. +# Example: +# +# process_fs_path: /rootfs/proc instances: # Cpu check only supports one configured instance - name: cpu_stats diff --git a/conf.d/disk.yaml b/conf.d/disk.yaml index 5ccc28a1..e5be8d4a 100644 --- a/conf.d/disk.yaml +++ b/conf.d/disk.yaml @@ -1,7 +1,11 @@ # (C) Copyright 2015,2016 Hewlett Packard Enterprise Development Company LP init_config: - +# process_fs_path: (optional) STRING. It will set up the path of the process +# filesystem. By default it's set for: /proc directory. +# Example: +# +# process_fs_path: /rootfs/proc instances: # Disk check only supports one configured instance - name: disk_stats diff --git a/conf.d/load.yaml b/conf.d/load.yaml index 75c8e261..4d35d836 100644 --- a/conf.d/load.yaml +++ b/conf.d/load.yaml @@ -1,7 +1,11 @@ # (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP init_config: - +# process_fs_path: (optional) STRING. It will set up the path of the process +# filesystem. By default it's set for: /proc directory. +# Example: +# +# process_fs_path: /rootfs/proc instances: # Load check only supports one configured instance - name: load_stats diff --git a/conf.d/memory.yaml b/conf.d/memory.yaml index e8c341b1..22fd8bce 100644 --- a/conf.d/memory.yaml +++ b/conf.d/memory.yaml @@ -1,7 +1,11 @@ # (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP init_config: - +# process_fs_path: (optional) STRING. It will set up the path of the process +# filesystem. By default it's set for: /proc directory. +# Example: +# +# process_fs_path: /rootfs/proc instances: # Memory check only supports one configured instance - name: memory_stats diff --git a/docs/Plugins.md b/docs/Plugins.md index e9e1fcb3..e347f2d5 100644 --- a/docs/Plugins.md +++ b/docs/Plugins.md @@ -370,6 +370,54 @@ This section documents all the checks that are supplied by the Agent. ## System Metrics This section documents the system metrics that are sent by the Agent. +Docker environment: + +For Docker environment you can enable the system plugins by adding cpu, disk, +memory and load yaml files to the monasca-agent-collector container (mount +plugin files to /plugins.d/cpu|disk|memory|load.yaml). Additionally you have to +specify the path of the host process filesystem. In this case mount host root +directory `/` to `/rootfs` in the container. Docker compose example: + +``` +volumes: + - "/:/rootfs:ro" +``` + +Sample configurations: + +cpu.yaml +``` +init_config: + process_fs_path: /rootfs/proc +instances: +- name: cpu_stats +``` + +disk.yaml +``` +init_config: + process_fs_path: /rootfs/proc +instances: +- name: disk_stats + ignore_filesystem_types: iso9660,tmpfs,nsfs +``` + +memory.yaml +``` +init_config: + process_fs_path: /rootfs/proc +instances: +- name: memory_stats +``` + +load.yaml +``` +init_config: + process_fs_path: /rootfs/proc +instances: +- name: load_stats +``` + ### CPU | Metric Name | Dimensions | Semantics | | ----------- | ---------- | --------- | diff --git a/monasca_agent/collector/checks_d/cpu.py b/monasca_agent/collector/checks_d/cpu.py index 36d2476b..3eaef2d9 100644 --- a/monasca_agent/collector/checks_d/cpu.py +++ b/monasca_agent/collector/checks_d/cpu.py @@ -26,6 +26,12 @@ class Cpu(checks.AgentCheck): def __init__(self, name, init_config, agent_config): super(Cpu, self).__init__(name, init_config, agent_config) + process_fs_path_config = init_config.get('process_fs_path', None) + if process_fs_path_config: + psutil.PROCFS_PATH = process_fs_path_config + self.log.debug('The path of the process filesystem set to %s', process_fs_path_config) + else: + self.log.debug('The process_fs_path not set. Use default path: /proc') # psutil.cpu_percent and psutil.cpu_times_percent are called in # __init__ because the first time these two functions are called with # interval = 0.0 or None, it will return a meaningless 0.0 value diff --git a/monasca_agent/collector/checks_d/disk.py b/monasca_agent/collector/checks_d/disk.py index 2fc0dbc2..59d72228 100644 --- a/monasca_agent/collector/checks_d/disk.py +++ b/monasca_agent/collector/checks_d/disk.py @@ -27,6 +27,12 @@ class Disk(checks.AgentCheck): self._partition_error = set() super(Disk, self).__init__(name, init_config, agent_config) + process_fs_path_config = init_config.get('process_fs_path', None) + if process_fs_path_config: + psutil.PROCFS_PATH = process_fs_path_config + self.log.debug('The path of the process filesystem set to %s', process_fs_path_config) + else: + self.log.debug('The process_fs_path not set. Use default path: /proc') def _log_once_per_day(self, message): if message in self._partition_error: @@ -65,60 +71,60 @@ class Disk(checks.AgentCheck): if partition.fstype not in fs_types_to_ignore \ and (not device_blacklist_re or not device_blacklist_re.match(partition.device)): - try: - device_name = self._get_device_name(partition.device) - disk_usage = psutil.disk_usage(partition.mountpoint) - total_capacity += disk_usage.total - total_used += disk_usage.used - st = os.statvfs(partition.mountpoint) - except Exception as ex: - exception_name = ex.__class__.__name__ - self._log_once_per_day('Unable to access partition {} ' - 'with error: {}'.format(partition, - exception_name)) - continue + try: + device_name = self._get_device_name(partition.device) + disk_usage = psutil.disk_usage(partition.mountpoint) + total_capacity += disk_usage.total + total_used += disk_usage.used + st = os.statvfs(partition.mountpoint) + except Exception as ex: + exception_name = ex.__class__.__name__ + self._log_once_per_day('Unable to access partition {} ' + 'with error: {}'.format(partition, + exception_name)) + continue - if use_mount: - dimensions.update({'mount_point': partition.mountpoint}) - self.gauge("disk.space_used_perc", - disk_usage.percent, + if use_mount: + dimensions.update({'mount_point': partition.mountpoint}) + self.gauge("disk.space_used_perc", + disk_usage.percent, + device_name=device_name, + dimensions=dimensions) + disk_count += 1 + if st.f_files > 0: + self.gauge("disk.inode_used_perc", + round((float(st.f_files - st.f_ffree) / st.f_files) * 100, 2), device_name=device_name, dimensions=dimensions) disk_count += 1 - if st.f_files > 0: - self.gauge("disk.inode_used_perc", - round((float(st.f_files - st.f_ffree) / st.f_files) * 100, 2), - device_name=device_name, - dimensions=dimensions) - disk_count += 1 - log.debug('Collected {0} disk usage metrics for partition {1}'.format( - disk_count, - partition.mountpoint)) - disk_count = 0 - if send_io_stats: - try: - stats = disk_stats[device_name] - self.rate("io.read_req_sec", round(float(stats.read_count), 2), - device_name=device_name, dimensions=dimensions) - self.rate("io.write_req_sec", round(float(stats.write_count), 2), - device_name=device_name, dimensions=dimensions) - self.rate("io.read_kbytes_sec", - round(float(stats.read_bytes / 1024), 2), - device_name=device_name, dimensions=dimensions) - self.rate("io.write_kbytes_sec", - round(float(stats.write_bytes / 1024), 2), - device_name=device_name, dimensions=dimensions) - self.rate("io.read_time_sec", round(float(stats.read_time / 1000), 2), - device_name=device_name, dimensions=dimensions) - self.rate("io.write_time_sec", round(float(stats.write_time / 1000), 2), - device_name=device_name, dimensions=dimensions) + log.debug('Collected {0} disk usage metrics for partition {1}'.format( + disk_count, + partition.mountpoint)) + disk_count = 0 + if send_io_stats: + try: + stats = disk_stats[device_name] + self.rate("io.read_req_sec", round(float(stats.read_count), 2), + device_name=device_name, dimensions=dimensions) + self.rate("io.write_req_sec", round(float(stats.write_count), 2), + device_name=device_name, dimensions=dimensions) + self.rate("io.read_kbytes_sec", + round(float(stats.read_bytes / 1024), 2), + device_name=device_name, dimensions=dimensions) + self.rate("io.write_kbytes_sec", + round(float(stats.write_bytes / 1024), 2), + device_name=device_name, dimensions=dimensions) + self.rate("io.read_time_sec", round(float(stats.read_time / 1000), 2), + device_name=device_name, dimensions=dimensions) + self.rate("io.write_time_sec", round(float(stats.write_time / 1000), 2), + device_name=device_name, dimensions=dimensions) - log.debug('Collected 6 disk I/O metrics for' - 'partition {0}'.format(partition.mountpoint)) - except KeyError: - log.debug('No Disk I/O metrics available for' - ' {0}...Skipping'.format(device_name)) + log.debug('Collected 6 disk I/O metrics for' + 'partition {0}'.format(partition.mountpoint)) + except KeyError: + log.debug('No Disk I/O metrics available for' + ' {0}...Skipping'.format(device_name)) if send_rollup_stats: self.gauge("disk.total_space_mb", diff --git a/monasca_agent/collector/checks_d/load.py b/monasca_agent/collector/checks_d/load.py index 4c589d9a..87014a05 100644 --- a/monasca_agent/collector/checks_d/load.py +++ b/monasca_agent/collector/checks_d/load.py @@ -28,6 +28,7 @@ class Load(checks.AgentCheck): def __init__(self, name, init_config, agent_config): super(Load, self).__init__(name, init_config, agent_config) + self.process_fs_path_config = init_config.get('process_fs_path', None) def check(self, instance): """Capture load stats @@ -38,7 +39,13 @@ class Load(checks.AgentCheck): if util.Platform.is_linux(): try: - loadAvrgProc = open('/proc/loadavg', 'r') + if self.process_fs_path_config: + log.debug( + 'The path of the process filesystem set to %s', + self.process_fs_path_config) + loadAvrgProc = open(self.process_fs_path_config + '/loadavg', 'r') + else: + loadAvrgProc = open('/proc/loadavg', 'r') uptime = loadAvrgProc.readlines() loadAvrgProc.close() except Exception: diff --git a/monasca_agent/collector/checks_d/memory.py b/monasca_agent/collector/checks_d/memory.py index 9b6f0a5c..9179cc00 100644 --- a/monasca_agent/collector/checks_d/memory.py +++ b/monasca_agent/collector/checks_d/memory.py @@ -23,6 +23,12 @@ class Memory(checks.AgentCheck): def __init__(self, name, init_config, agent_config): super(Memory, self).__init__(name, init_config, agent_config) + process_fs_path_config = init_config.get('process_fs_path', None) + if process_fs_path_config: + psutil.PROCFS_PATH = process_fs_path_config + self.log.debug('The path of the process filesystem set to %s', process_fs_path_config) + else: + self.log.debug('The process_fs_path not set. Use default path: /proc') def check(self, instance): """Capture memory stats