[Python] Migrate labeled metrics to UniFFI

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

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

@ -3,14 +3,13 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from typing import Any, Callable, List, Optional, Set, Type
from typing import Any, Optional, Set, Type
from .. import _ffi
from .boolean import BooleanMetricType
from .counter import CounterMetricType
from .lifetime import Lifetime
from .string import StringMetricType
from .._uniffi import CommonMetricData
from .._uniffi import LabeledBoolean
from .._uniffi import LabeledCounter
from .._uniffi import LabeledString
from ..testing import ErrorType
@ -30,50 +29,18 @@ class LabeledMetricBase:
metric storage and rearrange them correctly in the ping.
"""
# The following 4 class attributes must be overridden by classes
# The following class attribute must be overridden by classes
# inheriting from LabeledMetricBase:
# The class of the concrete metric type
_submetric_type: Type
# The FFI function to instantiate the labeled metric type
_metric_type_instantiator: Callable
# The FFI function to get a concrete metric type from the labeled metric type
_submetric_type_instantiator: Callable
# The FFI function for test_get_num_recorded_errors
_test_get_num_recorded_errors_ffi: Callable
_ctor: Type
def __init__(
self,
disabled: bool,
category: str,
lifetime: Lifetime,
name: str,
send_in_pings: List[str],
common_metric_data: CommonMetricData,
labels: Optional[Set[str]] = None,
):
self._disabled = disabled
self._send_in_pings = send_in_pings
if labels is not None:
label_list = _ffi.ffi_encode_vec_string(list(labels))
label_len = len(labels)
else:
label_list = _ffi.ffi.NULL
label_len = 0
self._handle = self._metric_type_instantiator(
_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,
label_list,
label_len,
)
self._inner = self._ctor(common_metric_data, labels)
def __getitem__(self, item: str) -> Any:
"""
@ -91,14 +58,7 @@ class LabeledMetricBase:
label is used, the metric will be recorded in the special `__other__`
label.
"""
handle = self._submetric_type_instantiator(
self._handle, _ffi.ffi_encode_string(item)
)
metric = self._submetric_type.__new__(self._submetric_type) # type: ignore
metric._handle = handle
metric._disabled = self._disabled
metric._send_in_pings = self._send_in_pings
return metric
return self._inner.get(item)
def test_get_num_recorded_errors(
self, error_type: ErrorType, ping_name: Optional[str] = None
@ -115,41 +75,19 @@ class LabeledMetricBase:
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 self._test_get_num_recorded_errors_ffi(
self._handle,
error_type.value,
_ffi.ffi_encode_string(ping_name),
)
return self._inner.test_get_num_recorded_errors(error_type, ping_name)
class LabeledBooleanMetricType(LabeledMetricBase):
_submetric_type = BooleanMetricType
_metric_type_instantiator = _ffi.lib.glean_new_labeled_boolean_metric
_submetric_type_instantiator = _ffi.lib.glean_labeled_boolean_metric_get
_test_get_num_recorded_errors_ffi = (
_ffi.lib.glean_labeled_boolean_test_get_num_recorded_errors
)
_ctor = LabeledBoolean
class LabeledCounterMetricType(LabeledMetricBase):
_submetric_type = CounterMetricType
_metric_type_instantiator = _ffi.lib.glean_new_labeled_counter_metric
_submetric_type_instantiator = _ffi.lib.glean_labeled_counter_metric_get
_test_get_num_recorded_errors_ffi = (
_ffi.lib.glean_labeled_counter_test_get_num_recorded_errors
)
_ctor = LabeledCounter
class LabeledStringMetricType(LabeledMetricBase):
_submetric_type = StringMetricType
_metric_type_instantiator = _ffi.lib.glean_new_labeled_string_metric
_submetric_type_instantiator = _ffi.lib.glean_labeled_string_metric_get
_test_get_num_recorded_errors_ffi = (
_ffi.lib.glean_labeled_string_test_get_num_recorded_errors
)
_ctor = LabeledString
__all__ = [

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

@ -2,145 +2,83 @@
# 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 io
import json
import sys
from glean_parser import validate_ping
from glean import Glean
from glean import __version__ as glean_version
from glean import _builtins
from glean import metrics
from glean._dispatcher import Dispatcher
from glean.metrics import Lifetime
from glean.metrics import Lifetime, CommonMetricData
from glean.testing import ErrorType
def test_labeled_counter_type(ping_schema_url):
labeled_counter_metric = metrics.LabeledCounterMetricType(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_counter_metric",
send_in_pings=["metrics"],
CommonMetricData(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_counter_metric",
send_in_pings=["metrics"],
dynamic_label=None,
)
)
labeled_counter_metric["label1"].add(1)
labeled_counter_metric["label2"].add(2)
assert labeled_counter_metric["label1"].test_has_value()
assert 1 == labeled_counter_metric["label1"].test_get_value()
assert labeled_counter_metric["label2"].test_has_value()
assert 2 == labeled_counter_metric["label2"].test_get_value()
json_content = Glean.test_collect(_builtins.pings.metrics)
assert 0 == validate_ping.validate_ping(
io.StringIO(json_content), sys.stdout, schema_url=ping_schema_url
)
tree = json.loads(json_content)
assert (
1
== tree["metrics"]["labeled_counter"]["telemetry.labeled_counter_metric"][
"label1"
]
)
assert (
2
== tree["metrics"]["labeled_counter"]["telemetry.labeled_counter_metric"][
"label2"
]
)
def test_labeled_boolean_type(ping_schema_url):
labeled_boolean_metric = metrics.LabeledBooleanMetricType(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_boolean_metric",
send_in_pings=["metrics"],
CommonMetricData(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_boolean_metric",
send_in_pings=["metrics"],
dynamic_label=None,
)
)
labeled_boolean_metric["label1"].set(True)
labeled_boolean_metric["label2"].set(False)
assert labeled_boolean_metric["label1"].test_has_value()
assert labeled_boolean_metric["label1"].test_get_value()
assert labeled_boolean_metric["label2"].test_has_value()
assert not labeled_boolean_metric["label2"].test_get_value()
json_content = Glean.test_collect(_builtins.pings.metrics)
assert 0 == validate_ping.validate_ping(
io.StringIO(json_content), sys.stdout, schema_url=ping_schema_url
)
tree = json.loads(json_content)
assert tree["metrics"]["labeled_boolean"]["telemetry.labeled_boolean_metric"][
"label1"
]
assert not tree["metrics"]["labeled_boolean"]["telemetry.labeled_boolean_metric"][
"label2"
]
def test_labeled_string_type(ping_schema_url):
labeled_string_metric = metrics.LabeledStringMetricType(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_string_metric",
send_in_pings=["metrics"],
CommonMetricData(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_string_metric",
send_in_pings=["metrics"],
dynamic_label=None,
)
)
labeled_string_metric["label1"].set("foo")
labeled_string_metric["label2"].set("bar")
assert labeled_string_metric["label1"].test_has_value()
assert "foo" == labeled_string_metric["label1"].test_get_value()
assert labeled_string_metric["label2"].test_has_value()
assert "bar" == labeled_string_metric["label2"].test_get_value()
json_content = Glean.test_collect(_builtins.pings.metrics)
assert 0 == validate_ping.validate_ping(
io.StringIO(json_content), sys.stdout, schema_url=ping_schema_url
)
tree = json.loads(json_content)
assert (
"foo"
== tree["metrics"]["labeled_string"]["telemetry.labeled_string_metric"][
"label1"
]
)
assert (
"bar"
== tree["metrics"]["labeled_string"]["telemetry.labeled_string_metric"][
"label2"
]
)
def test_other_label_with_predefined_labels(ping_schema_url):
labeled_counter_metric = metrics.LabeledCounterMetricType(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_counter_metric",
send_in_pings=["metrics"],
CommonMetricData(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_counter_metric",
send_in_pings=["metrics"],
dynamic_label=None,
),
labels=["foo", "bar", "baz"],
)
@ -153,40 +91,20 @@ def test_other_label_with_predefined_labels(ping_schema_url):
assert 3 == labeled_counter_metric["foo"].test_get_value()
assert 1 == labeled_counter_metric["bar"].test_get_value()
assert not labeled_counter_metric["baz"].test_has_value()
assert not labeled_counter_metric["baz"].test_get_value()
assert 3 == labeled_counter_metric["not_there"].test_get_value()
json_content = Glean.test_collect(_builtins.pings.metrics)
assert 0 == validate_ping.validate_ping(
io.StringIO(json_content), sys.stdout, schema_url=ping_schema_url
)
tree = json.loads(json_content)
assert (
3
== tree["metrics"]["labeled_counter"]["telemetry.labeled_counter_metric"]["foo"]
)
assert (
1
== tree["metrics"]["labeled_counter"]["telemetry.labeled_counter_metric"]["bar"]
)
assert (
3
== tree["metrics"]["labeled_counter"]["telemetry.labeled_counter_metric"][
"__other__"
]
)
def test_other_label_without_predefined_labels(ping_schema_url):
labeled_counter_metric = metrics.LabeledCounterMetricType(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_counter_metric",
send_in_pings=["metrics"],
CommonMetricData(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_counter_metric",
send_in_pings=["metrics"],
dynamic_label=None,
)
)
for i in range(21):
@ -199,24 +117,20 @@ def test_other_label_without_predefined_labels(ping_schema_url):
assert 1 == labeled_counter_metric[f"label_{i}"].test_get_value()
assert 5 == labeled_counter_metric["__other__"].test_get_value()
json_content = Glean.test_collect(_builtins.pings.metrics)
assert 0 == validate_ping.validate_ping(
io.StringIO(json_content), sys.stdout, schema_url=ping_schema_url
)
def test_other_label_without_predefined_labels_before_glean_init():
labeled_counter_metric = metrics.LabeledCounterMetricType(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_counter_metric",
send_in_pings=["metrics"],
CommonMetricData(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_counter_metric",
send_in_pings=["metrics"],
dynamic_label=None,
)
)
Glean._reset()
Dispatcher.set_task_queueing(True)
for i in range(21):
labeled_counter_metric[f"label_{i}"].add(1)
@ -236,11 +150,14 @@ def test_other_label_without_predefined_labels_before_glean_init():
def test_invalid_labels_go_to_other():
labeled_counter_metric = metrics.LabeledCounterMetricType(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_counter_metric",
send_in_pings=["metrics"],
CommonMetricData(
disabled=False,
category="telemetry",
lifetime=Lifetime.APPLICATION,
name="labeled_counter_metric",
send_in_pings=["metrics"],
dynamic_label=None,
)
)
labeled_counter_metric["notSnakeCase"].add(1)