Прометей REGISTRY.get_sample_value возвращает None - PullRequest
0 голосов
/ 14 мая 2019

Я пытаюсь написать комбинированный трекер метрик RED в качестве менеджера контекста, который должен увеличивать соответствующие метрики при использовании.Однако, похоже, что либо а) мои метрики не вызываются (что я не могу себе представить, чтобы иметь место), либо я не получаю их правильно, так как REGISTRY.get_sample_value('<metric_name>', [method, path]) возвращает None.

Учитывая следующееКод и тесты:

>>> metrics_tracker.py
from prometheus_client import Counter, Histogram


HTTP_REQUESTS_TOTAL = Counter('http_requests_total', 'Total amount of HTTP Requests made.', labelnames=['method', 'path'])
HTTP_EXCEPTIONS_TOTAL = Counter('http_exceptions_total', 'Total amount of HTTP exceptions.', labelnames=['method', 'path'])
HTTP_REQUESTS_LATENCY = Histogram('http_requests_latency_seconds', 'Duration of HTTP requests processing.', labelnames=['method', 'path'])


class REDMetricsTracker:
    """Prometheus RED metrics tracker class."""
    def __init__(self, method, path):
        self.method, self.path = method, path
        self.timer = None

    def __enter__(self):
        HTTP_REQUESTS_TOTAL.labels(self.method, self.path).inc()
        self.start = timeit.default_timer()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_val:
            HTTP_EXCEPTIONS_TOTAL.labels(self.method, self.path).inc()

        duration = max(timeit.default_timer() - self.start, 0)
        HTTP_REQUESTS_LATENCY.labels(self.method, self.path).observe(duration)
>>>test_metrics_tracker.py
from prometheus_client import REGISTRY

from scenario_player.services.common.metrics import REDMetricsTracker


def trigger_metrics(method, path, wait=False, raise_exc=False):
    with REDMetricsTracker(method, path):
        print("printing stuff")
        if wait:
            print("waiting a few seconds..")
            time.sleep(2)
        if raise_exc:
            print("raising an exception..")
            raise ValueError
        print("Not raising an exception")
    print("Returning.")


class TestREDMetricContextManager:

    def test_requests_made_counter(self):
        method, path = 'TEST', 'PATH'
        before = REGISTRY.get_sample_value('http_requests_total', [method, path]) or 0

        trigger_metrics(method, path)

        after = REGISTRY.get_sample_value('http_requests_total', [method, path])
        assert after - before == 1

    def test_requests_exceptions_counter(self):
        method, path = 'TEST', 'PATH'
        before = REGISTRY.get_sample_value('http_exceptions_total', [method, path]) or 0

        with pytest.raises(ValueError):
            trigger_metrics(method, path, raise_exc=True)

        after = REGISTRY.get_sample_value('http_exceptions_total', [method, path])
        assert after - before == 1

    def test_request_latency_count(self):
        method, path = 'TEST', 'PATH'

        before = REGISTRY.get_sample_value('http_requests_latency_seconds_count', [method, path]) or 0

        trigger_metrics(method, path, wait=True)

        after = REGISTRY.get_sample_value('http_requests_latency_seconds_count', [method, path])

        assert after - before == 1

    def test_request_latency_sum(self):
        method, path = 'TEST', 'PATH'

        before = REGISTRY.get_sample_value('http_requests_latency_seconds_sum', [method, path]) or 0

        trigger_metrics(method, path, wait=True)

        after = REGISTRY.get_sample_value('http_requests_latency_seconds_sum', [method, path])

        diff = after - before

        # Check the difference is roughly in the ballpark of what we expect.
        assert (diff >= 2) and (diff <= 3)

Со следующим результатом:

(scenario-player) X280 /home/nls/devel/scenario-player$ pytest tests/unit-tests/services/common/test_metrics.py
======================================================================= test session starts =======================================================================
platform linux -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.11.0
rootdir: /home/nls/devel/scenario-player
collected 4 items

tests/unit-tests/services/common/test_metrics.py FFFF                                                                                                       [100%]

============================================================================ FAILURES =============================================================================
_____________________________________________________ TestREDMetricContextManager.test_requests_made_counter ______________________________________________________

self = <common.test_metrics.TestREDMetricContextManager object at 0x7fb1d6a9ed30>

    def test_requests_made_counter(self):
        method, path = 'TEST', 'PATH'
        before = REGISTRY.get_sample_value('http_requests_total', [method, path]) or 0

        trigger_metrics(method, path)

        after = REGISTRY.get_sample_value('http_requests_total', [method, path])
>       assert after - before == 1
E       TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

tests/unit-tests/services/common/test_metrics.py:32: TypeError
---------------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------------
printing stuff
Not raising an exception
Returning.
__________________________________________________ TestREDMetricContextManager.test_requests_exceptions_counter ___________________________________________________

self = <common.test_metrics.TestREDMetricContextManager object at 0x7fb1d6a78160>

    def test_requests_exceptions_counter(self):
        method, path = 'TEST', 'PATH'
        before = REGISTRY.get_sample_value('http_exceptions_total', [method, path]) or 0

        with pytest.raises(ValueError):
            trigger_metrics(method, path, raise_exc=True)

        after = REGISTRY.get_sample_value('http_exceptions_total', [method, path])
>       assert after - before == 1
E       TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

tests/unit-tests/services/common/test_metrics.py:42: TypeError
---------------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------------
printing stuff
raising an exception..
_____________________________________________________ TestREDMetricContextManager.test_request_latency_count ______________________________________________________

self = <common.test_metrics.TestREDMetricContextManager object at 0x7fb1d6abbbe0>

    def test_request_latency_count(self):
        method, path = 'TEST', 'PATH'

        before = REGISTRY.get_sample_value('http_requests_latency_seconds_count', [method, path]) or 0

        trigger_metrics(method, path, wait=True)

        after = REGISTRY.get_sample_value('http_requests_latency_seconds_count', [method, path])

>       assert after - before == 1
E       TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

tests/unit-tests/services/common/test_metrics.py:53: TypeError
---------------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------------
printing stuff
waiting a few seconds..
Not raising an exception
Returning.
______________________________________________________ TestREDMetricContextManager.test_request_latency_sum _______________________________________________________

self = <common.test_metrics.TestREDMetricContextManager object at 0x7fb1d6a647b8>

    def test_request_latency_sum(self):
        method, path = 'TEST', 'PATH'

        before = REGISTRY.get_sample_value('http_requests_latency_seconds_sum', [method, path]) or 0

        trigger_metrics(method, path, wait=True)

        after = REGISTRY.get_sample_value('http_requests_latency_seconds_sum', [method, path])

>       diff = after - before
E       TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

tests/unit-tests/services/common/test_metrics.py:64: TypeError
---------------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------------
printing stuff
waiting a few seconds..
Not raising an exception
Returning.
==================================================================== 4 failed in 4.12 seconds =====================================================================

Я рассчитывал, что первый раз, когда я позвоню get_sample_value, ожидается, что он будет None, так какМетрика еще не была вызвана, и ts может еще не существовать.Теперь, однако, я не так уверен.

1 Ответ

0 голосов
/ 19 июня 2019

Классика: REGISTRY.get_sample_value() ожидает, что метки будут переданы как dict, а не list. Так называем это так:

...
REGISTRY.get_sample_value('http_requests_total', {'method': method, 'path': path}) 
...

.. устраняет проблему и тесты проходят.

...