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 12, 2021
1 parent 3d323ec commit 0351b1c
Show file tree
Hide file tree
Showing 35 changed files with 2,467 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 kwargs or len(args) != 3 or not isinstance(args[2], list):
return super(OpenMetricsBaseCheck, cls).__new__(cls)

instance = args[2][0]
if not PY2 and 'openmetrics_endpoint' 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,76 @@
# (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, _):
self.refresh_scrapers()

for endpoint, scraper in self.scrapers.items():
self.log.info('Scraping OpenMetrics endpoint: %s', endpoint)

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

def configure_scrapers(self):
scrapers = OrderedDict()

for config in self.scraper_configs:
endpoint = config.get('openmetrics_endpoint', '')
if not isinstance(endpoint, str):
raise ConfigurationError('The setting `openmetrics_endpoint` must be a string')
elif not endpoint:
raise ConfigurationError('The setting `openmetrics_endpoint` is required')

scrapers[endpoint] = self.create_scraper(config)

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

def create_scraper(self, config):
# Subclasses can override to return a custom scraper based on configuration
return OpenMetricsScraper(self, 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 {}

def refresh_scrapers(self):
pass

@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 0351b1c

Please sign in to comment.