Conversation
This fixes and reorganizes the code in a few ways:
* Make it clearer that _metrics, _dimensions, _metadata and
_default_dimensions are class attributes. They don't need to be also
set as instance attributes when constructing Metrics, as they're only
meant to be used to construct the provider with shared data.
* Expose metric_set, dimension_set, metadata_set and default_dimensions
as attributes just to keep backwards compatibility. Don't expose setters
for these as previously setting them would have no side effect. Now
users will get an error, which is a small breaking change but arguably
for something they should never be doing anyway.
* Fix setting the default_dimensions in AmazonCloudWatchEMFProvider, as
`default_dimensions or {}` was setting a new dict instance when the
given default_dimensions was empty and we want to share the given dict.
|
Nice catch on I did find two behavior gaps while testing this branch though.
def handler():
metrics = Metrics(namespace="MyNamespace", service="MyService")
metrics.set_default_dimensions(Environment="dev", Resource="MyJob")
metrics.add_metric(name="MyJobDuration", unit=MetricUnit.Seconds, value=42)
metrics.flush_metrics()
On the read-only properties: agreed nobody should be assigning those, but it is still a breaking change on a public attribute, and this file's own maintenance note says breaking customers before v3 is off the table, so that part is probably a maintainer call. |
|
Thanks for testing this so thoroughly. On both points you raised, I checked them against the code as it stood before this PR (commit 1. Repeat invocation warnings — before this PR, the same repeated-invocation scenario from #8402 produced 4 warnings on the very first invocation (from the double 2. Type reverts to non-str — same story. 3. Read-only properties — agreed this is ultimately a maintainer call under the pre-v3 policy. Worth noting the previous behavior wasn't a clean no-op either: reassigning Given all three points trace back to pre-existing behavior rather than regressions introduced here, I'd like to keep this PR as-is and track the two remaining gaps as follow-ups. |
|
On the str cast I have to push back, because I tested this on develop (8db13c7) before commenting. With |
|
@vishwakt our AIs are discussing here over a PR and corresponding issue that were not even triaged by the project maintainers yet. Please I want to wait for the project maintainers feedback first before proceeding further with any other conversation. |
* Property cast dimension value to str in all code that updates dimension_set. * No need to check if `isinstance(value, str)` before casting to str. This is already optimized in CPython, which reuses the same instance if value is already an str. This is unnecessary overengineering.
0def6bd to
11ca80a
Compare
| return self.provider.default_dimensions | ||
|
|
||
|
|
||
| # Maintenance: until v3, we can't afford to break customers. |
There was a problem hiding this comment.
This comment seems outdated, as we're already on v3.
|
There was a problem hiding this comment.
Hi Eric, thank you for taking the time to investigate this and for going deeper into the state-sharing problem. Your finding around default_dimensions or {} is important, and I have asked for that fix to be incorporated into #8403, with credit to you.
After comparing both approaches, I am leaning towards continuing with #8403 for the specific bug reported in #8402. It keeps the change focused and also avoids warnings when the same default dimensions are registered again during warm invocations. In this PR, that scenario can still warn because the existing dimension is treated as an overwrite even when its value has not changed.
The read-only properties are the one part that makes me hesitant. Even if assigning to those attributes was not very useful before, changing them to raise an error could still affect someone. I think we should look at that separately.
Would you be comfortable with us continuing with #8403 for #8402 and handling the broader cleanup separately? I do not want to close this PR before hearing your thoughts.
Thank you again for the investigation and especially for catching the empty dictionary issue.
|
Oi @leandrodamascena! Thanks and I agree there's too much going on in this PR. Also agree replacing the direct references to the shared data by read-only attributes is not worth it -- there are other ways to break these references. Let me revert that, but also break this PR into the smaller different changes, if you agree. I'll list them below so we can discuss first. Regarding #8403, and since I was the (apparently first) one complaining about the warnings in #8402, for your consideration: I don't think it's a good idea to start hiding the warnings when the key is being set twice but with the same value. The warnings are currently alerting to places where potentially code is being called twice and thanks to them I was able to dig deeper into issues that currently exist. Hiding these warnings when the value is the same seems more of a shortcut to try to fix a symptom, and it's not a fix for root causes, which are the scenarios where code is being called twice. And here's the break down of the different changes I'm proposing:
Item 3 and 4 are what fixes #8402. |
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 aws-powertools#8404, requested in review. Co-authored-by: Eric Nielsen <4120606+ericbn@users.noreply.github.com>
|
Thanks @ericbn for the patience here. I spent more time on both PRs because I did not want to lose the valid problems you found. With #8403, the original warning from #8402 is covered, and your fix for the empty I would like to keep this PR for the other problem you found: non-string default dimensions can return to their original type when another For that, could we reduce this PR to only that fix? I would remove the read-only properties, the direct use of There are also two cases to handle in the new implementation. Calling I think we should cover these cases here:
We should also remove Thank you for going deeper into this. The normalization issue is real and worth fixing; I just want to keep it separate from the public state changes. |
…sions (#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>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #8404 +/- ##
===========================================
+ Coverage 96.64% 96.65% +0.01%
===========================================
Files 296 296
Lines 14767 14767
Branches 1246 1245 -1
===========================================
+ Hits 14271 14273 +2
+ Misses 361 359 -2
Partials 135 135 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|



Issue number: closes #8402
Summary
Changes
This fixes and reorganizes the code in a few ways:
default_dimensions or {}was setting a new dict instance when the given default_dimensions was empty and we want to share the given dict.isinstance(value, str)before casting to str. This is already optimized in CPython, which reuses the same instance if value is already an str. This is unnecessary overengineering.User experience
This fix will not produce the following warnings anymore as it makes sure default dimensions are only set once when using metrics.add_metric and metrics.flush_metrics methods.
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.