Skip to content

fix: cast dimension value to str to avoid issue where EMF silently fails #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)