API refactor
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-10-07 16:25:52 +09:00
parent 76d0d86211
commit 91c7e04474
1171 changed files with 81940 additions and 44117 deletions

View File

@@ -6,22 +6,25 @@ from typing import (
Any, Callable, Dict, Iterable, List, Literal, Optional, Sequence, Tuple,
Type, TypeVar, Union,
)
import warnings
from . import values # retain this import style for testability
from .context_managers import ExceptionCounter, InprogressTracker, Timer
from .metrics_core import (
Metric, METRIC_LABEL_NAME_RE, METRIC_NAME_RE,
RESERVED_METRIC_LABEL_NAME_RE,
)
from .metrics_core import Metric
from .registry import Collector, CollectorRegistry, REGISTRY
from .samples import Exemplar, Sample
from .utils import floatToGoString, INF
from .validation import (
_validate_exemplar, _validate_labelnames, _validate_metric_name,
)
T = TypeVar('T', bound='MetricWrapperBase')
F = TypeVar("F", bound=Callable[..., Any])
def _build_full_name(metric_type, name, namespace, subsystem, unit):
if not name:
raise ValueError('Metric name should not be empty')
full_name = ''
if namespace:
full_name += namespace + '_'
@@ -37,31 +40,6 @@ def _build_full_name(metric_type, name, namespace, subsystem, unit):
return full_name
def _validate_labelname(l):
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)
def _validate_labelnames(cls, labelnames):
labelnames = tuple(labelnames)
for l in labelnames:
_validate_labelname(l)
if l in cls._reserved_labelnames:
raise ValueError('Reserved label metric name: ' + l)
return labelnames
def _validate_exemplar(exemplar):
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')
def _get_use_created() -> bool:
return os.environ.get("PROMETHEUS_DISABLE_CREATED_SERIES", 'False').lower() not in ('true', '1', 't')
@@ -110,8 +88,8 @@ class MetricWrapperBase(Collector):
def collect(self) -> Iterable[Metric]:
metric = self._get_metric()
for suffix, labels, value, timestamp, exemplar in self._samples():
metric.add_sample(self._name + suffix, labels, value, timestamp, exemplar)
for suffix, labels, value, timestamp, exemplar, native_histogram_value in self._samples():
metric.add_sample(self._name + suffix, labels, value, timestamp, exemplar, native_histogram_value)
return [metric]
def __str__(self) -> str:
@@ -138,8 +116,7 @@ class MetricWrapperBase(Collector):
self._documentation = documentation
self._unit = unit
if not METRIC_NAME_RE.match(self._name):
raise ValueError('Invalid metric name: ' + self._name)
_validate_metric_name(self._name)
if self._is_parent():
# Prepare the fields needed for child metrics.
@@ -210,6 +187,11 @@ class MetricWrapperBase(Collector):
return self._metrics[labelvalues]
def remove(self, *labelvalues: Any) -> None:
if 'prometheus_multiproc_dir' in os.environ or 'PROMETHEUS_MULTIPROC_DIR' in os.environ:
warnings.warn(
"Removal of labels has not been implemented in multi-process mode yet.",
UserWarning)
if not self._labelnames:
raise ValueError('No label names were set when constructing %s' % self)
@@ -218,10 +200,15 @@ class MetricWrapperBase(Collector):
raise ValueError('Incorrect label count (expected %d, got %s)' % (len(self._labelnames), labelvalues))
labelvalues = tuple(str(l) for l in labelvalues)
with self._lock:
del self._metrics[labelvalues]
if labelvalues in self._metrics:
del self._metrics[labelvalues]
def clear(self) -> None:
"""Remove all labelsets from the metric"""
if 'prometheus_multiproc_dir' in os.environ or 'PROMETHEUS_MULTIPROC_DIR' in os.environ:
warnings.warn(
"Clearing labels has not been implemented in multi-process mode yet",
UserWarning)
with self._lock:
self._metrics = {}
@@ -236,8 +223,8 @@ class MetricWrapperBase(Collector):
metrics = self._metrics.copy()
for labels, metric in metrics.items():
series_labels = list(zip(self._labelnames, labels))
for suffix, sample_labels, value, timestamp, exemplar in metric._samples():
yield Sample(suffix, dict(series_labels + list(sample_labels.items())), value, timestamp, exemplar)
for suffix, sample_labels, value, timestamp, exemplar, native_histogram_value in metric._samples():
yield Sample(suffix, dict(series_labels + list(sample_labels.items())), value, timestamp, exemplar, native_histogram_value)
def _child_samples(self) -> Iterable[Sample]: # pragma: no cover
raise NotImplementedError('_child_samples() must be implemented by %r' % self)
@@ -282,6 +269,12 @@ class Counter(MetricWrapperBase):
# Count only one type of exception
with c.count_exceptions(ValueError):
pass
You can also reset the counter to zero in case your logical "process" restarts
without restarting the actual python process.
c.reset()
"""
_type = 'counter'
@@ -300,6 +293,11 @@ class Counter(MetricWrapperBase):
_validate_exemplar(exemplar)
self._value.set_exemplar(Exemplar(exemplar, amount, time.time()))
def reset(self) -> None:
"""Reset the counter to zero. Use this when a logical process restarts without restarting the actual python process."""
self._value.set(0)
self._created = time.time()
def count_exceptions(self, exception: Union[Type[BaseException], Tuple[Type[BaseException], ...]] = Exception) -> ExceptionCounter:
"""Count exceptions in a block of code or function.
@@ -684,6 +682,8 @@ class Info(MetricWrapperBase):
if self._labelname_set.intersection(val.keys()):
raise ValueError('Overlapping labels for Info metric, metric: {} child: {}'.format(
self._labelnames, val))
if any(i is None for i in val.values()):
raise ValueError('Label value cannot be None')
with self._lock:
self._value = dict(val)