Skip to content

Commit 94b9d5e

Browse files
vishwaktericbnleandrodamascena
authored
fix(metrics): stop spurious overwrite warnings from set_default_dimensions (#8403)
* fix(metrics): stop spurious overwrite warnings from set_default_dimensions Metrics.set_default_dimensions called provider.set_default_dimensions and then re-added every dimension through add_dimension, so the second pass always found the keys already registered and warned even on the first call. Remove the redundant loop and delegate to the provider. The provider also re-registers default dimensions internally, in clear_metrics after every flush and on repeated set_default_dimensions calls, which triggered the same warning on every warm invocation. Warn only when a dimension is overwritten with a different value, matching the warning message and the intent of #5653. Closes #8402 * fix(metrics): preserve shared default_dimensions dict in provider The provider replaced a falsy default_dimensions argument with a new dict, so the initially empty dict that Metrics shares was silently swapped out and updates made through the provider never reached the dict Metrics owns. Keep the given dict unless None is passed. Fix taken from #8404, requested in review. Co-authored-by: Eric Nielsen <4120606+ericbn@users.noreply.github.com> --------- Co-authored-by: Eric Nielsen <4120606+ericbn@users.noreply.github.com> Co-authored-by: Leandro Damascena <lcdama@amazon.pt>
1 parent 14af77f commit 94b9d5e

3 files changed

Lines changed: 102 additions & 6 deletions

File tree

aws_lambda_powertools/metrics/metrics.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ def log_metrics(
174174
)
175175

176176
def set_default_dimensions(self, **dimensions) -> None:
177-
self.provider.set_default_dimensions(**dimensions)
178177
"""Persist dimensions across Lambda invocations
179178
180179
Parameters
@@ -195,9 +194,7 @@ def set_default_dimensions(self, **dimensions) -> None:
195194
def lambda_handler():
196195
return True
197196
"""
198-
for name, value in dimensions.items():
199-
self.add_dimension(name, value)
200-
197+
self.provider.set_default_dimensions(**dimensions)
201198
self.default_dimensions.update(**dimensions)
202199

203200
def clear_default_dimensions(self) -> None:

aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def __init__(
8787
):
8888
self.metric_set = metric_set if metric_set is not None else {}
8989
self.dimension_set = dimension_set if dimension_set is not None else {}
90-
self.default_dimensions = default_dimensions or {}
90+
self.default_dimensions = default_dimensions if default_dimensions is not None else {}
9191
self.namespace = resolve_env_var_choice(choice=namespace, env=os.getenv(constants.METRICS_NAMESPACE_ENV))
9292
self.service = resolve_env_var_choice(choice=service, env=os.getenv(constants.SERVICE_NAME_ENV))
9393
self.function_name = function_name
@@ -317,7 +317,7 @@ def add_dimension(self, name: str, value: str) -> None:
317317
)
318318
return
319319

