monasca-agent/monasca_agent/collector/checks_d/vertica.py

178 lines
9.0 KiB
Python

# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
import monasca_agent.collector.checks as checks
from monasca_agent.common.util import timeout_command
LICENSE_STATUS_QUERY = "SELECT COALESCE(" \
"(SELECT usage_percent * 100 " \
"FROM v_catalog.license_audits " \
"WHERE audited_data ='Total' " \
"ORDER BY audit_start_timestamp " \
"DESC LIMIT 1), 0) license_usage_percent;"
NODE_METRICS_QUERY = "SELECT node_state " \
"FROM NODES " \
"WHERE node_name = '{0}';"
PROJECTION_METRICS_QUERY = "SELECT projection_name, wos_used_bytes, ros_count, " \
"COALESCE(tuple_mover_moveouts, 0) tuple_mover_moveouts, " \
"COALESCE(tuple_mover_mergeouts, 0) tuple_mover_mergeouts " \
"FROM projection_storage " \
"LEFT JOIN (SELECT projection_id, " \
"SUM(case when operation_name = 'Moveout' then 1 else 0 end) tuple_mover_moveouts, " \
"SUM(case when operation_name = 'Mergeout' then 1 else 0 end) tuple_mover_mergeouts " \
"FROM tuple_mover_operations " \
"WHERE node_name = '{0}' and is_executing = 't' " \
"GROUP BY projection_id) tm " \
"ON projection_storage.projection_id = tm.projection_id " \
"WHERE node_name = '{0}';"
RESOURCE_METRICS_QUERY = "SELECT COALESCE(request_queue_depth, 0) request_queue_depth, " \
"wos_used_bytes, " \
"COALESCE(resource_request_reject_count, 0) resource_rejections, " \
"COALESCE(disk_space_request_reject_count, 0) disk_space_rejections " \
"FROM resource_usage " \
"WHERE node_name = '{0}';"
RESOURCE_POOL_METRICS_QUERY = "SELECT pool_name, memory_size_actual_kb, memory_inuse_kb, running_query_count, " \
"COALESCE(rejection_count, 0) rejection_count " \
"FROM resource_pool_status " \
"LEFT JOIN (" \
"SELECT pool_id, COUNT(*) rejection_count " \
"FROM resource_rejections " \
"WHERE node_name = '{0}' " \
"GROUP BY pool_id) rj " \
"ON resource_pool_status.POOL_OID = rj.POOL_ID " \
"WHERE node_name = '{0}'"
class Vertica(checks.AgentCheck):
def __init__(self, name, init_config, agent_config):
super(Vertica, self).__init__(name, init_config, agent_config)
self._last_connection_status = 1
@staticmethod
def _get_config(instance):
user = instance.get('user')
password = instance.get('password')
service = instance.get('service')
node_name = instance.get('node_name')
timeout = int(instance.get('timeout'))
return user, password, service, node_name, timeout
def check(self, instance):
user, password, service, node_name, timeout = self._get_config(instance)
dimensions = self._set_dimensions({'component': 'vertica', 'service': service}, instance)
query = self._build_query(node_name)
results, connection_status = self._query_database(user, password, timeout, query)
if connection_status != 0:
self.gauge('vertica.connection_status', 1, dimensions=dimensions)
self._last_connection_status = 1
else:
if self._last_connection_status > 0:
# report successful connection status when last status not success
self.gauge('vertica.connection_status', 0, dimensions=dimensions)
self._last_connection_status = 0
results = results.split('\n')
# Database metrics
self._report_license_status(results[0], dimensions)
# Node metrics
dimensions['node_name'] = node_name
self._report_node_status(results[1], dimensions)
self._report_resource_metrics(results[2], dimensions)
self._report_projection_metrics(results[3], dimensions)
self._report_resource_pool_metrics(results[4], dimensions)
def _query_database(self, user, password, timeout, query):
stdout, stderr, return_code = timeout_command(["/opt/vertica/bin/vsql", "-U", user, "-w", password, "-A", "-R",
"|", "-t", "-F", ",", "-x"], timeout, command_input=query)
if return_code == 0:
# remove trailing newline
stdout = stdout.rstrip()
return stdout, 0
else:
self.log.error("Error querying vertica with return code of {0} and error {1}".format(return_code, stderr))
return stderr, 1
def _build_query(self, node_name):
query = ''
query += LICENSE_STATUS_QUERY
query += NODE_METRICS_QUERY.format(node_name)
query += RESOURCE_METRICS_QUERY.format(node_name)
query += PROJECTION_METRICS_QUERY.format(node_name)
query += RESOURCE_POOL_METRICS_QUERY.format(node_name)
return query
def _results_to_dict(self, results):
return [dict(entry.split(',') for entry in dictionary.split('|')) for dictionary in results.split('||')]
def _report_node_status(self, results, dimensions):
result = self._results_to_dict(results)
node_status = result[0]['node_state']
status_metric = 0 if node_status == 'UP' else 1
self.gauge('vertica.node_status', status_metric, dimensions=dimensions, value_meta=result[0])
def _report_projection_metrics(self, results, dimensions):
results = self._results_to_dict(results)
projection_metric_name = 'vertica.projection.'
for result in results:
projection_dimensions = dimensions.copy()
projection_dimensions['projection_name'] = result['projection_name']
# when nothing has been written, wos_used_bytes is empty.
# Needs to convert it to zero.
if not result['wos_used_bytes']:
result['wos_used_bytes'] = '0'
self.gauge(projection_metric_name + 'wos_used_bytes', int(result['wos_used_bytes']),
dimensions=projection_dimensions)
self.gauge(projection_metric_name + 'ros_count', int(result['ros_count']), dimensions=projection_dimensions)
self.rate(projection_metric_name + 'tuple_mover_moveouts', int(result['tuple_mover_moveouts']),
dimensions=projection_dimensions)
self.rate(projection_metric_name + 'tuple_mover_mergeouts', int(result['tuple_mover_mergeouts']),
dimensions=projection_dimensions)
def _report_resource_metrics(self, results, dimensions):
results = self._results_to_dict(results)
resource_metric_name = 'vertica.resource.'
resource_metrics = results[0]
for metric_name, metric_value in resource_metrics.items():
if metric_name in ['resource_rejections', 'disk_space_rejections']:
self.rate(resource_metric_name + metric_name, int(metric_value), dimensions=dimensions)
else:
if metric_name == 'wos_used_bytes' and not metric_value:
# when nothing has been written, wos_used_bytes is empty.
# Needs to convert it to zero.
metric_value = '0'
self.gauge(resource_metric_name + metric_name, int(metric_value), dimensions=dimensions)
def _report_resource_pool_metrics(self, results, dimensions):
results = self._results_to_dict(results)
resource_pool_metric_name = 'vertica.resource.pool.'
for result in results:
resource_pool_dimensions = dimensions.copy()
resource_pool_dimensions['resource_pool'] = result['pool_name']
self.gauge(resource_pool_metric_name + 'memory_size_actual_kb', int(result['memory_size_actual_kb']),
dimensions=resource_pool_dimensions)
self.gauge(resource_pool_metric_name + 'memory_inuse_kb', int(result['memory_inuse_kb']),
dimensions=resource_pool_dimensions)
self.gauge(resource_pool_metric_name + 'running_query_count', int(result['running_query_count']),
dimensions=resource_pool_dimensions)
self.rate(resource_pool_metric_name + 'rejection_count', int(result['rejection_count']),
dimensions=resource_pool_dimensions)
def _report_license_status(self, results, dimensions):
results = self._results_to_dict(results)
license_status = results[0]
self.gauge('vertica.license_usage_percent', float(license_status['license_usage_percent']),
dimensions=dimensions)