From b7e329496bd787566c7955ad5037806283cbe7c7 Mon Sep 17 00:00:00 2001 From: Vladimir Prudnikov Date: Wed, 1 Feb 2023 01:45:34 +0000 Subject: [PATCH 1/2] feat(metrics): default dimensions in single_metric --- aws_lambda_powertools/metrics/base.py | 11 ++++++- docs/core/metrics.md | 14 ++++++++ .../src/single_metric_default_dimensions.py | 14 ++++++++ ...ingle_metric_default_dimensions_inherit.py | 17 ++++++++++ tests/functional/test_metrics.py | 32 +++++++++++++++++++ 5 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 examples/metrics/src/single_metric_default_dimensions.py create mode 100644 examples/metrics/src/single_metric_default_dimensions_inherit.py diff --git a/aws_lambda_powertools/metrics/base.py b/aws_lambda_powertools/metrics/base.py index b032d181811..c2949ab43da 100644 --- a/aws_lambda_powertools/metrics/base.py +++ b/aws_lambda_powertools/metrics/base.py @@ -463,7 +463,11 @@ def add_metric(self, name: str, unit: Union[MetricUnit, str], value: float) -> N @contextmanager def single_metric( - name: str, unit: MetricUnit, value: float, namespace: Optional[str] = None + name: str, + unit: MetricUnit, + value: float, + namespace: Optional[str] = None, + default_dimensions: Optional[Dict[str, str]] = None, ) -> Generator[SingleMetric, None, None]: """Context manager to simplify creation of a single metric @@ -516,6 +520,11 @@ def single_metric( try: metric: SingleMetric = SingleMetric(namespace=namespace) metric.add_metric(name=name, unit=unit, value=value) + + if default_dimensions: + for dim_name, dim_value in default_dimensions.items(): + metric.add_dimension(name=dim_name, value=dim_value) + yield metric metric_set = metric.serialize_metric_set() finally: diff --git a/docs/core/metrics.md b/docs/core/metrics.md index e02b247f117..a1f68405aa1 100644 --- a/docs/core/metrics.md +++ b/docs/core/metrics.md @@ -216,6 +216,20 @@ CloudWatch EMF uses the same dimensions across all your metrics. Use `single_met --8<-- "examples/metrics/src/single_metric_output.json" ``` +By default it will skip all previously defined dimensions including default dimensions. Use `default_dimensions` keyword argument if you want to reuse default dimensions or specify custom dimensions from a dictionary. + +=== "single_metric_default_dimensions_inherit.json" + + ```json hl_lines="9-10 13" + --8<-- "examples/metrics/src/single_metric_default_dimensions_inherit.py" + ``` + +=== "single_metric_default_dimensions.py" + + ```python hl_lines="10" + --8<-- "examples/metrics/src/single_metric_default_dimensions.py" + ``` + ### Flushing metrics manually If you prefer not to use `log_metrics` because you might want to encapsulate additional logic when doing so, you can manually flush and clear metrics as follows: diff --git a/examples/metrics/src/single_metric_default_dimensions.py b/examples/metrics/src/single_metric_default_dimensions.py new file mode 100644 index 00000000000..3ed6c5e9035 --- /dev/null +++ b/examples/metrics/src/single_metric_default_dimensions.py @@ -0,0 +1,14 @@ +import os + +from aws_lambda_powertools import single_metric +from aws_lambda_powertools.metrics import MetricUnit +from aws_lambda_powertools.utilities.typing import LambdaContext + +STAGE = os.getenv("STAGE", "dev") + + +def lambda_handler(event: dict, context: LambdaContext): + with single_metric( + name="RecordsCount", unit=MetricUnit.Count, value=10, default_dimensions={"environment": STAGE} + ) as metric: + metric.add_dimension(name="TableName", value="Users") diff --git a/examples/metrics/src/single_metric_default_dimensions_inherit.py b/examples/metrics/src/single_metric_default_dimensions_inherit.py new file mode 100644 index 00000000000..92a27d6e0d3 --- /dev/null +++ b/examples/metrics/src/single_metric_default_dimensions_inherit.py @@ -0,0 +1,17 @@ +import os + +from aws_lambda_powertools import single_metric +from aws_lambda_powertools.metrics import Metrics, MetricUnit +from aws_lambda_powertools.utilities.typing import LambdaContext + +STAGE = os.getenv("STAGE", "dev") + +metrics = Metrics() +metrics.set_default_dimensions(environment=STAGE) + + +def lambda_handler(event: dict, context: LambdaContext): + with single_metric( + name="RecordsCount", unit=MetricUnit.Count, value=10, default_dimensions=metrics.default_dimensions + ) as metric: + metric.add_dimension(name="TableName", value="Users") diff --git a/tests/functional/test_metrics.py b/tests/functional/test_metrics.py index c45c138ad59..d15b105057e 100644 --- a/tests/functional/test_metrics.py +++ b/tests/functional/test_metrics.py @@ -156,6 +156,38 @@ def test_single_metric_logs_one_metric_only(capsys, metric, dimension, namespace assert expected == output +def test_single_metric_default_dimensions(capsys, metric, dimension, namespace): + # GIVEN we provide default dimensions + # WHEN using single_metric context manager + default_dimensions = {dimension["name"]: dimension["value"]} + with single_metric(namespace=namespace, default_dimensions=default_dimensions, **metric) as my_metric: + my_metric.add_metric(name="second_metric", unit="Count", value=1) + + output = capture_metrics_output(capsys) + expected = serialize_single_metric(metric=metric, dimension=dimension, namespace=namespace) + + # THEN we should have default dimension added to the metric + remove_timestamp(metrics=[output, expected]) + assert expected == output + + +def test_single_metric_default_dimensions_inherit(capsys, metric, dimension, namespace): + # GIVEN we provide Metrics default dimensions + # WHEN using single_metric context manager + metrics = Metrics() + default_dimensions = {dimension["name"]: dimension["value"]} + metrics.set_default_dimensions(**default_dimensions) + with single_metric(namespace=namespace, default_dimensions=metrics.default_dimensions, **metric) as my_metric: + my_metric.add_metric(name="second_metric", unit="Count", value=1) + + output = capture_metrics_output(capsys) + expected = serialize_single_metric(metric=metric, dimension=dimension, namespace=namespace) + + # THEN we should have default dimension added to the metric + remove_timestamp(metrics=[output, expected]) + assert expected == output + + def test_log_metrics(capsys, metrics, dimensions, namespace): # GIVEN Metrics is initialized my_metrics = Metrics(namespace=namespace) From 34a120d186983db31897ea0c73811b4faa50f416 Mon Sep 17 00:00:00 2001 From: Ruben Fonseca Date: Wed, 1 Feb 2023 14:46:49 +0100 Subject: [PATCH 2/2] fix(docs): highlights --- docs/core/metrics.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/core/metrics.md b/docs/core/metrics.md index a1f68405aa1..ca42b632f84 100644 --- a/docs/core/metrics.md +++ b/docs/core/metrics.md @@ -220,13 +220,13 @@ By default it will skip all previously defined dimensions including default dime === "single_metric_default_dimensions_inherit.json" - ```json hl_lines="9-10 13" + ```json hl_lines="10 15" --8<-- "examples/metrics/src/single_metric_default_dimensions_inherit.py" ``` === "single_metric_default_dimensions.py" - ```python hl_lines="10" + ```python hl_lines="12" --8<-- "examples/metrics/src/single_metric_default_dimensions.py" ```