You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
4.1 KiB
Python

import os
import re
METRIC_NAME_RE = re.compile(r'^[a-zA-Z_:][a-zA-Z0-9_:]*$')
METRIC_LABEL_NAME_RE = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*$')
RESERVED_METRIC_LABEL_NAME_RE = re.compile(r'^__.*$')
def _init_legacy_validation() -> bool:
"""Retrieve name validation setting from environment."""
return os.environ.get("PROMETHEUS_LEGACY_NAME_VALIDATION", 'False').lower() in ('true', '1', 't')
_legacy_validation = _init_legacy_validation()
def get_legacy_validation() -> bool:
"""Return the current status of the legacy validation setting."""
return _legacy_validation
def disable_legacy_validation():
"""Disable legacy name validation, instead allowing all UTF8 characters."""
global _legacy_validation
_legacy_validation = False
def enable_legacy_validation():
"""Enable legacy name validation instead of allowing all UTF8 characters."""
global _legacy_validation
_legacy_validation = True
def _validate_metric_name(name: str) -> None:
"""Raises ValueError if the provided name is not a valid metric name.
This check uses the global legacy validation setting to determine the validation scheme.
"""
if not name:
raise ValueError("metric name cannot be empty")
if _legacy_validation:
if not METRIC_NAME_RE.match(name):
raise ValueError("invalid metric name " + name)
try:
name.encode('utf-8')
except UnicodeDecodeError:
raise ValueError("invalid metric name " + name)
def _is_valid_legacy_metric_name(name: str) -> bool:
"""Returns true if the provided metric name conforms to the legacy validation scheme."""
if len(name) == 0:
return False
return METRIC_NAME_RE.match(name) is not None
def _validate_metric_label_name_token(tok: str) -> None:
"""Raises ValueError if a parsed label name token is invalid.
UTF-8 names must be quoted.
"""
if not tok:
raise ValueError("invalid label name token " + tok)
quoted = tok[0] == '"' and tok[-1] == '"'
if not quoted or _legacy_validation:
if not METRIC_LABEL_NAME_RE.match(tok):
raise ValueError("invalid label name token " + tok)
return
try:
tok.encode('utf-8')
except UnicodeDecodeError:
raise ValueError("invalid label name token " + tok)
def _validate_labelname(l):
"""Raises ValueError if the provided name is not a valid label name.
This check uses the global legacy validation setting to determine the validation scheme.
"""
if get_legacy_validation():
if not METRIC_LABEL_NAME_RE.match(l):
raise ValueError('Invalid label metric name: ' + l)
if RESERVED_METRIC_LABEL_NAME_RE.match(l):
raise ValueError('Reserved label metric name: ' + l)
else:
try:
l.encode('utf-8')
except UnicodeDecodeError:
raise ValueError('Invalid label metric name: ' + l)
if RESERVED_METRIC_LABEL_NAME_RE.match(l):
raise ValueError('Reserved label metric name: ' + l)
def _is_valid_legacy_labelname(l: str) -> bool:
"""Returns true if the provided label name conforms to the legacy validation scheme."""
if len(l) == 0:
return False
if METRIC_LABEL_NAME_RE.match(l) is None:
return False
return RESERVED_METRIC_LABEL_NAME_RE.match(l) is None
def _validate_labelnames(cls, labelnames):
"""Raises ValueError if any of the provided names is not a valid label name.
This check uses the global legacy validation setting to determine the validation scheme.
"""
labelnames = tuple(labelnames)
for l in labelnames:
_validate_labelname(l)
if l in cls._reserved_labelnames:
raise ValueError('Reserved label methe fric name: ' + l)
return labelnames
def _validate_exemplar(exemplar):
"""Raises ValueError if the exemplar is invalid."""
runes = 0
for k, v in exemplar.items():
_validate_labelname(k)
runes += len(k)
runes += len(v)
if runes > 128:
raise ValueError('Exemplar labels have %d UTF-8 characters, exceeding the limit of 128')