Fixed default process metrics.
The fix is from David Kennedy and then I added a much needed simple test to make sure it stays fixed. Change-Id: I79a562fd82834751fcd0bac7dd3b79d2d857696b
This commit is contained in:
parent
ffd53d8536
commit
f3b24fc0ac
|
@ -84,7 +84,7 @@ class ProcessCheck(checks.AgentCheck):
|
|||
# process metrics available for psutil versions 0.6.0 and later
|
||||
extended_metrics_0_6_0 = (self.is_psutil_version_later_than((0, 6, 0))
|
||||
and not util.Platform.is_win32())
|
||||
# On Windows get_ext_memory_info returns different metrics
|
||||
# On Windows ext_memory_info returns different metrics
|
||||
if extended_metrics_0_6_0:
|
||||
real = 0
|
||||
voluntary_ctx_switches = 0
|
||||
|
@ -116,10 +116,10 @@ class ProcessCheck(checks.AgentCheck):
|
|||
try:
|
||||
p = psutil.Process(pid)
|
||||
if extended_metrics_0_6_0:
|
||||
mem = p.get_ext_memory_info()
|
||||
mem = p.memory_info_ex()
|
||||
real += float((mem.rss - mem.shared) / 1048576)
|
||||
try:
|
||||
ctx_switches = p.get_num_ctx_switches()
|
||||
ctx_switches = p.num_ctx_switches()
|
||||
voluntary_ctx_switches += ctx_switches.voluntary
|
||||
involuntary_ctx_switches += ctx_switches.involuntary
|
||||
except NotImplementedError:
|
||||
|
@ -127,11 +127,11 @@ class ProcessCheck(checks.AgentCheck):
|
|||
voluntary_ctx_switches = None
|
||||
involuntary_ctx_switches = None
|
||||
else:
|
||||
mem = p.get_memory_info()
|
||||
mem = p.memory_info()
|
||||
|
||||
if extended_metrics_0_5_0_unix:
|
||||
try:
|
||||
open_file_descriptors = float(p.get_num_fds())
|
||||
open_file_descriptors = float(p.num_fds())
|
||||
max_open_file_descriptors = float(p.rlimit(psutil.RLIMIT_NOFILE)[1])
|
||||
if max_open_file_descriptors > 0.0:
|
||||
open_file_descriptors_perc = open_file_descriptors / max_open_file_descriptors * 100
|
||||
|
@ -142,13 +142,13 @@ class ProcessCheck(checks.AgentCheck):
|
|||
|
||||
rss += float(mem.rss / 1048576)
|
||||
vms += float(mem.vms / 1048576)
|
||||
thr += p.get_num_threads()
|
||||
cpu += p.get_cpu_percent(cpu_check_interval)
|
||||
thr += p.num_threads()
|
||||
cpu += p.cpu_percent(cpu_check_interval)
|
||||
|
||||
# user might not have permission to call get_io_counters()
|
||||
# user might not have permission to call io_counters()
|
||||
if read_count is not None:
|
||||
try:
|
||||
io_counters = p.get_io_counters()
|
||||
io_counters = p.io_counters()
|
||||
read_count += io_counters.read_count
|
||||
write_count += io_counters.write_count
|
||||
read_kbytes += float(io_counters.read_bytes / 1024)
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import os
|
||||
import sys
|
||||
import inspect
|
||||
|
||||
import monasca_agent.common.config as configuration
|
||||
from monasca_agent.common.util import Paths
|
||||
|
||||
# Base config must be loaded before AgentCheck or it will try to load with no config file
|
||||
base_config = configuration.Config(os.path.join(os.path.dirname(__file__), 'test-agent.yaml'))
|
||||
|
||||
from monasca_agent.collector.checks import AgentCheck
|
||||
|
||||
def load_check(name, config):
|
||||
checksd_path = Paths().get_checksd_path()
|
||||
if checksd_path not in sys.path:
|
||||
sys.path.append(checksd_path)
|
||||
|
||||
check_module = __import__(name)
|
||||
check_class = None
|
||||
classes = inspect.getmembers(check_module, inspect.isclass)
|
||||
for name, clsmember in classes:
|
||||
if clsmember == AgentCheck:
|
||||
continue
|
||||
if issubclass(clsmember, AgentCheck):
|
||||
check_class = clsmember
|
||||
if AgentCheck in clsmember.__bases__:
|
||||
continue
|
||||
else:
|
||||
break
|
||||
if check_class is None:
|
||||
raise Exception(
|
||||
"Unable to import check %s. Missing a class that inherits AgentCheck" % name)
|
||||
|
||||
init_config = config.get('init_config', None)
|
||||
instances = config.get('instances')
|
||||
|
||||
agent_config = base_config.get_config(sections='Main')
|
||||
# init the check class
|
||||
try:
|
||||
return check_class(
|
||||
name, init_config=init_config, agent_config=agent_config, instances=instances)
|
||||
except:
|
||||
# Backwards compatitiblity for old checks that don't support the
|
||||
# instances argument.
|
||||
c = check_class(name, init_config=init_config, agent_config=agent_config)
|
||||
c.instances = instances
|
||||
return c
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
Api:
|
||||
# To configure Keystone correctly, a project-scoped token must be acquired.
|
||||
# To accomplish this, the configuration must be set up with one of the
|
||||
# following scenarios:
|
||||
# Set username and password and you have a default project set in keystone.
|
||||
# Set username, password and project id.
|
||||
# Set username, password, project name and (domain id or domain name).
|
||||
#
|
||||
# Monitoring API URL: URL for the monitoring API, if undefined it will be pulled from the keystone service catalog
|
||||
# Example: https://region-a.geo-1.monitoring.hpcloudsvc.com:8080/v2.0
|
||||
url: http://localhost:8080
|
||||
# Keystone Username
|
||||
username: test
|
||||
# Keystone Password
|
||||
password: password
|
||||
# Keystone API URL: URL for the Keystone server to use
|
||||
# Example: https://region-a.geo-1.identity.hpcloudsvc.com:35357/v3/
|
||||
keystone_url: http://localhost:5000
|
||||
# Project name to be used by this agent
|
||||
project_name: test
|
||||
|
||||
# The following 2 options are for handling buffering and reconnection to the monasca-api
|
||||
# If you want the messages to be sent as fast as possible, set these two options to
|
||||
# the same number. If you have a larger system with many agents, you may want to throttle
|
||||
# the number of messages sent to the API by setting the backlog_send_rate to a lower number.
|
||||
|
||||
# Maximum number of messages to buffer when unable to communicate with the monasca-api
|
||||
max_buffer_size: 1000
|
||||
# Maximum number of messages to send at one time when communication with the monasca-api is restored
|
||||
backlog_send_rate: 1000
|
||||
|
||||
# Publish extra metrics to the API by adding this number of 'amplifier' dimensions.
|
||||
# For load testing purposes only; set to 0 for production use.
|
||||
|
||||
Main:
|
||||
# Force the hostname to whatever you want.
|
||||
hostname: localhost
|
||||
|
||||
Logging:
|
||||
# ========================================================================== #
|
||||
# Logging
|
||||
# ========================================================================== #
|
||||
log_level: DEBUG
|
||||
collector_log_file: /var/log/monasca/agent/collector.log
|
||||
forwarder_log_file: /var/log/monasca/agent/forwarder.log
|
||||
statsd_log_file: /var/log/monasca/agent/statsd.log
|
||||
|
||||
# if syslog is enabled but a host and port are not set, a local domain socket
|
||||
# connection will be attempted
|
||||
#
|
||||
# log_to_syslog: yes
|
||||
# syslog_host:
|
||||
# syslog_port:
|
|
@ -0,0 +1,56 @@
|
|||
import unittest
|
||||
|
||||
from tests.common import load_check
|
||||
|
||||
|
||||
class TestSimpleProcess(unittest.TestCase):
|
||||
def setUp(self):
|
||||
config = {'init_config': {}, 'instances': [{'name': 'test',
|
||||
'search_string': ['python'],
|
||||
'detailed': False}]}
|
||||
self.check = load_check('process', config)
|
||||
|
||||
def testPidCount(self):
|
||||
self.check.run()
|
||||
metrics = self.check.get_metrics()
|
||||
self.assertTrue(len(metrics) == 1, metrics)
|
||||
self.assertTrue(metrics[0].name == 'process.pid_count')
|
||||
|
||||
|
||||
class TestDetailedProcess(unittest.TestCase):
|
||||
def setUp(self):
|
||||
config = {'init_config': {}, 'instances': [{'name': 'test',
|
||||
'search_string': ['python'],
|
||||
'detailed': True}]}
|
||||
self.check = load_check('process', config)
|
||||
|
||||
def testPidCount(self):
|
||||
self.check.run()
|
||||
metrics = self.check.get_metrics()
|
||||
self.assertTrue(len(metrics) > 1, metrics)
|
||||
|
||||
def testMeasurements(self):
|
||||
self.check.run()
|
||||
metrics = self.check.get_metrics()
|
||||
|
||||
measurement_names = []
|
||||
for metric in metrics:
|
||||
measurement_names.append(metric.name)
|
||||
|
||||
measurement_names.sort()
|
||||
|
||||
expected_names = ['process.cpu_perc',
|
||||
'process.involuntary_ctx_switches',
|
||||
'process.io.read_count',
|
||||
'process.io.read_kbytes',
|
||||
'process.io.write_count',
|
||||
'process.io.write_kbytes',
|
||||
'process.mem.real_mbytes',
|
||||
'process.mem.rss_mbytes',
|
||||
'process.mem.vsz_mbytes',
|
||||
'process.open_file_descriptors',
|
||||
'process.open_file_descriptors_perc',
|
||||
'process.pid_count',
|
||||
'process.thread_count',
|
||||
'process.voluntary_ctx_switches']
|
||||
self.assertTrue(measurement_names == expected_names)
|
|
@ -8,42 +8,6 @@ from monasca_agent.common.util import Paths
|
|||
from monasca_agent.common.util import get_os
|
||||
|
||||
|
||||
def load_check(name, config, agent_config):
|
||||
checksd_path = Paths().get_checksd_path()
|
||||
if checksd_path not in sys.path:
|
||||
sys.path.append(checksd_path)
|
||||
|
||||
check_module = __import__(name)
|
||||
check_class = None
|
||||
classes = inspect.getmembers(check_module, inspect.isclass)
|
||||
for name, clsmember in classes:
|
||||
if clsmember == AgentCheck:
|
||||
continue
|
||||
if issubclass(clsmember, AgentCheck):
|
||||
check_class = clsmember
|
||||
if AgentCheck in clsmember.__bases__:
|
||||
continue
|
||||
else:
|
||||
break
|
||||
if check_class is None:
|
||||
raise Exception(
|
||||
"Unable to import check %s. Missing a class that inherits AgentCheck" % name)
|
||||
|
||||
init_config = config.get('init_config', None)
|
||||
instances = config.get('instances')
|
||||
|
||||
# init the check class
|
||||
try:
|
||||
return check_class(
|
||||
name, init_config=init_config, agent_config=agent_config, instances=instances)
|
||||
except:
|
||||
# Backwards compatitiblity for old checks that don't support the
|
||||
# instances argument.
|
||||
c = check_class(name, init_config=init_config, agent_config=agent_config)
|
||||
c.instances = instances
|
||||
return c
|
||||
|
||||
|
||||
def kill_subprocess(process_obj):
|
||||
try:
|
||||
process_obj.terminate()
|
||||
|
|
Loading…
Reference in New Issue