2020 TraceItemType as ProtoTraceItemType ,
2121)
2222from sentry_protos .snuba .v1 .trace_item_attribute_pb2 import AttributeKey
23- from sentry_protos .snuba .v1 .trace_item_filter_pb2 import ExistsFilter , OrFilter , TraceItemFilter
23+ from sentry_protos .snuba .v1 .trace_item_filter_pb2 import (
24+ ExistsFilter ,
25+ OrFilter ,
26+ TraceItemFilter ,
27+ )
2428
2529from sentry import features , options
2630from sentry .api .api_owners import ApiOwner
5458from sentry .search .eap .resolver import SearchResolver
5559from sentry .search .eap .spans .definitions import SPAN_DEFINITIONS
5660from sentry .search .eap .trace_metrics .definitions import TRACE_METRICS_DEFINITIONS
57- from sentry .search .eap .types import SearchResolverConfig , SupportedTraceItemType
61+ from sentry .search .eap .types import (
62+ AttributeSourceType ,
63+ SearchResolverConfig ,
64+ SupportedTraceItemType ,
65+ )
5866from sentry .search .eap .utils import (
5967 can_expose_attribute ,
6068 get_secondary_aliases ,
7987POSSIBLE_ATTRIBUTE_TYPES = ["string" , "number" , "boolean" ]
8088
8189
90+ class ProxyResolvedAttribute (ResolvedAttribute ):
91+ pass
92+
93+
8294class TraceItemAttributeKey (TypedDict ):
8395 key : str
8496 name : str
@@ -218,6 +230,7 @@ def as_attribute_key(
218230 name : str ,
219231 attr_type : Literal ["string" , "number" , "boolean" ],
220232 item_type : SupportedTraceItemType ,
233+ is_proxy : bool = False ,
221234) -> TraceItemAttributeKey :
222235 public_key , public_name , attribute_source = translate_internal_to_public_alias (
223236 name , attr_type , item_type
@@ -226,6 +239,8 @@ def as_attribute_key(
226239
227240 if public_key is not None and public_name is not None :
228241 pass
242+ elif is_proxy :
243+ public_key = public_name = name
229244 elif attr_type == "number" :
230245 public_key = f"tags[{ name } ,number]"
231246 public_name = name
@@ -237,7 +252,11 @@ def as_attribute_key(
237252 public_name = name
238253
239254 serialized_source : dict [str , str | bool ] = {
240- "source_type" : attribute_source ["source_type" ].value
255+ "source_type" : (
256+ attribute_source ["source_type" ].value
257+ if not is_proxy
258+ else AttributeSourceType .SENTRY .value
259+ )
241260 }
242261 if attribute_source .get ("is_transformed_alias" ):
243262 serialized_source ["is_transformed_alias" ] = True
@@ -378,18 +397,54 @@ def query_trace_attributes(
378397 all_aliased_attributes = []
379398 # our aliases don't exist in the db, so filter over our aliases
380399 # virtually page through defined aliases before we hit the db
381- if substring_match and offset <= len (column_definitions .columns ):
382- for index , column in enumerate (column_definitions .columns .values ()):
383- if (
384- column .proto_type == attr_type
385- and substring_match in column .public_alias
386- and not column .secondary_alias
387- and not column .private
388- ):
389- all_aliased_attributes .append (column )
400+ if offset <= len (column_definitions .columns ) + len (column_definitions .contexts ):
401+ if substring_match :
402+ for column in column_definitions .columns .values ():
403+ if (
404+ column .proto_type == attr_type
405+ and substring_match in column .public_alias
406+ and not column .secondary_alias
407+ and not column .private
408+ ):
409+ all_aliased_attributes .append (column )
410+ for (
411+ public_label ,
412+ virtual_context ,
413+ ) in column_definitions .contexts .items ():
414+ if (
415+ substring_match in public_label
416+ and virtual_context .search_type is not None
417+ and not virtual_context .secondary_alias
418+ and constants .TYPE_MAP [virtual_context .search_type ] == attr_type
419+ ):
420+ all_aliased_attributes .append (
421+ ProxyResolvedAttribute (
422+ public_alias = public_label ,
423+ internal_name = public_label ,
424+ search_type = virtual_context .search_type ,
425+ )
426+ )
427+ else :
428+ for (
429+ public_label ,
430+ virtual_context ,
431+ ) in column_definitions .contexts .items ():
432+ if (
433+ substring_match in public_label
434+ and virtual_context .search_type is not None
435+ and not virtual_context .secondary_alias
436+ and constants .TYPE_MAP [virtual_context .search_type ] == attr_type
437+ ):
438+ all_aliased_attributes .append (
439+ ProxyResolvedAttribute (
440+ public_alias = public_label ,
441+ internal_name = public_label ,
442+ search_type = virtual_context .search_type ,
443+ )
444+ )
390445 aliased_attributes = all_aliased_attributes [offset : offset + limit ]
391446 with sentry_sdk .start_span (op = "query" , name = "attribute_names" ) as span :
392- if len (aliased_attributes ) < limit - 1 :
447+ if len (aliased_attributes ) < limit :
393448 offset -= len (all_aliased_attributes ) - len (aliased_attributes )
394449 limit -= len (aliased_attributes )
395450 rpc_request = TraceItemAttributeNamesRequest (
@@ -419,6 +474,7 @@ def query_trace_attributes(
419474 include_internal ,
420475 substring_match ,
421476 aliased_attributes ,
477+ all_aliased_attributes ,
422478 )
423479
424480 sentry_sdk .set_context ("api_response" , {"attributes" : attributes })
@@ -433,7 +489,8 @@ def serialize_trace_attributes_using_sentry_conventions(
433489 trace_item_type : SupportedTraceItemType ,
434490 include_internal : bool ,
435491 substring_match : str ,
436- aliased_attributes : list [ResolvedAttribute ],
492+ aliased_attributes : list [ResolvedAttribute | ProxyResolvedAttribute ],
493+ exclude_attributes : list [ResolvedAttribute | ProxyResolvedAttribute ],
437494 ) -> list [TraceItemAttributeKey ]:
438495 attribute_keys = {}
439496 for attribute in rpc_response .attributes :
@@ -457,11 +514,21 @@ def serialize_trace_attributes_using_sentry_conventions(
457514 )
458515
459516 attribute_keys [attr_key ["name" ]] = attr_key
517+ for aliased_attr in exclude_attributes :
518+ attr_key = as_attribute_key (
519+ aliased_attr .internal_name ,
520+ attribute_type ,
521+ trace_item_type ,
522+ is_proxy = isinstance (aliased_attr , ProxyResolvedAttribute ),
523+ )
524+ if attr_key ["name" ] in attribute_keys :
525+ del attribute_keys [attr_key ["name" ]]
460526 for aliased_attr in aliased_attributes :
461527 attr_key = as_attribute_key (
462528 aliased_attr .internal_name ,
463529 attribute_type ,
464530 trace_item_type ,
531+ is_proxy = isinstance (aliased_attr , ProxyResolvedAttribute ),
465532 )
466533 attribute_keys [attr_key ["name" ]] = attr_key
467534
@@ -476,33 +543,42 @@ def serialize_trace_attributes(
476543 trace_item_type : SupportedTraceItemType ,
477544 include_internal : bool ,
478545 substring_match : str ,
479- aliased_attributes : list [ResolvedAttribute ],
546+ aliased_attributes : list [ResolvedAttribute | ProxyResolvedAttribute ],
547+ exclude_attributes : list [ResolvedAttribute | ProxyResolvedAttribute ],
480548 ) -> list [TraceItemAttributeKey ]:
481- attributes = list (
482- filter (
483- lambda x : (
484- not is_sentry_convention_replacement_attribute (x ["name" ], trace_item_type )
549+ attribute_keys = {}
550+ for attribute in rpc_response .attributes :
551+ if attribute .name and can_expose_attribute (
552+ attribute .name ,
553+ trace_item_type ,
554+ include_internal = include_internal ,
555+ ):
556+ attr_key = as_attribute_key (
557+ attribute .name ,
558+ attribute_type ,
559+ trace_item_type ,
560+ )
561+ if (
562+ not is_sentry_convention_replacement_attribute (
563+ attr_key ["name" ], trace_item_type
564+ )
485565 # Remove anything where the public alias doesn't match the substring
486566 # This can happen when the public alias is different, but that's handled by
487567 # aliased_attributes
488- and (substring_match in x ["name" ] if substring_match else True )
489- ),
490- [
491- as_attribute_key (
492- attribute .name ,
493- attribute_type ,
494- trace_item_type ,
495- )
496- for attribute in rpc_response .attributes
497- if attribute .name
498- and can_expose_attribute (
499- attribute .name ,
500- trace_item_type ,
501- include_internal = include_internal ,
502- )
503- ],
568+ and (substring_match in attr_key ["name" ] if substring_match else True )
569+ ):
570+ attribute_keys [attr_key ["key" ]] = attr_key
571+ # We need to exclude any aliased attributes here since because of pagination they might have already been seen
572+ # earlier
573+ for aliased_attr in exclude_attributes :
574+ attr_key = as_attribute_key (
575+ aliased_attr .internal_name ,
576+ attribute_type ,
577+ trace_item_type ,
578+ is_proxy = isinstance (aliased_attr , ProxyResolvedAttribute ),
504579 )
505- )
580+ if attr_key ["name" ] in attribute_keys :
581+ del attribute_keys [attr_key ["name" ]]
506582 for aliased_attr in aliased_attributes :
507583 if can_expose_attribute (
508584 aliased_attr .public_alias ,
@@ -513,8 +589,11 @@ def serialize_trace_attributes(
513589 aliased_attr .internal_name ,
514590 attribute_type ,
515591 trace_item_type ,
592+ is_proxy = isinstance (aliased_attr , ProxyResolvedAttribute ),
516593 )
517- attributes .append (attr_key )
594+ attribute_keys [attr_key ["key" ]] = attr_key
595+ attributes = list (attribute_keys .values ())
596+ sentry_sdk .set_context ("api_response" , {"attributes" : attributes })
518597 return attributes
519598
520599
0 commit comments