-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
feat: Expose sentry conventions in UI #92370
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
Changes from all commits
38ade07
7b16910
cc07a70
89898bb
09cfd2d
5e1bc4f
4faae59
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,7 @@ | ||
from typing import Literal | ||
import logging | ||
import os | ||
from dataclasses import replace | ||
from typing import Any, Literal | ||
|
||
from sentry_protos.snuba.v1.trace_item_attribute_pb2 import VirtualColumnContext | ||
|
||
|
@@ -14,15 +17,20 @@ | |
simple_sentry_field, | ||
) | ||
from sentry.search.eap.common_columns import COMMON_COLUMNS | ||
from sentry.search.eap.spans.sentry_conventions import SENTRY_CONVENTIONS_DIRECTORY | ||
from sentry.search.events.constants import ( | ||
PRECISE_FINISH_TS, | ||
PRECISE_START_TS, | ||
SPAN_MODULE_CATEGORY_VALUES, | ||
) | ||
from sentry.search.events.types import SnubaParams | ||
from sentry.search.utils import DEVICE_CLASS | ||
from sentry.utils import json | ||
from sentry.utils.validators import is_empty_string, is_event_id_or_list, is_span_id | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
SPAN_ATTRIBUTE_DEFINITIONS = { | ||
column.public_alias: column | ||
for column in COMMON_COLUMNS | ||
|
@@ -426,6 +434,53 @@ | |
] | ||
} | ||
|
||
DEPRECATED_ATTRIBUTES: list[dict[str, Any]] = [] | ||
try: | ||
with open(os.path.join(SENTRY_CONVENTIONS_DIRECTORY, "deprecated_attributes.json"), "rb") as f: | ||
DEPRECATED_ATTRIBUTES = json.loads(f.read())["attributes"] | ||
except Exception: | ||
logger.exception("Failed to load deprecated attributes from 'deprecated_attributes.json'") | ||
|
||
|
||
try: | ||
for attribute in DEPRECATED_ATTRIBUTES: | ||
deprecation = attribute.get("deprecation", {}) | ||
attr_type = attribute.get("type", "string") | ||
key = attribute["key"] | ||
if ( | ||
"replacement" in deprecation | ||
and "_status" in deprecation | ||
and deprecation["_status"] == "backfill" | ||
): | ||
status = deprecation["_status"] | ||
replacement = deprecation["replacement"] | ||
if key in SPAN_ATTRIBUTE_DEFINITIONS: | ||
deprecated_attr = SPAN_ATTRIBUTE_DEFINITIONS[key] | ||
SPAN_ATTRIBUTE_DEFINITIONS[key] = replace( | ||
deprecated_attr, replacement=replacement, deprecation_status=status | ||
) | ||
# TODO: Introduce units to attribute schema. | ||
SPAN_ATTRIBUTE_DEFINITIONS[replacement] = replace( | ||
deprecated_attr, public_alias=replacement, internal_name=replacement | ||
) | ||
else: | ||
Comment on lines
+463
to
+465
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doing a |
||
SPAN_ATTRIBUTE_DEFINITIONS[key] = ResolvedAttribute( | ||
public_alias=key, | ||
internal_name=key, | ||
search_type=attr_type, | ||
replacement=replacement, | ||
deprecation_status=status, | ||
) | ||
|
||
SPAN_ATTRIBUTE_DEFINITIONS[replacement] = ResolvedAttribute( | ||
public_alias=replacement, | ||
internal_name=replacement, | ||
search_type=attr_type, | ||
) | ||
|
||
Comment on lines
+467
to
+479
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adds the deprecated attributes to the definitions if they don't already exist so they get replaced with the new convention correctly. |
||
except Exception as e: | ||
logger.exception("Failed to update attribute definitions: %s", e) | ||
|
||
|
||
def device_class_context_constructor(params: SnubaParams) -> VirtualColumnContext: | ||
# EAP defaults to lower case `unknown`, but in querybuilder we used `Unknown` | ||
|
@@ -503,6 +558,18 @@ def is_starred_segment_context_constructor(params: SnubaParams) -> VirtualColumn | |
if definition.private | ||
} | ||
|
||
SPANS_REPLACEMENT_ATTRIBUTES: set[str] = { | ||
definition.replacement | ||
for definition in SPAN_ATTRIBUTE_DEFINITIONS.values() | ||
if definition.replacement | ||
} | ||
|
||
SPANS_REPLACEMENT_MAP: dict[str, str] = { | ||
definition.public_alias: definition.replacement | ||
for definition in SPAN_ATTRIBUTE_DEFINITIONS.values() | ||
if definition.replacement | ||
} | ||
|
||
|
||
SPAN_VIRTUAL_CONTEXTS = { | ||
"device.class": VirtualColumnDefinition( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import os | ||
|
||
SENTRY_CONVENTIONS_DIRECTORY = os.path.join(os.path.dirname(os.path.abspath(__file__))) |
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.
In addition to this check 🤔 would it help to have a test that would effectively make sure that the json is accessible and valid?