[Python] Migrate string list metric to UniFFI

This commit is contained in:
Jan-Erik Rediger 2022-02-14 11:52:13 +01:00 коммит произвёл Jan-Erik Rediger
Родитель dbb8626c57
Коммит 13548115e6
2 изменённых файлов: 52 добавлений и 206 удалений

Просмотреть файл

@ -1,161 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import json
from typing import Iterable, List, Optional
from .. import _ffi
from .._dispatcher import Dispatcher
from ..testing import ErrorType
from .lifetime import Lifetime
class StringListMetricType:
"""
This implements the developer facing API for recording string list metrics.
Instances of this class type are automatically generated by
`glean.load_metrics`, allowing developers to record values that were
previously registered in the metrics.yaml file.
The stringlist API only exposes the `StringListMetricType.set` and
`StringListMetricType.add` methods, which takes case of validating the
input data and making sure that limits are enforced.
"""
def __init__(
self,
disabled: bool,
category: str,
lifetime: Lifetime,
name: str,
send_in_pings: List[str],
):
self._disabled = disabled
self._send_in_pings = send_in_pings
self._handle = _ffi.lib.glean_new_string_list_metric(
_ffi.ffi_encode_string(category),
_ffi.ffi_encode_string(name),
_ffi.ffi_encode_vec_string(send_in_pings),
len(send_in_pings),
lifetime.value,
disabled,
)
def __del__(self):
if getattr(self, "_handle", 0) != 0:
_ffi.lib.glean_destroy_string_list_metric(self._handle)
def add(self, value: str) -> None:
"""
Appends a string value to one or more string list metric stores. If the
string exceeds the maximum string length or if the list exceeds the
maximum length it will be truncated.
Args:
value (str): The is the user defined string value.
"""
if self._disabled:
return
@Dispatcher.launch
def set():
_ffi.lib.glean_string_list_add(self._handle, _ffi.ffi_encode_string(value))
def set(self, value: Iterable[str]) -> None:
"""
Sets a string list to one or more metric stores. If any string exceeds
the maximum string length or if the list exceeds the maximum length it
will be truncated.
Args:
value (iterator over str): This is a user-defined string list.
"""
if self._disabled:
return
@Dispatcher.launch
def set():
values = list(value)
_ffi.lib.glean_string_list_set(
self._handle, _ffi.ffi_encode_vec_string(values), len(values)
)
def test_has_value(self, ping_name: Optional[str] = None) -> bool:
"""
Tests whether a value is stored for the metric for testing purposes
only.
Args:
ping_name (str): (default: first value in send_in_pings) The name
of the ping to retrieve the metric for.
Returns:
has_value (bool): True if the metric value exists.
"""
if ping_name is None:
ping_name = self._send_in_pings[0]
return bool(
_ffi.lib.glean_string_list_test_has_value(
self._handle, _ffi.ffi_encode_string(ping_name)
)
)
def test_get_value(self, ping_name: Optional[str] = None) -> List[str]:
"""
Returns the stored value for testing purposes only.
Args:
ping_name (str): (default: first value in send_in_pings) The name
of the ping to retrieve the metric for.
Returns:
value (bool): value of the stored metric.
"""
if ping_name is None:
ping_name = self._send_in_pings[0]
if not self.test_has_value(ping_name):
raise ValueError("metric has no value")
return json.loads(
_ffi.ffi_decode_string(
_ffi.lib.glean_string_list_test_get_value_as_json_string(
self._handle, _ffi.ffi_encode_string(ping_name)
)
)
)
def test_get_num_recorded_errors(
self, error_type: ErrorType, ping_name: Optional[str] = None
) -> int:
"""
Returns the number of errors recorded for the given metric.
Args:
error_type (ErrorType): The type of error recorded.
ping_name (str): (default: first value in send_in_pings) The name
of the ping to retrieve the metric for.
Returns:
num_errors (int): The number of errors recorded for the metric for
the given error type.
"""
if ping_name is None:
ping_name = self._send_in_pings[0]
return _ffi.lib.glean_string_list_test_get_num_recorded_errors(
self._handle,
error_type.value,
_ffi.ffi_encode_string(ping_name),
)
__all__ = ["StringListMetricType"]

Просмотреть файл

@ -2,99 +2,105 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import pytest
from glean import metrics
from glean.metrics import Lifetime
from glean.metrics import Lifetime, CommonMetricData
from glean import testing
def test_the_api_saves_to_its_storage_engine_by_first_adding_then_setting():
metric = metrics.StringListMetricType(
CommonMetricData(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="string_list_metric",
send_in_pings=["store1"],
dynamic_label=None,
)
)
metric.add("value1")
metric.add("value2")
metric.add("value3")
assert metric.test_has_value()
snapshot = metric.test_get_value()
assert ["value1", "value2", "value3"] == snapshot
metric.set(["other1", "other2", "other3"])
assert metric.test_has_value()
snapshot2 = metric.test_get_value()
assert ["other1", "other2", "other3"] == snapshot2
def test_the_api_saves_to_its_storage_engine_by_first_setting_then_adding():
metric = metrics.StringListMetricType(
CommonMetricData(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="string_list_metric",
send_in_pings=["store1"],
dynamic_label=None,
)
)
metric.set(["value1", "value2", "value3"])
assert metric.test_has_value()
snapshot = metric.test_get_value()
assert ["value1", "value2", "value3"] == snapshot
metric.add("added1")
assert metric.test_has_value()
snapshot = metric.test_get_value()
assert ["value1", "value2", "value3", "added1"] == snapshot
def test_disabled_lists_must_not_record_data():
metric = metrics.StringListMetricType(
CommonMetricData(
disabled=True,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="string_list_metric",
send_in_pings=["store1"],
dynamic_label=None,
)
)
metric.set(["value1", "value2", "value3"])
assert not metric.test_has_value()
assert not metric.test_get_value()
metric.add("value4")
assert not metric.test_has_value()
assert not metric.test_get_value()
def test_test_get_value_throws():
metric = metrics.StringListMetricType(
CommonMetricData(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="string_list_metric",
send_in_pings=["store1"],
dynamic_label=None,
)
)
with pytest.raises(ValueError):
metric.test_get_value()
assert not metric.test_get_value()
def test_api_saves_to_secondary_pings():
metric = metrics.StringListMetricType(
CommonMetricData(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="string_list_metric",
send_in_pings=["store1", "store2"],
dynamic_label=None,
)
)
metric.add("value1")
@ -102,23 +108,24 @@ def test_api_saves_to_secondary_pings():
metric.add("value3")
for store in ["store1", "store2"]:
assert metric.test_has_value(store)
assert ["value1", "value2", "value3"] == metric.test_get_value(store)
metric.set(["other1", "other2", "other3"])
for store in ["store1", "store2"]:
assert metric.test_has_value(store)
assert ["other1", "other2", "other3"] == metric.test_get_value(store)
def test_long_string_lists_are_truncated():
metric = metrics.StringListMetricType(
CommonMetricData(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="string_list_metric",
send_in_pings=["store1"],
dynamic_label=None,
)
)
for i in range(21):