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

Support new implementation of Windows performance counters on Python 3 #10546

Merged
merged 2 commits into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 2 additions & 24 deletions iis/assets/configuration/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ files:
options:
- template: init_config
options:
- template: init_config/perf_counters
- template: init_config/default
- template: instances
options:
Expand Down Expand Up @@ -39,30 +40,7 @@ files:
compact_example: false
items:
type: string
- name: is_2008
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't do anything

required: false
display_priority: 1
description: |
Because of a typo in IIS6/7 (typically on W2K8) where perfmon reports TotalBytesTransferred as
TotalBytesTransfered, you may have to enable this to grab the IIS metrics in that environment.
value:
example: false
type: boolean
- template: instances/pdh_legacy
overrides:
host.required: true
host.display_priority: 2
username.display_priority: 2
password.display_priority: 2
host.description: |
By default, this check runs against a single instance - the current
machine that the Agent is running on. It checks the PDH (Performance
Data Helper) performance counters for IIS on that machine.

"." means the current host, any other value makes the Agent attempt to connect to a remote host.
Note: Remote access requires additional permissions.
additional_metrics.value.example:
- ['Web Service', none, 'CGI Requests/sec', iis.httpd_request_method.cgi, gauge]
Comment on lines -64 to -65
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not working, I made a card to fix config spec nested overrides

- template: instances/perf_counters
- template: instances/default
- template: logs
example:
Expand Down
120 changes: 120 additions & 0 deletions iis/datadog_checks/iis/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# (C) Datadog, Inc. 2021-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from datadog_checks.base.checks.windows.perf_counters.base import PerfCountersBaseCheckWithLegacySupport
from datadog_checks.base.checks.windows.perf_counters.counter import PerfObject
from datadog_checks.base.constants import ServiceCheck

from .metrics import METRICS_CONFIG


class IISCheckV2(PerfCountersBaseCheckWithLegacySupport):
__NAMESPACE__ = 'iis'

def get_default_config(self):
metrics_config = {}
for object_name, config in METRICS_CONFIG.items():
new_config = config.copy()

include = []
if object_name == 'APP_POOL_WAS':
new_config['tag_name'] = 'app_pool'
include.extend(self.instance.get('app_pools', []))
elif object_name == 'Web Service':
new_config['tag_name'] = 'site'
include.extend(self.instance.get('sites', []))

if include:
new_config['include'] = [f'^{instance}$' for instance in include]

metrics_config[object_name] = new_config

return {'server_tag': 'iis_host', 'metrics': metrics_config}

def get_perf_object(self, connection, object_name, object_config, use_localized_counters, tags):
if object_name == 'APP_POOL_WAS':
return CompatibilityPerfObject(
self,
connection,
object_name,
object_config,
use_localized_counters,
tags,
'Current Application Pool Uptime',
'app_pool',
self.instance.get('app_pools', []),
)
elif object_name == 'Web Service':
return CompatibilityPerfObject(
self,
connection,
object_name,
object_config,
use_localized_counters,
tags,
'Service Uptime',
'site',
self.instance.get('sites', []),
)
else:
return super().get_perf_object(connection, object_name, object_config, use_localized_counters, tags)


class CompatibilityPerfObject(PerfObject):
def __init__(
self,
check,
connection,
object_name,
object_config,
use_localized_counters,
tags,
uptime_counter,
instance_type,
instances_included,
):
super().__init__(check, connection, object_name, object_config, use_localized_counters, tags)

self.uptime_counter = uptime_counter
self.instance_type = instance_type
self.instance_service_check_name = f'{self.instance_type}_up'
self.instances_included = set(instances_included)

# Resets during refreshes
self.instances_unseen = set()

def refresh(self):
self.instances_unseen.clear()
self.instances_unseen.update(self.instances_included)

for instance in sorted(self.instances_unseen):
self.logger.debug('Expecting %ss: %s', self.instance_type, instance)

super().refresh()

for instance in sorted(self.instances_unseen):
tags = [f'{self.instance_type}:{instance}']
tags.extend(self.tags)
self.logger.warning('Did not get any data for expected %s: %s', self.instance_type, instance)
self.check.service_check(self.instance_service_check_name, ServiceCheck.CRITICAL, tags=tags)

def _instance_excluded(self, instance):
self.instances_unseen.discard(instance)
return super()._instance_excluded(instance)

def get_custom_transformers(self):
return {self.uptime_counter: self.__get_uptime_transformer}

def __get_uptime_transformer(self, check, metric_name, modifiers):
gauge_method = check.gauge
service_check_method = check.service_check