320-
if name in self.dimension_set or name in self.default_dimensions:
320+
if name in self.dimension_set and self.dimension_set[name] != value:
321321
warnings.warn(
322322
f"Dimension '{name}' has already been added. The previous value will be overwritten.",
323323
category=PowertoolsUserWarning,

tests/functional/metrics/required_dependencies/test_metrics_cloudwatch_emf.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,105 @@ def test_clear_default_dimensions(namespace):
11331133
assert not my_metrics.default_dimensions
11341134

11351135

1136+
def test_set_default_dimensions_no_warning_on_first_call(namespace):
1137+
# GIVEN a Metrics instance with no dimensions set
1138+
my_metrics = Metrics(namespace=namespace)
1139+
1140+
# WHEN we persist default dimensions for the first time
1141+
with warnings.catch_warnings(record=True) as w:
1142+
warnings.simplefilter("default")
1143+
my_metrics.set_default_dimensions(environment="test", log_group="/lambda/test")
1144+
1145+
# THEN no overwrite warning should be emitted
1146+
assert not [warning for warning in w if "has already been added" in str(warning.message)]
1147+
1148+
1149+
def test_set_default_dimensions_no_warning_when_unchanged(namespace):
1150+
# GIVEN a Metrics instance with default dimensions persisted
1151+
my_metrics = Metrics(namespace=namespace)
1152+
my_metrics.set_default_dimensions(environment="test", log_group="/lambda/test")
1153+
1154+
# WHEN we persist the same default dimensions again e.g., on a warm invocation
1155+
with warnings.catch_warnings(record=True) as w:
1156+
warnings.simplefilter("default")
1157+
my_metrics.set_default_dimensions(environment="test", log_group="/lambda/test")
1158+
1159+
# THEN no overwrite warning should be emitted
1160+
assert not [warning for warning in w if "has already been added" in str(warning.message)]
1161+
1162+
1163+
def test_set_default_dimensions_warns_when_value_changes(namespace):
1164+
# GIVEN a Metrics instance with a default dimension persisted
1165+
my_metrics = Metrics(namespace=namespace)
1166+
my_metrics.set_default_dimensions(environment="test")
1167+
1168+
# WHEN we persist the same default dimension with a different value
1169+
with warnings.catch_warnings(record=True) as w:
1170+
warnings.simplefilter("default")
1171+
my_metrics.set_default_dimensions(environment="prod")
1172+
1173+
# THEN a single overwrite warning should be emitted
1174+
assert len([warning for warning in w if "has already been added" in str(warning.message)]) == 1
1175+
1176+
1177+
def test_log_metrics_with_default_dimensions_no_warning_across_invocations(namespace, metric, capsys):
1178+
# GIVEN a Metrics instance with default dimensions persisted
1179+
my_metrics = Metrics(namespace=namespace)
1180+
my_metrics.set_default_dimensions(environment="test", log_group="/lambda/test")
1181+
1182+
@my_metrics.log_metrics
1183+
def lambda_handler(evt, ctx):
1184+
my_metrics.add_metric(**metric)
1185+
1186+
# WHEN metrics are flushed across multiple invocations
1187+
with warnings.catch_warnings(record=True) as w:
1188+
warnings.simplefilter("default")
1189+
lambda_handler({}, {})
1190+
lambda_handler({}, {})
1191+
1192+
# THEN no overwrite warning should be emitted
1193+
assert not [warning for warning in w if "has already been added" in str(warning.message)]
1194+
1195+
1196+
def test_provider_keeps_provided_default_dimensions_dict(namespace):
1197+
# GIVEN a provider constructed with an empty default dimensions dict e.g., the one Metrics shares
1198+
shared_default_dimensions: dict = {}
1199+
my_provider = AmazonCloudWatchEMFProvider(namespace=namespace, default_dimensions=shared_default_dimensions)
1200+
1201+
# WHEN default dimensions are set through the provider
1202+
my_provider.set_default_dimensions(environment="test")
1203+
1204+
# THEN the provided dict remains in use and receives the update
1205+
assert my_provider.default_dimensions is shared_default_dimensions
1206+
assert shared_default_dimensions == {"environment": "test"}
1207+
1208+
1209+
def test_metrics_shares_default_dimensions_with_provider(namespace):
1210+
# GIVEN a Metrics instance with the default provider
1211+
my_metrics = Metrics(namespace=namespace)
1212+
1213+
# WHEN default dimensions are set
1214+
my_metrics.set_default_dimensions(environment="test")
1215+
1216+
# THEN Metrics and the provider hold the same dict, both with the update
1217+
assert my_metrics.default_dimensions is my_metrics.provider.default_dimensions
1218+
assert my_metrics.default_dimensions == {"environment": "test"}
1219+
1220+
1221+
def test_add_dimension_no_warning_when_value_unchanged(namespace):
1222+
# GIVEN a Metrics instance with a dimension added
1223+
my_metrics = Metrics(namespace=namespace)
1224+
my_metrics.add_dimension("environment", "test")
1225+
1226+
# WHEN the same dimension is added again with the same value
1227+
with warnings.catch_warnings(record=True) as w:
1228+
warnings.simplefilter("default")
1229+
my_metrics.add_dimension("environment", "test")
1230+
1231+
# THEN no overwrite warning should be emitted
1232+
assert not [warning for warning in w if "has already been added" in str(warning.message)]
1233+
1234+
11361235
def test_add_dimensions_with_empty_value(namespace, capsys, metric):
11371236
# GIVEN Metrics is initialized
11381237
my_metrics = Metrics(namespace=namespace)

0 commit comments

Comments
 (0)