10000 refactor · prometheus/client_python@2bffd2c · GitHub
[go: up one dir, main page]

Skip to content

Commit 2bffd2c

Browse files
committed
refactor
1 parent aac1c66 commit 2bffd2c

File tree

4 files changed

+121
-123
lines changed

4 files changed

+121
-123
lines changed

prometheus_client/metrics.py

Lines changed: 10 additions & 50 deletions
313
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010

1111
from . import values # retain this import style for testability
1212
from .context_managers import ExceptionCounter, InprogressTracker, Timer
13-
from .metrics_core import (
14-
get_legacy_validation, Metric, METRIC_LABEL_NAME_RE, METRIC_NAME_RE,
15-
RESERVED_METRIC_LABEL_NAME_RE
16-
)
13+
from .metrics_core import Metric
1714
from .registry import Collector, CollectorRegistry, REGISTRY
1815
from .samples import Exemplar, Sample
1916
from .utils import floatToGoString, INF
17+
from .validation import (
18+
validate_metric_name, validate_exemplar, validate_labelnames
19+
)
2020

2121
T = TypeVar('T', bound='MetricWrapperBase')
2222
F = TypeVar("F", bound=Callable[..., Any])
@@ -38,39 +38,6 @@ def _build_full_name(metric_type, name, namespace, subsystem, unit):
3838
return full_name
3939

4040

41-
def _validate_labelname(l):
42-
if get_legacy_validation():
43-
if not METRIC_LABEL_NAME_RE.match(l):
44-
raise ValueError('Invalid label metric name: ' + l)
45-
if RESERVED_METRIC_LABEL_NAME_RE.match(l):
46-
raise ValueError('Reserved label metric name: ' + l)
47-
else:
48-
try:
49-
l.encode('utf-8')
50-
except UnicodeDecodeError:
51-
raise ValueError('Invalid label metric name: ' + l)
52-
if RESERVED_METRIC_LABEL_NAME_RE.match(l):
53-
raise ValueError('Reserved label metric name: ' + l)
54-
55-
56-
def _validate_labelnames(cls, labelnames):
57-
labelnames = tuple(labelnames)
58-
for l in labelnames:
59-
_validate_labelname(l)
60-
if l in cls._reserved_labelnames:
61-
raise ValueError('Reserved label metric name: ' + l)
62-
return labelnames
63-
64-
65-
def _validate_exemplar(exemplar):
66-
runes = 0
67-
for k, v in exemplar.items():
68-
_validate_labelname(k)
69-
runes += len(k)
70-
runes += len(v)
71-
if runes > 128:
72-
raise ValueError('Exemplar labels have %d UTF-8 characters, exceeding the limit of 128')
73-
7441

7542
def _get_use_created() -> bool:
7643
return os.environ.get("PROMETHEUS_DISABLE_CREATED_SERIES", 'False').lower() not in ('true', '1', 't')
@@ -91,7 +58,6 @@ def enable_created_metrics():
9158
_use_created = True
9259

9360

94-
9561
class MetricWrapperBase(Collector):
9662
_type: Optional[str] = None
9763
_reserved_labelnames: Sequence[str] = ()
@@ -142,20 +108,14 @@ def __init__(self: T,
142108
_labelvalues: Optional[Sequence[str]] = None,
143109
) -> None:
144110 A3DB
self._name = _build_full_name(self._type, name, namespace, subsystem, unit)
145-
self._labelnames = _validate_labelnames(self, labelnames)
111+
self._labelnames = validate_labelnames(self, labelnames)
146112
self._labelvalues = tuple(_labelvalues or ())
147113
self._kwargs: Dict[str, Any] = {}
148114
self._documentation = documentation
149115
self._unit = unit
150116

151-
if get_legacy_validation():
152-
if not METRIC_NAME_RE.match(self._name):
153-
raise ValueError('Invalid metric name2: ' + self._name)
154-
else:
155-
try:
156-
self._name.encode('utf-8')
157-
except UnicodeDecodeError:
158-
raise ValueError('Invalid metric name3: ' + self._name)
117+
if not validate_metric_name(self._name):
118+
raise ValueError('Invalid metric name: ' + self._name)
159119