def submit_uptime(value, tags=None):
gauge_method(metric_name, value, tags=tags)
service_check_method(
self.instance_service_check_name, ServiceCheck.CRITICAL if value == 0 else ServiceCheck.OK, tags=tags
)

del check
del modifiers
return submit_uptime
32 changes: 24 additions & 8 deletions iis/datadog_checks/iis/config_models/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,14 @@ def shared_service(field, value):
return get_default_field_value(field, value)


def instance_additional_metrics(field, value):
return get_default_field_value(field, value)
def shared_use_localized_counters(field, value):
return False


def instance_app_pools(field, value):
return get_default_field_value(field, value)


def instance_counter_data_types(field, value):
return get_default_field_value(field, value)


def instance_disable_generic_tags(field, value):
return False

Expand All @@ -28,18 +24,38 @@ def instance_empty_default_hostname(field, value):
return False


def instance_is_2008(field, value):
return False
def instance_enable_health_service_check(field, value):
return True


def instance_extra_metrics(field, value):
return get_default_field_value(field, value)


def instance_metrics(field, value):
return get_default_field_value(field, value)


def instance_min_collection_interval(field, value):
return 15


def instance_namespace(field, value):
return get_default_field_value(field, value)


def instance_password(field, value):
return get_default_field_value(field, value)


def instance_server(field, value):
return get_default_field_value(field, value)


def instance_server_tag(field, value):
return get_default_field_value(field, value)


def instance_service(field, value):
return get_default_field_value(field, value)

Expand Down
82 changes: 76 additions & 6 deletions iis/datadog_checks/iis/config_models/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,99 @@
# Licensed under a 3-clause BSD style license (see LICENSE)
from __future__ import annotations

from typing import Optional, Sequence
from typing import Literal, Mapping, Optional, Sequence, Union

from pydantic import BaseModel, root_validator, validator
from pydantic import BaseModel, Extra, Field, root_validator, validator

from datadog_checks.base.utils.functions import identity
from datadog_checks.base.utils.models import validation

from . import defaults, validators


class Counter(BaseModel):
class Config:
extra = Extra.allow
allow_mutation = False

aggregate: Optional[Union[bool, Literal['only']]]
average: Optional[bool]
metric_name: Optional[str]
name: Optional[str]
type: Optional[str]


class InstanceCounts(BaseModel):
class Config:
allow_mutation = False

monitored: Optional[str]
total: Optional[str]
unique: Optional[str]


class ExtraMetrics(BaseModel):
class Config:
allow_mutation = False

counters: Sequence[Mapping[str, Union[str, Counter]]]
exclude: Optional[Sequence[str]]
include: Optional[Sequence[str]]
instance_counts: Optional[InstanceCounts]
name: str
tag_name: Optional[str]
use_localized_counters: Optional[bool]


class Counter1(BaseModel):
class Config:
extra = Extra.allow
allow_mutation = False

aggregate: Optional[Union[bool, Literal['only']]]
average: Optional[bool]
metric_name: Optional[str]
name: Optional[str]
type: Optional[str]


class InstanceCounts1(BaseModel):
class Config:
allow_mutation = False

monitored: Optional[str]
total: Optional[str]
unique: Optional[str]


class Metrics(BaseModel):
class Config:
allow_mutation = False

counters: Sequence[Mapping[str, Union[str, Counter1]]]
exclude: Optional[Sequence[str]]
include: Optional[Sequence[str]]
instance_counts: Optional[InstanceCounts1]
name: str
tag_name: Optional[str]
use_localized_counters: Optional[bool]


class InstanceConfig(BaseModel):
class Config:
allow_mutation = False

additional_metrics: Optional[Sequence[Sequence[str]]]
app_pools: Optional[Sequence[str]]
counter_data_types: Optional[Sequence[str]]
disable_generic_tags: Optional[bool]
empty_default_hostname: Optional[bool]
host: str
is_2008: Optional[bool]
enable_health_service_check: Optional[bool]
extra_metrics: Optional[Mapping[str, ExtraMetrics]]
metrics: Optional[Mapping[str, Metrics]]
min_collection_interval: Optional[float]
namespace: Optional[str] = Field(None, regex='\\w*')
password: Optional[str]
server: Optional[str]
server_tag: Optional[str]
service: Optional[str]
sites: Optional[Sequence[str]]
tags: Optional[Sequence[str]]
Expand Down
1 change: 1 addition & 0 deletions iis/datadog_checks/iis/config_models/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class Config:
allow_mutation = False

service: Optional[str]
use_localized_counters: Optional[bool]

@root_validator(pre=True)
def _initial_validation(cls, values):
Expand Down
Loading