userver: pytest_userver.metrics.MetricsSnapshot Class Reference
Loading...
Searching...
No Matches
pytest_userver.metrics.MetricsSnapshot Class Reference

Detailed Description

Snapshot of captured metrics that mimics the dict interface.

Metrics have the 'dict[str(path), Set[Metric]]' format.

Example with await monitor_client.metrics(path_prefix, labels):

async def test_engine_logger_metrics(service_client, monitor_client: pytest_userver.client.ClientMonitor):
metrics_dict: pytest_userver.metrics.MetricsSnapshot = await monitor_client.metrics(
prefix='logger.',
labels={'logger': 'default'},
)
assert metrics_dict
assert 'logger.total' in metrics_dict
assert metrics_dict.value_at('logger.total') > 0
assert (
metrics_dict.value_at(
'logger.dropped',
labels={
'logger': 'default',
'version': '2',
},
)
== 0
)

There are 3 ways to construct a MetricsSnapshot:

  1. The constructor itself, taking a ready dict[str(path), Set[Metric]]. Useful when dealing with just a few simple metrics, or when generating metrics programmatically, or when combining or transforming snapshots. This format is also well-suited for individual metrics with a large number of labels.
  2. from_dict / from_json, taking the flat json userver metrics format (a list of {"labels": ..., "value": ...} per path). This is an alternative to the constructor for loading from a JSON file. Note that from_layered_dict is often more terse and more readable.
  3. from_layered_dict, taking a layered dict format that avoids repeating labels for every metric. Recommended in tests that have many metrics sharing a label structure. Can be written out in code or loaded from a JSON file using load_json fixture.

Definition at line 135 of file metrics.py.

Public Member Functions

 __init__ (self, Mapping[str, Set[Metric]] values, *, str common_prefix='', Mapping[str, str]|None common_labels=None)
