@@ -69,6 +69,7 @@ def wrap_executor_context_init(wrapped, instance, args, kwargs):
6969 instance .field_resolver = wrap_resolver (instance .field_resolver )
7070 instance .field_resolver ._nr_wrapped = True
7171
72+
7273 return result
7374
7475
@@ -91,65 +92,84 @@ def wrap_execute_operation(wrapped, instance, args, kwargs):
9192 except TypeError :
9293 operation = bind_operation_v2 (* args , ** kwargs )
9394
94- operation_name = operation .name
95- if hasattr (operation_name , "value" ):
96- operation_name = operation_name .value
95+ operation_name = get_node_value (operation , "name" )
9796 trace .operation_name = operation_name = operation_name or "<anonymous>"
9897
99- operation_type = operation .operation
100- if hasattr (operation_type , "name" ):
101- operation_type = operation_type .name .lower ()
98+ operation_type = get_node_value (operation , "operation" , "name" ).lower ()
10299 trace .operation_type = operation_type = operation_type or "<unknown>"
103100
104101 if operation .selection_set is not None :
105102 fields = operation .selection_set .selections
106- try :
107- deepest_path = traverse_deepest_path (fields )
108- except :
109- deepest_path = []
110- trace .deepest_path = deepest_path = "." .join (deepest_path ) or "<unknown>"
103+ # Ignore transactions for introspection queries
104+ for field in fields :
105+ if get_node_value (field , "name" ) in GRAPHQL_INTROSPECTION_FIELDS :
106+ ignore_transaction ()
111107
112- transaction .set_transaction_name (callable_name (wrapped ), "GraphQL" , priority = 11 )
108+ deepest_path = traverse_deepest_unique_path (fields )
109+ trace .deepest_path = deepest_path = "." .join (deepest_path ) or ""
113110
111+ transaction .set_transaction_name (callable_name (wrapped ), "GraphQL" , priority = 11 )
114112 result = wrapped (* args , ** kwargs )
115- transaction_name = "%s/%s/%s" % (operation_type , operation_name , deepest_path )
113+ transaction_name = "%s/%s/%s" % (operation_type , operation_name , deepest_path ) if deepest_path else "%s/%s" % ( operation_type , operation_name )
116114 transaction .set_transaction_name (transaction_name , "GraphQL" , priority = 14 )
117115
118116 return result
119117
120118
121- def traverse_deepest_path (fields ):
122- inputs = deque (((field , deque (), 0 ) for field in fields ))
123- deepest_path_len = 0
124- deepest_path = []
125-
126- while inputs :
127- field , current_path , current_path_len = inputs .pop ()
128-
129- field_name = field .name
130- if hasattr (field_name , "value" ):
131- field_name = field_name .value
132-
133- if field_name in GRAPHQL_INTROSPECTION_FIELDS :
134- # If an introspection query is identified, ignore the transaction completely.
135- # This matches the logic used in Apollo server for identifying introspection queries.
136- ignore_transaction ()
137- return []
138- elif field_name not in GRAPHQL_IGNORED_FIELDS :
139- # Only add to the current path for non-ignored values.
140- current_path .append (field_name )
141- current_path_len += 1
142-
143- if field .selection_set is None or len (field .selection_set .selections ) == 0 :
144- if deepest_path_len < current_path_len :
145- deepest_path = current_path
146- deepest_path_len = current_path_len
147- else :
148- for inner_field in field .selection_set .selections :
149- inputs .append ((inner_field , copy (current_path ), current_path_len ))
119+ def get_node_value (field , attr , subattr = "value" ):
120+ field_name = getattr (field , attr , None )
121+ if hasattr (field_name , subattr ):
122+ field_name = getattr (field_name , subattr )
123+ return field_name
150124
151- return deepest_path
152125
126+ def is_fragment (field ):
127+ # Resolve version specific imports
128+ try :
129+ from graphql .language .ast import FragmentSpread , InlineFragment
130+ except ImportError :
131+ from graphql import FragmentSpreadNode as FragmentSpread , InlineFragmentNode as InlineFragment
132+
133+ _fragment_types = (InlineFragment , FragmentSpread )
134+
135+ return isinstance (field , _fragment_types )
136+
137+ def is_named_fragment (field ):
138+ # Resolve version specific imports
139+ try :
140+ from graphql .language .ast import NamedType
141+ except ImportError :
142+ from graphql import NamedTypeNode as NamedType
143+
144+ return is_fragment (field ) and getattr (field , "type_condition" , None ) is not None and isinstance (field .type_condition , NamedType )
145+
146+
147+ def traverse_deepest_unique_path (fields ):
148+ deepest_path = deque ()
149+
150+ while fields is not None and len (fields ) > 0 :
151+ fields = [f for f in fields if get_node_value (f , "name" ) not in GRAPHQL_IGNORED_FIELDS ]
152+ if len (fields ) != 1 : # Either selections is empty, or non-unique
153+ return deepest_path
154+ field = fields [0 ]
155+
156+ field_name = get_node_value (field , "name" )
157+ if is_named_fragment (field ):
158+ name = get_node_value (field .type_condition , "name" )
159+ if name :
160+ deepest_path .append ("%s<%s>" % (deepest_path .pop (), name ))
161+ elif is_fragment (field ):
162+ break
163+ else :
164+ if field_name :
165+ deepest_path .append (field_name )
166+
167+ if field .selection_set is None :
168+ break
169+ else :
170+ fields = field .selection_set .selections
171+
172+ return deepest_path
153173
154174def bind_get_middleware_resolvers (middlewares ):
155175 return middlewares
@@ -176,7 +196,6 @@ def wrap_middleware(wrapped, instance, args, kwargs):
176196 return wrapped (* args , ** kwargs )
177197
178198
179-
180199def bind_get_field_resolver (field_resolver ):
181200 return field_resolver
182201
@@ -217,7 +236,9 @@ def wrap_resolver(wrapped, instance, args, kwargs):
217236 transaction = current_transaction ()
218237 if transaction is None :
219238 return wrapped (* args , ** kwargs )
239+
220240 transaction .set_transaction_name (callable_name (wrapped ), "GraphQL" , priority = 13 )
241+
221242 with ErrorTrace (ignore = ignore_graphql_duplicate_exception ):
222243 return wrapped (* args , ** kwargs )
223244
@@ -250,8 +271,8 @@ def wrap_parse(wrapped, instance, args, kwargs):
250271 transaction = current_transaction ()
251272 if transaction is None :
252273 return wrapped (* args , ** kwargs )
253- transaction .set_transaction_name (callable_name (wrapped ), "GraphQL" , priority = 10 )
254274
275+ transaction .set_transaction_name (callable_name (wrapped ), "GraphQL" , priority = 10 )
255276 with ErrorTrace (ignore = ignore_graphql_duplicate_exception ):
256277 return wrapped (* args , ** kwargs )
257278
@@ -333,7 +354,7 @@ def wrap_graphql_impl(wrapped, instance, args, kwargs):
333354 trace .statement = graphql_statement (query )
334355 with ErrorTrace (ignore = ignore_graphql_duplicate_exception ):
335356 result = wrapped (* args , ** kwargs )
336- #transaction.set_transaction_name(transaction_name, "GraphQL", priority=14)
357+ # transaction.set_transaction_name(transaction_name, "GraphQL", priority=14)
337358 return result
338359
339360
0 commit comments