-
Notifications
You must be signed in to change notification settings - Fork 1.5k
POC reworking how we handle tags within mysql integration #20390
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
Conversation
@@ -803,6 +803,7 @@ def test_database_instance_metadata(aggregator, dd_run_check, instance_complex, | |||
expected_tags = tags.METRIC_TAGS + [ | |||
"database_hostname:{}".format(expected_database_hostname), | |||
"database_instance:{}".format(expected_database_instance), | |||
"dbms_flavor:{}".format(MYSQL_FLAVOR.lower()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like an actual bug in our current logic. We set dbms_flavor
tag on all of our metrics/events except for database_instance
event. So then we also miss it on any cloud provider dynamic metric linking as well. This would fix that
# sort tags to ensure consistent ordering | ||
tags.sort() | ||
# Get sorted tags from tag manager and make a copy to avoid mutation | ||
tags = sorted(self.tag_manager.get_tags()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should get_tags
just always return a sorted list?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! It actually already is here. Good catch. Had left this initially as sorted()
returns a new copy. But will circle back and verify what sort of copy we need to perform to avoid mutation. Perhaps in the get_tags
returned value in general
@@ -384,7 +375,7 @@ def check(self, _): | |||
self.check_userstat_enabled(db) | |||
|
|||
# Metric collection | |||
tags = copy.deepcopy(self.tags) | |||
tags = copy.deepcopy(self.tag_manager.get_tags()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do these need to be copied still? I expect we're doing it to avoid mutations but if tag manager always returns a copy then we don't have to copy here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fully agree, good eye. This is on my list to iron out after the approach is validated as a direction we want to go
Codecov ReportAttention: Patch coverage is
Additional details and impacted files
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
What does this PR do?
Putting this up as a draft example of how I feel we can rework the logic on how we handle tags on the mysql integration. The goal here is to allow for more efficient handling of our tag lists, currently split between
MysqlCheck.tags
andMysqlCheck._non_internal_tags
.TagManager
Class SummaryThe
TagManager
class manages tags that can be either key-value pairs (e.g.,env:prod
) or keyless (e.g.,linux
). It supports both regular and internal tags and uses caching for efficient access.Internal Data Structures
self._tags
: Stores regular tags as a dictionary:{key: [value1, value2, ...]}
.self._internal_tags
: Stores internal-only tags with the same structure.self._cached_tag_list
: Cached list of formatted regular tag strings.self._cached_internal_tag_list
: Cached list of formatted internal tag strings.Core Methods
set_tag(key, value, replace=False, internal=False)
Adds a tag.
key
isNone
or empty, stores it as a keyless tag.replace=True
, replaces existing values.internal=True
, stores it in the internal tag dictionary.set_tags_from_list(tag_list, replace=False)
Adds multiple tags from a list of strings, internally calling set_tag on each.
Strings can be in
"key:value"
or"value"
(keyless) format.delete_tag(key, value=None, internal=False)
Deletes a tag or a specific value.
value
isNone
, removes all values for the key.None
or""
as the key.get_tags(include_internal=True)
Returns a sorted list of all tag strings.
"key:value"
.include_internal=True
.Data Relationships
_tags
) and internal (_internal_tags
).TagType.KEYLESS
enum as the key.Motivation
Currently it's quite difficult to work with our tags. We keep track of two lists of tags
MysqlCheck.tags
andMysqlCheck._non_internal_tags
. The latter is only used to avoid addingdd.internal*
tags todatabase_instance
events. Since we only store tags in a list today we have a mix of complex logic to search the list and delete a tag when updating mutable values between check runs as well as bugs that often result in tags not updating or removing properly. This lays a foundation to better handle these growing use case patterns. Storing tags in a hashmap structure allows for easily accessing single and multi value tags. The larger goal of this would be to open a new PR adding TagManager into our base utility class and have it used across all of our dbms integrations to better encapsulate tags and their life cycleReview checklist (to be filled by reviewers)
qa/skip-qa
label if the PR doesn't need to be tested during QA.backport/<branch-name>
label to the PR and it will automatically open a backport PR once this one is merged