Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PDH to be able to use new agent signature #5936

Merged
merged 12 commits into from
Mar 23, 2020
158 changes: 79 additions & 79 deletions datadog_checks_base/datadog_checks/base/checks/win/winpdh_base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# (C) Datadog, Inc. 2018-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from collections import defaultdict
from typing import Dict, List

import win32wnet
from six import iteritems

Expand Down Expand Up @@ -28,81 +31,81 @@ class PDHBaseCheck(AgentCheck):
Windows only.
"""

def __init__(self, name, init_config, agentConfig, instances, counter_list):
AgentCheck.__init__(self, name, init_config, agentConfig, instances)
self._missing_counters = {}
self._metrics = {}
self._tags = {}
key = None
def __init__(self, *args, **kwargs): # To support optional agentConfig
# TODO: Change signature to (self, name, init_config, instances, counter_list) once subclasses have been edited
super(PDHBaseCheck, self).__init__(*args, **kwargs)
self._missing_counters = {} # type: Dict[str, tuple]
self._metrics = defaultdict(list) # type: Dict[int, List[List]] # This dictionary only has one key
self._tags = defaultdict(list) # type: Dict[int, List[str]] # This dictionary only has one key
self.refresh_counters = is_affirmative(self.instance.get('refresh_counters', True)) # type: bool
# TODO Remove once signature is restored to (self, name, init_config, instances, counter_list)
counter_list = kwargs.get('counter_list', args[-1]) # type: List[List[str]]

try:
for instance in instances:
key = hash_mutable(instance)

cfg_tags = instance.get('tags')
if cfg_tags is not None:
if not isinstance(cfg_tags, list):
self.log.error("Tags must be configured as a list")
raise ValueError("Tags must be type list, not %s" % str(type(cfg_tags)))
self._tags[key] = list(cfg_tags)

remote_machine = None
host = instance.get('host')
self._metrics[key] = []
if host is not None and host != ".":
try:
remote_machine = host

username = instance.get('username')
password = instance.get('password')
nr = self._get_netresource(remote_machine)
win32wnet.WNetAddConnection2(nr, password, username, 0)

except Exception as e:
self.log.error("Failed to make remote connection %s", str(e))
return

# counter_data_types allows the precision with which counters are queried
# to be configured on a per-metric basis. In the metric instance, precision
# should be specified as
# counter_data_types:
# - iis.httpd_request_method.get,int
# - iis.net.bytes_rcvd,float
#
# the above would query the counter associated with iis.httpd_request_method.get
# as an integer (LONG) and iis.net.bytes_rcvd as a double
datatypes = {}
precisions = instance.get('counter_data_types')
if precisions is not None:
if not isinstance(precisions, list):
self.log.warning("incorrect type for counter_data_type %s", str(precisions))
else:
for p in precisions:
k, v = p.split(",")
v = v.lower().strip()
if v in int_types:
self.log.info("Setting datatype for %s to integer", k)
datatypes[k] = DATA_TYPE_INT
elif v in double_types:
self.log.info("Setting datatype for %s to double", k)
datatypes[k] = DATA_TYPE_DOUBLE
else:
self.log.warning("Unknown data type %s", str(v))

self._make_counters(key, (counter_list, (datatypes, remote_machine, False, 'entry')))

# get any additional metrics in the instance
addl_metrics = instance.get('additional_metrics')
if addl_metrics is not None:
self._make_counters(
key, (addl_metrics, (datatypes, remote_machine, True, 'additional metric entry'))
)
self.instance_hash = hash_mutable(self.instance) # type: int
cfg_tags = self.instance.get('tags') # type: List[str]
if cfg_tags is not None:
if not isinstance(cfg_tags, list):
self.log.error("Tags must be configured as a list")
raise ValueError("Tags must be type list, not %s" % str(type(cfg_tags)))
self._tags[self.instance_hash] = list(cfg_tags)

remote_machine = None
host = self.instance.get('host')
if host is not None and host != ".":
try:
remote_machine = host

username = self.instance.get('username')
password = self.instance.get('password')
nr = self._get_netresource(remote_machine)
win32wnet.WNetAddConnection2(nr, password, username, 0)

except Exception as e:
self.log.error("Failed to make remote connection %s", str(e))
return

# counter_data_types allows the precision with which counters are queried
# to be configured on a per-metric basis. In the metric instance, precision
# should be specified as
# counter_data_types:
# - iis.httpd_request_method.get,int
# - iis.net.bytes_rcvd,float
#
# the above would query the counter associated with iis.httpd_request_method.get
# as an integer (LONG) and iis.net.bytes_rcvd as a double
datatypes = {}
precisions = self.instance.get('counter_data_types')
if precisions is not None:
if not isinstance(precisions, list):
self.log.warning("incorrect type for counter_data_type %s", str(precisions))
else:
for p in precisions:
k, v = p.split(",")
v = v.lower().strip()
if v in int_types:
self.log.info("Setting datatype for %s to integer", k)
datatypes[k] = DATA_TYPE_INT
elif v in double_types:
self.log.info("Setting datatype for %s to double", k)
datatypes[k] = DATA_TYPE_DOUBLE
else:
self.log.warning("Unknown data type %s", str(v))

self._make_counters(counter_data=(counter_list, (datatypes, remote_machine, False, 'entry')))

# get any additional metrics in the instance
addl_metrics = self.instance.get('additional_metrics')
if addl_metrics is not None:
self._make_counters(
counter_data=(addl_metrics, (datatypes, remote_machine, True, 'additional metric entry'))
)

except Exception as e:
self.log.debug("Exception in PDH init: %s", str(e))
raise

if key is None or not self._metrics.get(key):
if not self.instance_hash or not self._metrics.get(self.instance_hash):
raise AttributeError('No valid counters to collect')

def _get_netresource(self, remote_machine):
Expand Down Expand Up @@ -143,22 +146,18 @@ def _get_netresource(self, remote_machine):

def check(self, instance):
self.log.debug("PDHBaseCheck: check()")
key = hash_mutable(instance)
refresh_counters = is_affirmative(instance.get('refresh_counters', True))

if refresh_counters:
if self.refresh_counters:
for counter, values in list(iteritems(self._missing_counters)):
self._make_counters(key, ([counter], values))
self._make_counters(counter_data=([counter], values))

for inst_name, dd_name, metric_func, counter in self._metrics[key]:
for inst_name, dd_name, metric_func, counter in self._metrics[self.instance_hash]:
try:
if refresh_counters:
if self.refresh_counters:
counter.collect_counters()
vals = counter.get_all_values()
for instance_name, val in iteritems(vals):
tags = []
if key in self._tags:
tags = list(self._tags[key])
tags = list(self._tags.get(self.instance_hash, [])) # type: List[str]

if not counter.is_single_instance():
tag = "instance:%s" % instance_name
Expand All @@ -168,7 +167,8 @@ def check(self, instance):
# don't give up on all of the metrics because one failed
self.log.error("Failed to get data for %s %s: %s", inst_name, dd_name, str(e))

def _make_counters(self, key, counter_data):
def _make_counters(self, key=None, counter_data=([], ())): # Key left in for retrocompatibility
# type: (int, tuple) -> None
counter_list, (datatypes, remote_machine, check_instance, message) = counter_data

# list of the metrics. Each entry is itself an entry,
Expand Down Expand Up @@ -205,7 +205,7 @@ def _make_counters(self, key, counter_data):

entry = [inst_name, dd_name, m, obj]
self.log.debug('%s: %s', message, entry)
self._metrics[key].append(entry)
self._metrics[self.instance_hash].append(entry)

@classmethod
def _no_instance(cls, inst_name):
Expand Down