Set[Metric__getitem__ (self, str path)
 Returns a list of metrics by specified path.
int __len__ (self)
 Returns count of metrics paths.
 __iter__ (self)
 Returns a (path, list) iterable over the metrics.
bool __contains__ (self, str path)
 Returns True if metric with specified path is in the snapshot, False otherwise.
bool __eq__ (self, object other)
 Compares the snapshot with a dict of metrics or with another snapshot.
str __repr__ (self)
str __str__ (self)
 get (self, str path, default=None)
 Returns an list of metrics by path or default if there's no such path.
 items (self)
 Returns a (path, list) iterable over the metrics.
 keys (self)
 Returns an iterable over paths of metrics.
 values (self)
 Returns an iterable over lists of metrics.
MetricsSnapshot sliced (self, str|None prefix, dict[str, str]|None labels=None)
 Returns a new MetricsSnapshot restricted to the metrics whose path starts with prefix as a whole '.
MetricsSnapshot unsliced (self)
 Returns a new MetricsSnapshot with the prefix accumulated from the preceding (possibly chained) sliced() call(s) prepended back to every surviving metric's path.
MetricValue value_at (self, str path, dict[str, str]|None labels=None)
MetricValue|T value_at (self, str path, dict[str, str]|None labels, *, T default)
MetricValue|Any value_at (self, str path, dict[str, str]|None labels=None, *, Any default=_MISSING)
 Returns a single metric value at specified path.
list[Metricmetrics_at (self, str path, dict[str, str]|None require_labels=None)
 Metrics path must exactly equal the given path.
bool has_metrics_at (self, str path, dict[str, str]|None require_labels=None)
None assert_equals (self, Mapping[str, Set[Metric]] other, *, bool ignore_zeros=False)
MetricsSnapshot without_zero_rates (self)
 Returns a new snapshot with "empty" RATE and HIST_RATE metrics removed: a RATE metric is removed if its value is zero, a HIST_RATE metric is removed if its histogram has zero count in every bucket and in inf.
str pretty_print (self)
 Multiline linear print: path: (label=value),(label=value) TYPE VALUE path: (label=value),(label=value) TYPE VALUE Usage:
str to_json (self)
 Serialize to a JSON string.

Static Public Member Functions

MetricsSnapshot from_dict (Mapping[str, Any] data)
 Construct MetricsSnapshot from a JSON dict in the json userver metrics format.
MetricsSnapshot from_json (str json_str)
 Construct MetricsSnapshot from a JSON string in the json userver metrics format.
MetricsSnapshot from_layered_dict (Mapping[str, Any] data, *, str common_prefix='', Mapping[str, str]|None common_labels=None)
 Construct MetricsSnapshot from a layered dict format that avoids repeating a label's name for every metric that only differs by that label's value.

Protected Attributes

 _values = _apply_common_prefix_labels(values, common_prefix, common_labels)
str|None _sliced_prefix = None
dict _sliced_labels = {}

Constructor & Destructor Documentation

◆ __init__()

pytest_userver.metrics.MetricsSnapshot.__init__ ( self,
Mapping[str, Set[Metric]] values,
* ,
str common_prefix = '',
Mapping[str, str] | None common_labels = None )
Parameters
valuesMetrics keyed by path, as a dict[str(path), Set[Metric]] (the same format MetricsSnapshot itself exposes via items()).
common_prefixIf provided, prepended to each path (separated by a dot).
common_labelsIf provided, these labels are added to every metric, merged with (and overridden by) that metric's own labels.

Definition at line 160 of file metrics.py.

Member Function Documentation

◆ __contains__()

bool pytest_userver.metrics.MetricsSnapshot.__contains__ ( self,
str path )

Returns True if metric with specified path is in the snapshot, False otherwise.

Definition at line 190 of file metrics.py.

◆ __eq__()

bool pytest_userver.metrics.MetricsSnapshot.__eq__ ( self,
object other )

Compares the snapshot with a dict of metrics or with another snapshot.

A path mapped to an empty set of metrics is treated the same as an absent path.

Definition at line 196 of file metrics.py.

◆ __getitem__()

Set[Metric] pytest_userver.metrics.MetricsSnapshot.__getitem__ ( self,
str path )

Returns a list of metrics by specified path.

Definition at line 178 of file metrics.py.

◆ __iter__()

pytest_userver.metrics.MetricsSnapshot.__iter__ ( self)

Returns a (path, list) iterable over the metrics.

Definition at line 186 of file metrics.py.

◆ __len__()

int pytest_userver.metrics.MetricsSnapshot.__len__ ( self)

Returns count of metrics paths.

Definition at line 182 of file metrics.py.

◆ __repr__()

str pytest_userver.metrics.MetricsSnapshot.__repr__ ( self)

Definition at line 210 of file metrics.py.

◆ __str__()

str pytest_userver.metrics.MetricsSnapshot.__str__ ( self)

Definition at line 213 of file metrics.py.

◆ assert_equals()

None pytest_userver.metrics.MetricsSnapshot.assert_equals ( self,
Mapping[str, Set[Metric]] other,
* ,
bool ignore_zeros = False )
Deprecated
Use == operator instead, which produces a nice diff automatically via pytest_assertrepr_compare. To ignore zero-rate metrics, use without_zero_rates() on the snapshots before comparing.

Definition at line 412 of file metrics.py.

◆ from_dict()

MetricsSnapshot pytest_userver.metrics.MetricsSnapshot.from_dict ( Mapping[str, Any] data)
static

Construct MetricsSnapshot from a JSON dict in the json userver metrics format.

Definition at line 469 of file metrics.py.

◆ from_json()

MetricsSnapshot pytest_userver.metrics.MetricsSnapshot.from_json ( str json_str)
static

Construct MetricsSnapshot from a JSON string in the json userver metrics format.

Definition at line 487 of file metrics.py.

◆ from_layered_dict()

MetricsSnapshot pytest_userver.metrics.MetricsSnapshot.from_layered_dict ( Mapping[str, Any] data,
* ,
str common_prefix = '',
Mapping[str, str] | None common_labels = None )
static

Construct MetricsSnapshot from a layered dict format that avoids repeating a label's name for every metric that only differs by that label's value.

Top-level keys of data are metric paths, used as-is. Within a path's value, each dict key names a label as 'name = value' (with exactly one space on each side of =: everything before is the label name, everything after is its value); the corresponding child value is interpreted the same way recursively, so several labels can be layered one inside another. A dict with bounds and buckets keys is a leaf value instead of being recursed into, parsed as a Histogram; any other non-dict value is a plain leaf metric value.

If common_prefix is provided, it is prepended to each path (separated by a dot) so that paths in data can omit a shared prefix.

If common_labels is provided, these labels are added to every metric in the snapshot, merged with any labels from the layered dict structure.

Example: {'a': {'x = foo': 1, 'x = bar': 2}} is equivalent to MetricsSnapshot({'a': {Metric({'x': 'foo'}, 1), Metric({'x': 'bar'}, 2)}}).

Definition at line 494 of file metrics.py.

◆ get()

pytest_userver.metrics.MetricsSnapshot.get ( self,
str path,
default = None )

Returns an list of metrics by path or default if there's no such path.

Definition at line 216 of file metrics.py.

◆ has_metrics_at()

bool pytest_userver.metrics.MetricsSnapshot.has_metrics_at ( self,
str path,
dict[str, str] | None require_labels = None )

Definition at line 403 of file metrics.py.

◆ items()

pytest_userver.metrics.MetricsSnapshot.items ( self)

Returns a (path, list) iterable over the metrics.

Definition at line 222 of file metrics.py.

◆ keys()

pytest_userver.metrics.MetricsSnapshot.keys ( self)

Returns an iterable over paths of metrics.

Definition at line 226 of file metrics.py.

◆ metrics_at()

list[Metric] pytest_userver.metrics.MetricsSnapshot.metrics_at ( self,
str path,
dict[str, str] | None require_labels = None )

Metrics path must exactly equal the given path.

A required subset of labels is specified by require_labels Example: require_labels={'a':'b', 'c':'d'} { 'a':'b', 'c':'d'} - exact match { 'a':'b', 'c':'d', 'e': 'f', 'h':'k'} - match { 'a':'x', 'c':'d'} - no match, incorrect value for label 'a' { 'a' : 'b'} - required label not found

async def test_engine_logger_metrics(service_client, monitor_client: pytest_userver.client.ClientMonitor):
metrics_dict: pytest_userver.metrics.MetricsSnapshot = await monitor_client.metrics(
prefix='logger.',
labels={'logger': 'default'},
)
assert metrics_dict
assert 'logger.total' in metrics_dict
assert metrics_dict.value_at('logger.total') > 0
assert (
metrics_dict.value_at(
'logger.dropped',
labels={
'logger': 'default',
'version': '2',
},
)
== 0
)

Definition at line 376 of file metrics.py.

◆ pretty_print()

str pytest_userver.metrics.MetricsSnapshot.pretty_print ( self)

Multiline linear print: path: (label=value),(label=value) TYPE VALUE path: (label=value),(label=value) TYPE VALUE Usage:

assert 'some.thing.sensor' in metric, metric.pretty_print()

Definition at line 442 of file metrics.py.

◆ sliced()

MetricsSnapshot pytest_userver.metrics.MetricsSnapshot.sliced ( self,
str | None prefix,
dict[str, str] | None labels = None )

Returns a new MetricsSnapshot restricted to the metrics whose path starts with prefix as a whole '.

'-separated segment, and, if labels is given, whose labels are a superset of labels (same subset-match semantics as require_labels in metrics_at).

prefix may be:

  • A non-empty string: matches paths equal to prefix, or starting with prefix followed by a whole '.'-separated segment boundary (prefix='a.b' matches paths 'a.b' and 'a.b.c', but not 'a.bc'). The matched prefix (and the following '.', if any) is stripped from the start of every surviving metric's path, so e.g. slicing 'a.b.c' by prefix='a.b' makes it accessible as 'c', and slicing 'a.b' by prefix='a.b' makes it accessible as ''.
  • '': matches paths equal to '', or starting with a literal leading '.'; the leading '.' is stripped. Only relevant for the rare case of a metric path that itself starts with a dot.
  • None: matches every path unconditionally. Use this to filter by labels only.

Calling sliced() several times in a row composes: each prefix is matched against the already-stripped paths of the previous sliced() call, and labels requirements accumulate.

Slicing only ever affects filtering (which metrics are visible, and under which path): it never touches the Metric objects themselves. metrics_at(), value_at() and iteration over a sliced snapshot all keep returning the exact same, untouched Metric objects (same labels, value, identity), just possibly under a shorter path and/or a smaller surrounding set.

Intended use: carve out a small, closed slice of a snapshot (e.g. one metric path with a handful of varying labels) to compare it with == against a compact expected snapshot, or to look up several label combinations with value_at/metrics_at without repeating the common prefix and labels in every call.

Exceptions
AssertionErrorif stripping prefix from a metric path would leave an empty remainder, e.g. path 'a.b.' sliced by prefix='a.b', which would be indistinguishable from path 'a.b'.
# Suppose 'hello-handler' exposes a per-language greetings counter and a
# couple of top-level request counters, e.g. as reported by
# `await monitor_client.metrics(prefix='hello-handler')`:
'hello-handler.requests-total': 8,
'hello-handler.errors-total': 0,
'hello-handler.greetings-by-lang-count': {
'lang = en': 3,
'lang = ru': 5,
},
})
# First `sliced()` narrows the snapshot down to the handler's own metrics,
# dropping any unrelated components and letting us use short paths below.
handler = metrics.sliced('hello-handler')
assert handler.value_at('requests-total') == 8
assert handler.value_at('errors-total') == 0
# Second `sliced()` narrows further, down to a single metric path with
# a varying 'lang' label; the empty string ('') stands for "no path left".
greetings_by_lang = handler.sliced('greetings-by-lang-count')
assert greetings_by_lang.value_at('', labels={'lang': 'en'}) == 3
assert greetings_by_lang.value_at('', labels={'lang': 'ru'}) == 5

