(self, check, config)
The base class for any scraper overrides.
The base class for any scraper overrides.
The base class for any scraper overrides .
def __init__(self, check, config):
        """
        The base class for any scraper overrides.
        """

        self.config = config

        # Save a reference to the check instance
        self.check = check

        # Parse the configuration
        self.endpoint = config['openmetrics_endpoint']

        self.metric_transformer = MetricTransformer(self.check, config)
        self.label_aggregator = LabelAggregator(self.check, config)

        self.enable_telemetry = is_affirmative(config.get('telemetry', False))
        # Make every telemetry submission method a no-op to avoid many lookups of `self.enable_telemetry`
        if not self.enable_telemetry:
            for name, _ in inspect.getmembers(self, predicate=inspect.ismethod):
                if name.startswith('submit_telemetry_'):
                    setattr(self, name, no_op)

        # Prevent overriding an integration's defined namespace
        self.namespace = check.__NAMESPACE__ or config.get('namespace', '')
        if not isinstance(self.namespace, str):
            raise ConfigurationError('Setting `namespace` must be a string')

        self.raw_metric_prefix = config.get('raw_metric_prefix', '')
        if not isinstance(self.raw_metric_prefix, str):
            raise ConfigurationError('Setting `raw_metric_prefix` must be a string')

        self.enable_health_service_check = is_affirmative(config.get('enable_health_service_check', True))

        self.hostname_label = config.get('hostname_label', '')
        if not isinstance(self.hostname_label, str):
            raise ConfigurationError('Setting `hostname_label` must be a string')

        hostname_format = config.get('hostname_format', '')
        if not isinstance(hostname_format, str):
            raise ConfigurationError('Setting `hostname_format` must be a string')

        self.hostname_formatter = None
        if self.hostname_label and hostname_format:
            placeholder = '<HOSTNAME>'
            if placeholder not in hostname_format:
                raise ConfigurationError(f'Setting `hostname_format` does not contain the placeholder `{placeholder}`')

            self.hostname_formatter = lambda hostname: hostname_format.replace('<HOSTNAME>', hostname, 1)

        exclude_labels = config.get('exclude_labels', [])
        if not isinstance(exclude_labels, list):
            raise ConfigurationError('Setting `exclude_labels` must be an array')

        self.exclude_labels = set()
        for i, entry in enumerate(exclude_labels, 1):
            if not isinstance(entry, str):
                raise ConfigurationError(f'Entry #{i} of setting `exclude_labels` must be a string')

            self.exclude_labels.add(entry)

        include_labels = config.get('include_labels', [])
        if not isinstance(include_labels, list):
            raise ConfigurationError('Setting `include_labels` must be an array')
        self.include_labels = set()
        for i, entry in enumerate(include_labels, 1):
            if not isinstance(entry, str):
                raise ConfigurationError(f'Entry #{i} of setting `include_labels` must be a string')
            if entry in self.exclude_labels:
                self.log.debug(
                    'Label `%s` is set in both `exclude_labels` and `include_labels`. Excluding label.', entry
                )
            self.include_labels.add(entry)

        self.rename_labels = config.get('rename_labels', {})
        if not isinstance(self.rename_labels, dict):
            raise ConfigurationError('Setting `rename_labels` must be a mapping')

        for key, value in self.rename_labels.items():
            if not isinstance(value, str):
                raise ConfigurationError(f'Value for label `{key}` of setting `rename_labels` must be a string')

        exclude_metrics = config.get('exclude_metrics', [])
        if not isinstance(exclude_metrics, list):
            raise ConfigurationError('Setting `exclude_metrics` must be an array')

        self.exclude_metrics = set()
        self.exclude_metrics_pattern = None
        exclude_metrics_patterns = []
        for i, entry in enumerate(exclude_metrics, 1):
            if not isinstance(entry, str):
                raise ConfigurationError(f'Entry #{i} of setting `exclude_metrics` must be a string')

            escaped_entry = re.escape(entry)
            if entry == escaped_entry:
                self.exclude_metrics.add(entry)
            else:
                exclude_metrics_patterns.append(entry)

        if exclude_metrics_patterns:
            self.exclude_metrics_pattern = re.compile('|'.join(exclude_metrics_patterns))

        self.exclude_metrics_by_labels = {}
        exclude_metrics_by_labels = config.get('exclude_metrics_by_labels', {})
        if not isinstance(exclude_metrics_by_labels, dict):
            raise ConfigurationError('Setting `exclude_metrics_by_labels` must be a mapping')
        elif exclude_metrics_by_labels:
            for label, values in exclude_metrics_by_labels.items():
                if values is True:
                    self.exclude_metrics_by_labels[label] = return_true
                elif isinstance(values, list):
                    for i, value in enumerate(values, 1):
                        if not isinstance(value, str):
                            raise ConfigurationError(
                                f'Value #{i} for label `{label}` of setting `exclude_metrics_by_labels` '
                                f'must be a string'
                            )

                    self.exclude_metrics_by_labels[label] = (
                        lambda label_value, pattern=re.compile('|'.join(values)): pattern.search(label_value)
                        is not None
                    )
                else:
                    raise ConfigurationError(
                        f'Label `{label}` of setting `exclude_metrics_by_labels` must be an array or set to `true`'
                    )

        custom_tags = config.get('tags', [])
        if not isinstance(custom_tags, list):
            raise ConfigurationError('Setting `tags` must be an array')

        for i, entry in enumerate(custom_tags, 1):
            if not isinstance(entry, str):
                raise ConfigurationError(f'Entry #{i} of setting `tags` must be a string')

        # Some tags can be ignored to reduce the cardinality.
        # This can be useful for cost optimization in containerized environments
        # when the openmetrics check is configured to collect custom metrics.
        # Even when the Agent's Tagger is configured to add low-cardinality tags only,
        # some tags can still generate unwanted metric contexts (e.g pod annotations as tags).
        ignore_tags = config.get('ignore_tags', [])
        if ignore_tags:
            ignored_tags_re = re.compile('|'.join(set(ignore_tags)))
            custom_tags = [tag for tag in custom_tags if not ignored_tags_re.search(tag)]

        # These will be applied only to service checks
        self.static_tags = [f'endpoint:{self.endpoint}']
        self.static_tags.extend(custom_tags)
        self.static_tags = tuple(self.static_tags)

        # These will be applied to everything except service checks
        self.tags = self.static_tags

        self.raw_line_filter = None
        raw_line_filters = config.get('raw_line_filters', [])
        if not isinstance(raw_line_filters, list):
            raise ConfigurationError('Setting `raw_line_filters` must be an array')
        elif raw_line_filters:
            for i, entry in enumerate(raw_line_filters, 1):
                if not isinstance(entry, str):
                    raise ConfigurationError(f'Entry #{i} of setting `raw_line_filters` must be a string')

            self.raw_line_filter = re.compile('|'.join(raw_line_filters))

        self.http = RequestsWrapper(config, self.check.init_config, self.check.HTTP_CONFIG_REMAPPER, self.check.log)

        # Decide how strictly we will adhere to the latest version of the specification
        if is_affirmative(config.get('use_latest_spec', False)):
            self.parse_metric_families = parse_metric_families_strict
            # https://github.com/prometheus/client_python/blob/v0.9.0/prometheus_client/openmetrics/exposition.py#L7
            self.http.options['headers'].setdefault(
                'Accept', 'application/openmetrics-text; version=0.0.1; charset=utf-8'
            )
        else:
            self.parse_metric_families = parse_metric_families
            self.http.options['headers'].setdefault('Accept', 'text/plain')

        self.use_process_start_time = is_affirmative(config.get('use_process_start_time'))

        # Used for monotonic counts
        self.flush_first_value = False