160120
if self._is_parent():
161121
# Prepare the fields needed for child metrics.
@@ -307,7 +267,7 @@ def f():
307267
# Count only one type of exception
308268
with c.count_exceptions(ValueError):
309269
pass
310-
270+
311271
You can also reset the counter to zero in case your logical "process" restarts
312272
without restarting the actual python process.
273
@@ -328,7 +288,7 @@ def inc(self, amount: float = 1, exemplar: Optional[Dict[str, str]] = None) -> N
328288
raise ValueError('Counters can only be incremented by non-negative amounts.')
329289
self._value.inc(amount)
330290
if exemplar:
331-
_validate_exemplar(exemplar)
291+
validate_exemplar(exemplar)
332292
self._value.set_exemplar(Exemplar(exemplar, amount, time.time()))
333293

334294
def reset(self) -> None:
@@ -667,7 +627,7 @@ def observe(self, amount: float, exemplar: Optional[Dict[str, str]] = None) -> N
667627
if amount <= bound:
668628
self._buckets[i].inc(1)
669629
if exemplar:
670-
_validate_exemplar(exemplar)
630+
validate_exemplar(exemplar)
671631
self._buckets[i].set_exemplar(Exemplar(exemplar, amount, time.time()))
672632
break
673633

prometheus_client/metrics_core.py

Lines changed: 2 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,12 @@
1-
import os
2-
import re
31
from typing import Dict, List, Optional, Sequence, Tuple, Union
42

53
from .samples import Exemplar, NativeHistogram, Sample, Timestamp
4+
from .validation import validate_metric_name
65

