Skip to content

Commit

Permalink
fix: cast dimension value to str to avoid issue where EMF silently fa…
Browse files Browse the repository at this point in the history
…ils (#52)

* fix: cast dimension value to str to avoid issue where EMF silently fails to collect the metrics

* fix: correct type hint in fixture

* fix: remove surplus assertions and logic from new test

* chore: fix formatting
  • Loading branch information
cakepietoast committed Jun 2, 2020
1 parent 3f51e20 commit c5a9b3f
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 2 deletions.
9 changes: 8 additions & 1 deletion aws_lambda_powertools/metrics/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,14 @@ def add_dimension(self, name: str, value: str):
Dimension value
"""
logger.debug(f"Adding dimension: {name}:{value}")
self.dimension_set[name] = value

# Cast value to str according to EMF spec
# Majority of values are expected to be string already, so
# checking before casting improves performance in most cases
if isinstance(value, str):
self.dimension_set[name] = value
else:
self.dimension_set[name] = str(value)

def __extract_metric_unit_value(self, unit: Union[str, MetricUnit]) -> str:
"""Return metric value from metric unit whether that's str or MetricUnit enum
Expand Down
34 changes: 33 additions & 1 deletion tests/functional/test_metrics.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import json
from typing import Dict, List
from typing import Any, Dict, List

import pytest

Expand Down Expand Up @@ -48,6 +48,14 @@ def dimensions() -> List[Dict[str, str]]:
]


@pytest.fixture
def non_str_dimensions() -> List[Dict[str, Any]]:
return [
{"name": "test_dimension", "value": True},
{"name": "test_dimension_2", "value": 3},
]


@pytest.fixture
def namespace() -> Dict[str, str]:
return {"name": "test_namespace"}
Expand Down Expand Up @@ -380,3 +388,27 @@ def lambda_handler(evt, context):

# THEN metric set should be empty after function has been run
assert my_metrics.metric_set == {}


def test_log_metrics_non_string_dimension_values(capsys, metrics, non_str_dimensions, namespace):
# GIVEN Metrics is initialized and dimensions with non-string values are added
my_metrics = Metrics()
my_metrics.add_namespace(**namespace)
for metric in metrics:
my_metrics.add_metric(**metric)
for dimension in non_str_dimensions:
my_metrics.add_dimension(**dimension)

# WHEN we utilize log_metrics to serialize
# and flush all metrics at the end of a function execution
@my_metrics.log_metrics
def lambda_handler(evt, ctx):
return True

lambda_handler({}, {})
output = json.loads(capsys.readouterr().out.strip())

# THEN we should have no exceptions
# and dimension values hould be serialized as strings
for dimension in non_str_dimensions:
assert isinstance(output[dimension["name"]], str)

0 comments on commit c5a9b3f

Please sign in to comment.