Skip to content

Commit 8ae86bd

Browse files
committed
Merge branch 'develop'
* develop: chore: plat wheels are not needed Fix Logger value coercion to main keys (#53) fix: cast dimension value to str to avoid issue where EMF silently fails (#52)
2 parents cd57c0f + 42b6081 commit 8ae86bd

File tree

9 files changed

+63
-45
lines changed

9 files changed

+63
-45
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
## [0.9.5] - 2020-06-02
10+
### Fixed
11+
- **Metrics**: Coerce non-string dimension values to string
12+
- **Logger**: Correct `cold_start`, `function_memory_size` values from string to bool and int respectively
13+
914
## [0.9.4] - 2020-05-29
1015
### Fixed
1116
- **Metrics**: Fix issue where metrics were not correctly flushed, and cleared on every invocation

Makefile

+1-6
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,7 @@ release-test:
7070
poetry config pypi-token.pypi ${PYPI_TEST_TOKEN}
7171
poetry publish --repository testpypi -n
7272

73-
build-linux-wheels:
73+
release: pr
7474
poetry build
75-
docker run --env PLAT=manylinux1_x86_64 --rm -it -v ${PWD}:/io -w /io quay.io/pypa/manylinux1_x86_64 /io/build_linux_wheels.sh
76-
cp ./wheelhouse/* dist/ && rm -rf wheelhouse
77-
78-
release:
79-
$(MAKE) build-linux-wheels
8075
$(MAKE) release-test
8176
$(MAKE) release-prod

aws_lambda_powertools/helper/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def build_lambda_context_model(context: object) -> LambdaContextModel:
6565

6666
context = {
6767
"function_name": context.function_name,
68-
"function_memory_size": str(context.memory_limit_in_mb),
68+
"function_memory_size": context.memory_limit_in_mb,
6969
"function_arn": context.invoked_function_arn,
7070
"function_request_id": context.aws_request_id,
7171
}

aws_lambda_powertools/logging/logger.py

+10-8
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def __init__(self, **kwargs):
6262
datefmt = kwargs.pop("datefmt", None)
6363

6464
super(JsonFormatter, self).__init__(datefmt=datefmt)
65+
self.reserved_keys = ["timestamp", "level", "location"]
6566
self.format_dict = {
6667
"timestamp": "%(asctime)s",
6768
"level": "%(levelname)s",
@@ -76,10 +77,12 @@ def format(self, record): # noqa: A003
7677

7778
log_dict = {}
7879
for key, value in self.format_dict.items():
79-
if value:
80+
if value and key in self.reserved_keys:
8081
# converts default logging expr to its record value
8182
# e.g. '%(asctime)s' to '2020-04-24 09:35:40,698'
8283
log_dict[key] = value % record_dict
84+
else:
85+
log_dict[key] = value
8386

8487
if isinstance(record_dict["msg"], dict):
8588
log_dict["message"] = record_dict["msg"]
@@ -149,20 +152,19 @@ def handler(evt, ctx):
149152
raise DeprecationWarning("Use Logger instead - This method will be removed when GA")
150153

151154

152-
def _is_cold_start() -> str:
153-
"""Verifies whether is cold start and return a string used for struct logging
155+
def _is_cold_start() -> bool:
156+
"""Verifies whether is cold start
154157
155158
Returns
156159
-------
157-
str
158-
lower case bool as a string
159-
aws_lambda_logging doesn't support bool; cast cold start value to string
160+
bool
161+
cold start bool value
160162
"""
161-
cold_start = "false"
163+
cold_start = False
162164

163165
global is_cold_start
164166
if is_cold_start:
165-
cold_start = str(is_cold_start).lower()
167+
cold_start = is_cold_start
166168
is_cold_start = False
167169

168170
return cold_start

aws_lambda_powertools/metrics/base.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,14 @@ def add_dimension(self, name: str, value: str):
203203
Dimension value
204204
"""
205205
logger.debug(f"Adding dimension: {name}:{value}")
206-
self.dimension_set[name] = value
206+
207+
# Cast value to str according to EMF spec
208+
# Majority of values are expected to be string already, so
209+
# checking before casting improves performance in most cases
210+
if isinstance(value, str):
211+
self.dimension_set[name] = value
212+
else:
213+
self.dimension_set[name] = str(value)
207214

208215
def __extract_metric_unit_value(self, unit: Union[str, MetricUnit]) -> str:
209216
"""Return metric value from metric unit whether that's str or MetricUnit enum

build_linux_wheels.sh

-23
This file was deleted.

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "aws_lambda_powertools"
3-
version = "0.9.4"
3+
version = "0.9.5"
44
description = "Python utilities for AWS Lambda functions including but not limited to tracing, logging and custom metric"
55
authors = ["Amazon Web Services"]
66
classifiers=[

tests/functional/test_logger.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -228,12 +228,12 @@ def handler(event, context):
228228
first_log, second_log, third_log, fourth_log = logs
229229

230230
# First execution
231-
assert "true" == first_log["cold_start"]
232-
assert "true" == second_log["cold_start"]
231+
assert first_log["cold_start"] is True
232+
assert second_log["cold_start"] is True
233233

234234
# Second execution
235-
assert "false" == third_log["cold_start"]
236-
assert "false" == fourth_log["cold_start"]
235+
assert third_log["cold_start"] is False
236+
assert fourth_log["cold_start"] is False
237237

238238

239239
def test_log_metric(capsys):

tests/functional/test_metrics.py

+33-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import json
2-
from typing import Dict, List
2+
from typing import Any, Dict, List
33

44
import pytest
55

@@ -48,6 +48,14 @@ def dimensions() -> List[Dict[str, str]]:
4848
]
4949

5050

51+
@pytest.fixture
52+
def non_str_dimensions() -> List[Dict[str, Any]]:
53+
return [
54+
{"name": "test_dimension", "value": True},
55+
{"name": "test_dimension_2", "value": 3},
56+
]
57+
58+
5159
@pytest.fixture
5260
def namespace() -> Dict[str, str]:
5361
return {"name": "test_namespace"}
@@ -380,3 +388,27 @@ def lambda_handler(evt, context):
380388

381389
# THEN metric set should be empty after function has been run
382390
assert my_metrics.metric_set == {}
391+
392+
393+
def test_log_metrics_non_string_dimension_values(capsys, metrics, non_str_dimensions, namespace):
394+
# GIVEN Metrics is initialized and dimensions with non-string values are added
395+
my_metrics = Metrics()
396+
my_metrics.add_namespace(**namespace)
397+
for metric in metrics:
398+
my_metrics.add_metric(**metric)
399+
for dimension in non_str_dimensions:
400+
my_metrics.add_dimension(**dimension)
401+
402+
# WHEN we utilize log_metrics to serialize
403+
# and flush all metrics at the end of a function execution
404+
@my_metrics.log_metrics
405+
def lambda_handler(evt, ctx):
406+
return True
407+
408+
lambda_handler({}, {})
409+
output = json.loads(capsys.readouterr().out.strip())
410+
411+
# THEN we should have no exceptions
412+
# and dimension values hould be serialized as strings
413+
for dimension in non_str_dimensions:
414+
assert isinstance(output[dimension["name"]], str)

0 commit comments

Comments
 (0)