def __init__ ( self , check , config ) : self . config = config # Save a reference to the check instance self . check = check # Parse the configuration self . endpoint = config [ 'openmetrics_endpoint' ] self . metric_transformer = MetricTransformer ( self . check , config ) self . label_aggregator = LabelAggregator ( self . check , config ) self . enable_telemetry = is_affirmative ( config . get ( 'telemetry' , False ) ) # Make every telemetry submission method a no-op to avoid many lookups of `self.enable_telemetry` if not self . enable_telemetry : for name , _ in inspect . getmembers ( self , predicate = inspect . ismethod ) : if name . startswith ( 'submit_telemetry_' ) : setattr ( self , name , no_op ) # Prevent overriding an integration's defined namespace self . namespace = check . __NAMESPACE__ or config . get ( 'namespace' , '' ) if not isinstance ( self . namespace , str ) : raise ConfigurationError ( 'Setting `namespace` must be a string' ) self . raw_metric_prefix = config . get ( 'raw_metric_prefix' , '' ) if not isinstance ( self . raw_metric_prefix , str ) : raise ConfigurationError ( 'Setting `raw_metric_prefix` must be a string' ) self . enable_health_service_check = is_affirmative ( config . get ( 'enable_health_service_check' , True ) ) self . hostname_label = config . get ( 'hostname_label' , '' ) if not isinstance ( self . hostname_label , str ) : raise ConfigurationError ( 'Setting `hostname_label` must be a string' ) hostname_format = config . get ( 'hostname_format' , '' ) if not isinstance ( hostname_format , str ) : raise ConfigurationError ( 'Setting `hostname_format` must be a string' ) self . hostname_formatter = None if self . hostname_label and hostname_format : placeholder = '<HOSTNAME>' if placeholder not in hostname_format : raise ConfigurationError ( f'Setting `hostname_format` does not contain the placeholder `{placeholder}`' ) self . hostname_formatter = lambda hostname : hostname_format . replace ( '<HOSTNAME>' , hostname , 1 ) exclude_labels = config . get ( 'exclude_labels' , [ ] ) if not isinstance ( exclude_labels , list ) : raise ConfigurationError ( 'Setting `exclude_labels` must be an array' ) self . exclude_labels = set ( ) for i , entry in enumerate ( exclude_labels , 1 ) : if not isinstance ( entry , str ) : raise ConfigurationError ( f'Entry #{i} of setting `exclude_labels` must be a string' ) self . exclude_labels . add ( entry ) include_labels = config . get ( 'include_labels' , [ ] ) if not isinstance ( include_labels , list ) : raise ConfigurationError ( 'Setting `include_labels` must be an array' ) self . include_labels = set ( ) for i , entry in enumerate ( include_labels , 1 ) : if not isinstance ( entry , str ) : raise ConfigurationError ( f'Entry #{i} of setting `include_labels` must be a string' ) if entry in self . exclude_labels : self . log . debug ( 'Label `%s` is set in both `exclude_labels` and `include_labels`. Excluding label.' , entry ) self . include_labels . add ( entry ) self . rename_labels = config . get ( 'rename_labels' , { } ) if not isinstance ( self . rename_labels , dict ) : raise ConfigurationError ( 'Setting `rename_labels` must be a mapping' ) for key , value in self . rename_labels . items ( ) : if not isinstance ( value , str ) : raise ConfigurationError ( f'Value for label `{key}` of setting `rename_labels` must be a string' ) exclude_metrics = config . get ( 'exclude_metrics' , [ ] ) if not isinstance ( exclude_metrics , list ) : raise ConfigurationError ( 'Setting `exclude_metrics` must be an array' ) self . exclude_metrics = set ( ) self . exclude_metrics_pattern = None exclude_metrics_patterns = [ ] for i , entry in enumerate ( exclude_metrics , 1 ) : if not isinstance ( entry , str ) : raise ConfigurationError ( f'Entry #{i} of setting `exclude_metrics` must be a string' ) escaped_entry = re . escape ( entry ) if entry == escaped_entry : self . exclude_metrics . add ( entry ) else : exclude_metrics_patterns . append ( entry ) if exclude_metrics_patterns : self . exclude_metrics_pattern = re . compile ( '|' . join ( exclude_metrics_patterns ) ) self . exclude_metrics_by_labels = { } exclude_metrics_by_labels = config . get ( 'exclude_metrics_by_labels' , { } ) if not isinstance ( exclude_metrics_by_labels , dict ) : raise ConfigurationError ( 'Setting `exclude_metrics_by_labels` must be a mapping' ) elif exclude_metrics_by_labels : for label , values in exclude_metrics_by_labels . items ( ) : if values is True : self . exclude_metrics_by_labels [ label ] = return_true elif isinstance ( values , list ) : for i , value in enumerate ( values , 1 ) : if not isinstance ( value , str ) : raise ConfigurationError ( f'Value #{i} for label `{label}` of setting `exclude_metrics_by_labels` ' f'must be a string' ) self . exclude_metrics_by_labels [ label ] = ( lambda label_value , pattern = re . compile ( '|' . join ( values ) ) : pattern . search ( label_value ) is not None ) else : raise ConfigurationError ( f'Label `{label}` of setting `exclude_metrics_by_labels` must be an array or set to `true`' ) custom_tags = config . get ( 'tags' , [ ] ) if not isinstance ( custom_tags , list ) : raise ConfigurationError ( 'Setting `tags` must be an array' ) for i , entry in enumerate ( custom_tags , 1 ) : if not isinstance ( entry , str ) : raise ConfigurationError ( f'Entry #{i} of setting `tags` must be a string' ) # Some tags can be ignored to reduce the cardinality. # This can be useful for cost optimization in containerized environments # when the openmetrics check is configured to collect custom metrics. # Even when the Agent's Tagger is configured to add low-cardinality tags only, # some tags can still generate unwanted metric contexts (e.g pod annotations as tags). ignore_tags = config . get ( 'ignore_tags' , [ ] ) if ignore_tags : ignored_tags_re = re . compile ( '|' . join ( set ( ignore_tags ) ) ) custom_tags = [ tag for tag in custom_tags if not ignored_tags_re . search ( tag ) ] # These will be applied only to service checks self . static_tags = [ f'endpoint:{self.endpoint}' ] self . static_tags . extend ( custom_tags ) self . static_tags = tuple ( self . static_tags ) # These will be applied to everything except service checks self . tags = self . static_tags self . raw_line_filter = None raw_line_filters = config . get ( 'raw_line_filters' , [ ] ) if not isinstance ( raw_line_filters , list ) : raise ConfigurationError ( 'Setting `raw_line_filters` must be an array' ) elif raw_line_filters : for i , entry in enumerate ( raw_line_filters , 1 ) : if not isinstance ( entry , str ) : raise ConfigurationError ( f'Entry #{i} of setting `raw_line_filters` must be a string' ) self . raw_line_filter = re . compile ( '|' . join ( raw_line_filters ) ) self . http = RequestsWrapper ( config , self . check . init_config , self . check . HTTP_CONFIG_REMAPPER , self . check . log ) # Decide how strictly we will adhere to the latest version of the specification if is_affirmative ( config . get ( 'use_latest_spec' , False ) ) : self . parse_metric_families = parse_metric_families_strict # https://github.com/prometheus/client_python/blob/v0.9.0/prometheus_client/openmetrics/exposition.py#L7 self . http . options [ 'headers' ] . setdefault ( 'Accept' , 'application/openmetrics-text; version=0.0.1; charset=utf-8' ) else : self . parse_metric_families = parse_metric_families self . http . options [ 'headers' ] . setdefault ( 'Accept' , 'text/plain' ) self . use_process_start_time = is_affirmative ( config . get ( 'use_process_start_time' ) ) # Used for monotonic counts self . flush_first_value = False