76
METRIC_TYPES = (
87
'counter', 'gauge', 'summary', 'histogram',
98
'gaugehistogram', 'unknown', 'info', 'stateset',
109
)
11-
METRIC_NAME_RE = re.compile(r'^[a-zA-Z_:][a-zA-Z0-9_:]*$')
12-
METRIC_LABEL_NAME_RE = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*$')
13-
RESERVED_METRIC_LABEL_NAME_RE = re.compile(r'^__.*$')
14-
15-
16-
def _init_legacy_validation() -> bool:
17-
print("getting value!", os.environ.get("PROMETHEUS_LEGACY_NAME_VALIDATION", 'False').lower() in ('true', '1', 't 10000 9;))
18-
return os.environ.get("PROMETHEUS_LEGACY_NAME_VALIDATION", 'False').lower() in ('true', '1', 't')
19-
20-
21-
_legacy_validation = _init_legacy_validation()
22-
23-
24-
def get_legacy_validation() -> bool:
25-
global _legacy_validation
26-
return _legacy_validation
27-
28-
29-
def disable_legacy_validation():
30-
"""Disable legacy name validation, instead allowing all UTF8 characters."""
31-
global _legacy_validation
32-
_legacy_validation = False
33-
34-
35-
def enable_legacy_validation():
36-
"""Enable legacy name validation instead of allowing all UTF8 characters."""
37-
global _legacy_validation
38-
_legacy_validation = True
39-
40-
41-
def valid_metric_name(name: str) -> bool:
42-
global _legacy_validation
43-
if _legacy_validation:
44-
return METRIC_NAME_RE.match(name)
45-
if not name:
46-
return False
47-
try:
48-
name.encode('utf-8')
49-
return True
50-
except UnicodeDecodeError:
51-
return False
52-
53-
54-
def valid_metric_name_token(tok: str) -> bool:
55-
global _legacy_validation
56-
quoted = tok[0] == '"' and tok[-1] == '"'
57-
if not quoted or _legacy_validation:
58-
return METRIC_NAME_RE.match(tok)
59-
if not tok:
60-
return False
61-
try:
62-
tok.encode('utf-8')
63-
return True
64-
except UnicodeDecodeError:
65-
return False
66-
67-
68-
def valid_metric_label_name_token(tok: str) -> bool:
69-
global _legacy_validation
70-
quoted = tok[0] == '"' and tok[-1] == '"'
71-
if not quoted or _legacy_validation:
72-
return METRIC_LABEL_NAME_RE.match(tok)
73-
if not tok:
74-
return False
75-
try:
76-
tok.encode('utf-8')
77-
return True
78-
except UnicodeDecodeError:
79-
return False
8010

8111

8212
class Metric:
@@ -91,7 +21,7 @@ class Metric:
9121
def __init__(self, name: str, documentation: str, typ: str, unit: str = ''):
9222
if unit and not name.endswith("_" + unit):
9323
name += "_" + unit
94-
if not valid_metric_name(name):
24+
if not validate_metric_name(name):
9525
raise ValueError('Invalid metric name: ' + name)
9626
self.name: str = name
9727
self.documentation: str = documentation

prometheus_client/openmetrics/parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import math
66
import re
77

8-
from ..metrics_core import Metric, valid_metric_name_token, valid_metric_label_name_token
8+
from ..metrics_core import Metric, valid_metric_label_name_token, valid_metric_name_token
99
from ..samples import BucketSpan, Exemplar, NativeHistogram, Sample, Timestamp
1010
from ..utils import floatToGoString
1111

prometheus_client/validation.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import os
2+
import re
3+
4+
METRIC_NAME_RE = re.compile(r'^[a-zA-Z_:][a-zA-Z0-9_:]*$')
5+
METRIC_LABEL_NAME_RE = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*$')
6+
RESERVED_METRIC_LABEL_NAME_RE = re.compile(r'^__.*$')
7+
8+
9+
def _init_legacy_validation() -> bool:
10+
"""Retrieve name validation setting from environment."""
11+
return os.environ.get("PROMETHEUS_LEGACY_NAME_VALIDATION", 'False').lower() in ('true', '1', 't')
12+
13+
14+
_legacy_validation = _init_legacy_validation()
15+
16+
17+
def get_legacy_validation() -> bool:
18+
global _legacy_validation
19+
return _legacy_validation
20+
21+
22+
def disable_legacy_validation():
23+
"""Disable legacy name validation, instead allowing all UTF8 characters."""
24+
global _legacy_validation
25+
_legacy_validation = False
26+
27+
28+
def enable_legacy_validation():
29+
"""Enable legacy name validation instead of allowing all UTF8 characters."""
30+
global _legacy_validation
31+
_legacy_validation = True
32+
33+
34+
def validate_metric_name(name: str) -> bool:
35+
if not name:
36+
return False
37+
global _legacy_validation
38+
if _legacy_validation:
39+
return METRIC_NAME_RE.match(name)
40+
try:
41+
name.encode('utf-8')
42+
return True
43+
except UnicodeDecodeError:
44+
return False
45+
46+
47+
def validate_metric_name_token(tok: str) -> bool:
48+
"""Check validity of a parsed metric name token. UTF-8 names must be quoted."""
49+
if not tok:
50+
return False
51+
global _legacy_validation
52+
quoted = tok[0] == '"' and tok[-1] == '"'
53+
if not quoted or _legacy_validation:
54+
return METRIC_NAME_RE.match(tok)
55+
try:
56+
tok.encode('utf-8')
57+
return True
58+
except UnicodeDecodeError:
59+
return False
60+
61+
62+
def validate_metric_label_name_token(tok: str) -> bool:
63+
"""Check validity of a parsed label name token. UTF-8 names must be quoted."""
64+
if not tok:
65+
return False
66+
global _legacy_validation
67+
quoted = tok[0] == '"' and tok[-1] == '"'
68+
if not quoted or _legacy_validation:
69+
return METRIC_LABEL_NAME_RE.match(tok)
70+
try:
71+
tok.encode('utf-8')
72+
return True
73+
except UnicodeDecodeError:
74+
return False
75+
76+
77+
def validate_labelname(l):
78+
if get_legacy_validation():
79+
if not METRIC_LABEL_NAME_RE.match(l):
80+
raise ValueError('Invalid label metric name: ' + l)
81+
if RESERVED_METRIC_LABEL_NAME_RE.match(l):
82+
raise ValueError('Reserved label metric name: ' + l)
83+
else:
84+
try:
85+
l.encode('utf-8')
86+
except UnicodeDecodeError:
87+
raise ValueError('Invalid label metric name: ' + l)
88+
if RESERVED_METRIC_LABEL_NAME_RE.match(l):
89+
raise ValueError('Reserved label metric name: ' + l)
90+
91+
92+
def validate_labelnames(cls, labelnames):
93+
labelnames = tuple(labelnames)
94+
for l in labelnames:
95+
validate_labelname(l)
96+
if l in cls._reserved_labelnames:
97+
raise ValueError('Reserved label metric name: ' + l)
98+
return labelnames
99+
100+
101+
def validate_exemplar(exemplar):
102+
runes = 0
103+
for k, v in exemplar.items():
104+
validate_labelname(k)
105+
runes += len(k)
106+
runes += len(v)
107+
if runes > 128:
108+
raise ValueError('Exemplar labels have %d UTF-8 characters, exceeding the limit of 128')

0 commit comments

Comments
 (0)
0