Skip to content

Commit

Permalink
wildcard type_overrides
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmed-mez committed Jul 6, 2020
1 parent 8d9e010 commit d72d526
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from __future__ import division

import copy
from fnmatch import translate
from fnmatch import translate, fnmatch
from math import isinf, isnan
from os.path import isfile
from re import compile
Expand Down Expand Up @@ -247,6 +247,11 @@ def create_scraper_configuration(self, instance=None):
config['type_overrides'] = default_instance.get('type_overrides', {})
config['type_overrides'].update(instance.get('type_overrides', {}))

# `_matched_type_overrides` is a dictionary where we cache the known metric names
# that match the `type_overrides` wildcard configurations.
# Using `_matched_type_overrides` will avoid calling fnmatch in every check run.
config['_matched_type_overrides'] = {}

# Some metrics are retrieved from differents hosts and often
# a label can hold this information, this transfers it to the hostname
config['label_to_hostname'] = instance.get('label_to_hostname', default_instance.get('label_to_hostname', None))
Expand Down Expand Up @@ -392,7 +397,17 @@ def parse_metric_family(self, response, scraper_config):
self._send_telemetry_counter(
self.TELEMETRY_COUNTER_METRICS_INPUT_COUNT, len(metric.samples), scraper_config
)
metric.type = scraper_config['type_overrides'].get(metric.name, metric.type)
type_override = scraper_config['type_overrides'].get(metric.name)
matched_type_override = scraper_config['_matched_type_overrides'].get(metric.name)
if type_override:
metric.type = type_override
elif matched_type_override:
metric.type = matched_type_override
elif scraper_config['type_overrides']:
for name_pattern, new_type in iteritems(scraper_config['type_overrides']):
if fnmatch(metric.name, name_pattern):
metric.type = new_type
scraper_config['_matched_type_overrides'][metric.name] = new_type
if metric.type not in self.METRIC_TYPES:
continue
metric.name = self._remove_metric_prefix(metric.name, scraper_config)
Expand Down
48 changes: 47 additions & 1 deletion datadog_checks_base/tests/test_openmetrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ def close(self):
pass


FAKE_ENDPOINT = 'http://fake.endpoint:10055/metrics'


PROMETHEUS_CHECK_INSTANCE = {
'prometheus_url': 'http://fake.endpoint:10055/metrics',
'prometheus_url': FAKE_ENDPOINT,
'metrics': [{'process_virtual_memory_bytes': 'process.vm.bytes'}],
'namespace': 'prometheus',
# Defaults for checks that were based on PrometheusCheck
Expand Down Expand Up @@ -2534,3 +2537,46 @@ def test_http_handler(mocked_openmetrics_check_factory):

assert http_handler.options['headers']['accept-encoding'] == 'gzip'
assert http_handler.options['headers']['accept'] == 'text/plain'


def test_simple_type_overrides(aggregator, mocked_prometheus_check, text_data):
"""
Test that metric type is overridden correctly.
"""
check = mocked_prometheus_check
instance = copy.deepcopy(PROMETHEUS_CHECK_INSTANCE)
instance['type_overrides'] = {"process_virtual_memory_bytes": "counter"}

# Make sure we don't send counters as gauges
instance['send_monotonic_counter'] = True

config = check.get_scraper_config(instance)
config['_dry_run'] = False

check.poll = mock.MagicMock(return_value=MockResponse(text_data, text_content_type))
check.process(config)

aggregator.assert_metric('prometheus.process.vm.bytes', count=1, metric_type=aggregator.MONOTONIC_COUNT)


def test_wildcard_type_overrides(aggregator, mocked_prometheus_check, text_data):
"""
Test that metric type is overridden correctly with wildcard.
"""
check = mocked_prometheus_check
instance = copy.deepcopy(PROMETHEUS_CHECK_INSTANCE)
instance['type_overrides'] = {"*_virtual_memory_*": "counter"}

# Make sure we don't send counters as gauges
instance['send_monotonic_counter'] = True

config = check.get_scraper_config(instance)
config['_dry_run'] = False

check.poll = mock.MagicMock(return_value=MockResponse(text_data, text_content_type))
check.process(config)

aggregator.assert_metric('prometheus.process.vm.bytes', count=1, metric_type=aggregator.MONOTONIC_COUNT)

# assert that we're caching the result
assert check.config_map[FAKE_ENDPOINT]['_matched_type_overrides']['process_virtual_memory_bytes'] == 'counter'
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ instances:
## Type override allows you to override a type in the prometheus payload
## or type an untyped metrics (they're ignored by default).
## Supported <METRIC_TYPE> are `gauge`, `counter`, `histogram`, `summary`
## The "*" wildcard can be used to match multiple metric names.
#
# type_overrides:
# <METRIC_NAME>: <METRIC_TYPE>
Expand Down

0 comments on commit d72d526

Please sign in to comment.