Definition at line 234 of file metrics.py.

◆ to_json()

str pytest_userver.metrics.MetricsSnapshot.to_json ( self)

Serialize to a JSON string.

Definition at line 531 of file metrics.py.

◆ unsliced()

MetricsSnapshot pytest_userver.metrics.MetricsSnapshot.unsliced ( self)

Returns a new MetricsSnapshot with the prefix accumulated from the preceding (possibly chained) sliced() call(s) prepended back to every surviving metric's path.

Does not mutate self.

Metrics that were filtered out by sliced() (because their path did not match prefix, or their labels did not match labels) do NOT come back: unsliced() only restores the path of what remains in the snapshot, it does not undo the filtering itself.

If this snapshot was never sliced() (i.e. self is the original snapshot, or the result of operations other than sliced()), returns an equivalent snapshot unchanged.

Definition at line 300 of file metrics.py.

◆ value_at() [1/3]

MetricValue | T pytest_userver.metrics.MetricsSnapshot.value_at ( self,
str path,
dict[str, str] | None labels,
* ,
T default )

Definition at line 326 of file metrics.py.

◆ value_at() [2/3]

MetricValue pytest_userver.metrics.MetricsSnapshot.value_at ( self,
str path,
dict[str, str] | None labels = None )

Definition at line 319 of file metrics.py.

