Skip to content

Commit

Permalink
Add new version of OpenMetrics base class
Browse files Browse the repository at this point in the history
  • Loading branch information
ofek committed Jan 6, 2021
1 parent a602039 commit fb6a1ce
Show file tree
Hide file tree
Showing 24 changed files with 2,321 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
from .. import AgentCheck
from .mixins import OpenMetricsScraperMixin

if not PY2:
from .v2.base import OpenMetricsBaseCheckV2

STANDARD_FIELDS = [
'prometheus_url',
'namespace',
Expand Down Expand Up @@ -60,6 +63,17 @@ class OpenMetricsBaseCheck(OpenMetricsScraperMixin, AgentCheck):
'prometheus_timeout': {'name': 'timeout'},
}

def __new__(cls, *args, **kwargs):
# Legacy signature
if len(args) != 3:
return super(OpenMetricsBaseCheck, cls).__new__(cls)

instance = args[2][0]
if not PY2 and 'prometheus_endpoints' in instance:
return OpenMetricsBaseCheckV2(*args, **kwargs)
else:
return super(OpenMetricsBaseCheck, cls).__new__(cls)

def __init__(self, *args, **kwargs):
"""
The base class for any Prometheus-based integration.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ def create_scraper_configuration(self, instance=None):
A default mixin configuration will be returned if there is no instance.
"""
if 'prometheus_endpoints' in instance:
raise CheckException('The setting `prometheus_endpoints` is only available for Agent version 7 or later')

# We can choose to create a default mixin configuration for an empty instance
if instance is None:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# (C) Datadog, Inc. 2020-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# (C) Datadog, Inc. 2020-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from collections import OrderedDict
from contextlib import contextmanager

from ....errors import ConfigurationError
from ... import AgentCheck
from .scraper import OpenMetricsScraper

try:
from collections import ChainMap
except ImportError:
from chainmap import ChainMap


class OpenMetricsBaseCheckV2(AgentCheck):
DEFAULT_METRIC_LIMIT = 2000

def __init__(self, name, init_config, instances):
super(OpenMetricsBaseCheckV2, self).__init__(name, init_config, instances)

# All desired scraper configurations, which subclasses can override as needed
self.scraper_configs = [self.instance]

# All configured scrapers keyed by the endpoint
self.scrapers = OrderedDict()

self.check_initializations.append(self.configure_scrapers)

def check(self, _):
for endpoint, scraper in self.scrapers.items():
self.log.info('Scraping Prometheus endpoint: %s', endpoint)

with self.adopt_namespace(scraper.namespace):
scraper.scrape()

def configure_scrapers(self):
scrapers = OrderedDict()

for config in self.scraper_configs:
endpoints = config.get('prometheus_endpoints', [])
if not isinstance(endpoints, list):
raise ConfigurationError('Setting `prometheus_endpoints` must be an array')
elif not endpoints:
raise ConfigurationError('Setting `prometheus_endpoints` is required')

for i, endpoint in enumerate(endpoints, 1):
if not isinstance(endpoint, str):
raise ConfigurationError(
'Endpoint #{} of setting `prometheus_endpoints` must be a string'.format(i)
)
elif not endpoint:
raise ConfigurationError(
'Endpoint #{} of setting `prometheus_endpoints` must not be an empty string'.format(i)
)

scrapers[endpoint] = self.create_scraper(endpoint, config)

self.scrapers.clear()
self.scrapers.update(scrapers)

def create_scraper(self, endpoint, config):
# Subclasses can override to return a custom scraper based on configuration
return OpenMetricsScraper(self, endpoint, self.get_config_with_defaults(config))

def get_config_with_defaults(self, config):
return ChainMap(config, self.get_default_config())

def get_default_config(self):
return {}

@contextmanager
def adopt_namespace(self, namespace):
old_namespace = self.__NAMESPACE__

try:
self.__NAMESPACE__ = namespace or old_namespace
yield
finally:
self.__NAMESPACE__ = old_namespace
Loading

0 comments on commit fb6a1ce

Please sign in to comment.