◆ value_at() [3/3]

MetricValue | Any pytest_userver.metrics.MetricsSnapshot.value_at ( self,
str path,
dict[str, str] | None labels = None,
* ,
Any default = _MISSING )

Returns a single metric value at specified path.

If a dict of labels is provided, does en exact match of labels (i.e. {} stands for no labels; {'a': 'b', 'c': 'd'} matches only {'a': 'b', 'c': 'd'} or {'c': 'd', 'a': 'b'} but neither match {'a': 'b'} nor {'a': 'b', 'c': 'd', 'e': 'f'}).

If default is provided, it is returned instead of asserting when the metric is not found.

Exceptions
AssertionErrorif not one metric by path and no default is given
async def test_engine_logger_metrics(service_client, monitor_client: pytest_userver.client.ClientMonitor):
metrics_dict: pytest_userver.metrics.MetricsSnapshot = await monitor_client.metrics(
prefix='logger.',
labels={'logger': 'default'},
)
assert metrics_dict
assert 'logger.total' in metrics_dict
assert metrics_dict.value_at('logger.total') > 0
assert (
metrics_dict.value_at(
'logger.dropped',
labels={
'logger': 'default',
'version': '2',
},
)
== 0
)

Definition at line 334 of file metrics.py.

◆ values()

pytest_userver.metrics.MetricsSnapshot.values ( self)

Returns an iterable over lists of metrics.

Definition at line 230 of file metrics.py.

◆ without_zero_rates()

MetricsSnapshot pytest_userver.metrics.MetricsSnapshot.without_zero_rates ( self)

Returns a new snapshot with "empty" RATE and HIST_RATE metrics removed: a RATE metric is removed if its value is zero, a HIST_RATE metric is removed if its histogram has zero count in every bucket and in inf.

GAUGE (and untyped) metrics are kept as-is, because a zero GAUGE value can be meaningful.

Definition at line 427 of file metrics.py.

Member Data Documentation

◆ _sliced_labels

dict pytest_userver.metrics.MetricsSnapshot._sliced_labels = {}
protected

Definition at line 176 of file metrics.py.

◆ _sliced_prefix

str | None pytest_userver.metrics.MetricsSnapshot._sliced_prefix = None
protected

Definition at line 175 of file metrics.py.

◆ _values

pytest_userver.metrics.MetricsSnapshot._values = _apply_common_prefix_labels(values, common_prefix, common_labels)
protected

Definition at line 174 of file metrics.py.


The documentation for this class was generated from the following file:
  • /data/code/userver/testsuite/pytest_plugins/pytest_userver/metrics.py