graphql 1.13.19 → 2.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (256) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +1 -1
  3. data/lib/generators/graphql/relay.rb +3 -17
  4. data/lib/generators/graphql/templates/schema.erb +3 -0
  5. data/lib/graphql/analysis/ast/field_usage.rb +3 -1
  6. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
  7. data/lib/graphql/analysis/ast/query_complexity.rb +1 -1
  8. data/lib/graphql/analysis/ast/query_depth.rb +0 -1
  9. data/lib/graphql/analysis/ast/visitor.rb +43 -36
  10. data/lib/graphql/analysis/ast.rb +2 -12
  11. data/lib/graphql/analysis.rb +0 -7
  12. data/lib/graphql/backtrace/table.rb +2 -20
  13. data/lib/graphql/backtrace/tracer.rb +2 -3
  14. data/lib/graphql/backtrace.rb +2 -8
  15. data/lib/graphql/dataloader/null_dataloader.rb +3 -1
  16. data/lib/graphql/dataloader/source.rb +9 -0
  17. data/lib/graphql/dataloader.rb +4 -1
  18. data/lib/graphql/dig.rb +1 -1
  19. data/lib/graphql/execution/errors.rb +12 -82
  20. data/lib/graphql/execution/interpreter/resolve.rb +26 -0
  21. data/lib/graphql/execution/interpreter/runtime.rb +162 -119
  22. data/lib/graphql/execution/interpreter.rb +187 -78
  23. data/lib/graphql/execution/lazy.rb +7 -21
  24. data/lib/graphql/execution/lookahead.rb +44 -40
  25. data/lib/graphql/execution/multiplex.rb +3 -174
  26. data/lib/graphql/execution.rb +11 -4
  27. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  28. data/lib/graphql/introspection/entry_points.rb +2 -15
  29. data/lib/graphql/introspection/type_type.rb +8 -1
  30. data/lib/graphql/introspection.rb +4 -3
  31. data/lib/graphql/language/document_from_schema_definition.rb +18 -35
  32. data/lib/graphql/language/lexer.rb +216 -1488
  33. data/lib/graphql/language/lexer.ri +744 -0
  34. data/lib/graphql/language/nodes.rb +41 -33
  35. data/lib/graphql/language/parser.rb +375 -363
  36. data/lib/graphql/language/parser.y +48 -43
  37. data/lib/graphql/language/printer.rb +37 -21
  38. data/lib/graphql/language/visitor.rb +191 -83
  39. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  40. data/lib/graphql/pagination/array_connection.rb +4 -2
  41. data/lib/graphql/pagination/connection.rb +31 -4
  42. data/lib/graphql/pagination/connections.rb +3 -28
  43. data/lib/graphql/pagination/relation_connection.rb +2 -0
  44. data/lib/graphql/query/context.rb +155 -196
  45. data/lib/graphql/query/input_validation_result.rb +1 -1
  46. data/lib/graphql/query/null_context.rb +0 -3
  47. data/lib/graphql/query/validation_pipeline.rb +10 -34
  48. data/lib/graphql/query/variables.rb +7 -20
  49. data/lib/graphql/query.rb +32 -42
  50. data/lib/graphql/railtie.rb +0 -104
  51. data/lib/graphql/rake_task/validate.rb +1 -1
  52. data/lib/graphql/rake_task.rb +29 -1
  53. data/lib/graphql/relay/range_add.rb +9 -20
  54. data/lib/graphql/relay.rb +0 -15
  55. data/lib/graphql/schema/addition.rb +7 -9
  56. data/lib/graphql/schema/argument.rb +36 -43
  57. data/lib/graphql/schema/build_from_definition.rb +32 -18
  58. data/lib/graphql/schema/directive/one_of.rb +12 -0
  59. data/lib/graphql/schema/directive/transform.rb +1 -1
  60. data/lib/graphql/schema/directive.rb +11 -22
  61. data/lib/graphql/schema/enum.rb +28 -39
  62. data/lib/graphql/schema/enum_value.rb +5 -25
  63. data/lib/graphql/schema/field/connection_extension.rb +4 -0
  64. data/lib/graphql/schema/field.rb +214 -327
  65. data/lib/graphql/schema/input_object.rb +56 -67
  66. data/lib/graphql/schema/interface.rb +0 -35
  67. data/lib/graphql/schema/introspection_system.rb +3 -8
  68. data/lib/graphql/schema/late_bound_type.rb +8 -2
  69. data/lib/graphql/schema/list.rb +0 -6
  70. data/lib/graphql/schema/loader.rb +1 -2
  71. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -19
  72. data/lib/graphql/schema/member/build_type.rb +5 -7
  73. data/lib/graphql/schema/member/has_arguments.rb +144 -53
  74. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  75. data/lib/graphql/schema/member/has_directives.rb +71 -56
  76. data/lib/graphql/schema/member/has_fields.rb +15 -3
  77. data/lib/graphql/schema/member/has_interfaces.rb +47 -18
  78. data/lib/graphql/schema/member/has_validators.rb +31 -5
  79. data/lib/graphql/schema/member/relay_shortcuts.rb +28 -2
  80. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  81. data/lib/graphql/schema/member/validates_input.rb +1 -1
  82. data/lib/graphql/schema/member.rb +0 -6
  83. data/lib/graphql/schema/mutation.rb +0 -9
  84. data/lib/graphql/schema/non_null.rb +1 -7
  85. data/lib/graphql/schema/object.rb +15 -52
  86. data/lib/graphql/schema/relay_classic_mutation.rb +53 -42
  87. data/lib/graphql/schema/resolver/has_payload_type.rb +20 -10
  88. data/lib/graphql/schema/resolver.rb +41 -42
  89. data/lib/graphql/schema/scalar.rb +7 -22
  90. data/lib/graphql/schema/subscription.rb +0 -7
  91. data/lib/graphql/schema/timeout.rb +24 -28
  92. data/lib/graphql/schema/type_membership.rb +3 -0
  93. data/lib/graphql/schema/union.rb +10 -17
  94. data/lib/graphql/schema/warden.rb +23 -6
  95. data/lib/graphql/schema/wrapper.rb +0 -5
  96. data/lib/graphql/schema.rb +240 -968
  97. data/lib/graphql/static_validation/all_rules.rb +1 -0
  98. data/lib/graphql/static_validation/base_visitor.rb +4 -21
  99. data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
  100. data/lib/graphql/static_validation/error.rb +2 -2
  101. data/lib/graphql/static_validation/literal_validator.rb +19 -1
  102. data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
  103. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +12 -12
  104. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  105. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  106. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +12 -6
  107. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
  108. data/lib/graphql/static_validation/validator.rb +3 -25
  109. data/lib/graphql/static_validation.rb +0 -2
  110. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -1
  111. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
  112. data/lib/graphql/subscriptions/event.rb +3 -8
  113. data/lib/graphql/subscriptions/instrumentation.rb +0 -51
  114. data/lib/graphql/subscriptions.rb +32 -20
  115. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  116. data/lib/graphql/tracing/appoptics_trace.rb +231 -0
  117. data/lib/graphql/tracing/appsignal_trace.rb +66 -0
  118. data/lib/graphql/tracing/data_dog_trace.rb +148 -0
  119. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  120. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  121. data/lib/graphql/tracing/notifications_trace.rb +41 -0
  122. data/lib/graphql/tracing/platform_trace.rb +107 -0
  123. data/lib/graphql/tracing/platform_tracing.rb +26 -41
  124. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  125. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  126. data/lib/graphql/tracing/scout_trace.rb +72 -0
  127. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  128. data/lib/graphql/tracing.rb +136 -40
  129. data/lib/graphql/type_kinds.rb +6 -3
  130. data/lib/graphql/types/iso_8601_date.rb +4 -1
  131. data/lib/graphql/types/iso_8601_date_time.rb +4 -0
  132. data/lib/graphql/types/relay/base_connection.rb +16 -6
  133. data/lib/graphql/types/relay/connection_behaviors.rb +5 -25
  134. data/lib/graphql/types/relay/default_relay.rb +5 -9
  135. data/lib/graphql/types/relay/edge_behaviors.rb +1 -4
  136. data/lib/graphql/types/relay/node_behaviors.rb +5 -1
  137. data/lib/graphql/types/relay.rb +0 -2
  138. data/lib/graphql/types/string.rb +1 -1
  139. data/lib/graphql/version.rb +1 -1
  140. data/lib/graphql.rb +11 -72
  141. metadata +31 -132
  142. data/lib/graphql/analysis/analyze_query.rb +0 -98
  143. data/lib/graphql/analysis/field_usage.rb +0 -45
  144. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  145. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  146. data/lib/graphql/analysis/query_complexity.rb +0 -88
  147. data/lib/graphql/analysis/query_depth.rb +0 -43
  148. data/lib/graphql/analysis/reducer_state.rb +0 -48
  149. data/lib/graphql/argument.rb +0 -131
  150. data/lib/graphql/authorization.rb +0 -82
  151. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  152. data/lib/graphql/backwards_compatibility.rb +0 -61
  153. data/lib/graphql/base_type.rb +0 -232
  154. data/lib/graphql/boolean_type.rb +0 -2
  155. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  156. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  157. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  158. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  159. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  160. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  161. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  162. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  163. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  164. data/lib/graphql/compatibility.rb +0 -5
  165. data/lib/graphql/define/assign_argument.rb +0 -12
  166. data/lib/graphql/define/assign_connection.rb +0 -13
  167. data/lib/graphql/define/assign_enum_value.rb +0 -18
  168. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  169. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  170. data/lib/graphql/define/assign_object_field.rb +0 -42
  171. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  172. data/lib/graphql/define/instance_definable.rb +0 -255
  173. data/lib/graphql/define/no_definition_error.rb +0 -7
  174. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  175. data/lib/graphql/define/type_definer.rb +0 -31
  176. data/lib/graphql/define.rb +0 -31
  177. data/lib/graphql/deprecated_dsl.rb +0 -55
  178. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  179. data/lib/graphql/directive/include_directive.rb +0 -2
  180. data/lib/graphql/directive/skip_directive.rb +0 -2
  181. data/lib/graphql/directive.rb +0 -107
  182. data/lib/graphql/enum_type.rb +0 -133
  183. data/lib/graphql/execution/execute.rb +0 -333
  184. data/lib/graphql/execution/flatten.rb +0 -40
  185. data/lib/graphql/execution/instrumentation.rb +0 -92
  186. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  187. data/lib/graphql/execution/typecast.rb +0 -50
  188. data/lib/graphql/field/resolve.rb +0 -59
  189. data/lib/graphql/field.rb +0 -226
  190. data/lib/graphql/float_type.rb +0 -2
  191. data/lib/graphql/function.rb +0 -128
  192. data/lib/graphql/id_type.rb +0 -2
  193. data/lib/graphql/input_object_type.rb +0 -138
  194. data/lib/graphql/int_type.rb +0 -2
  195. data/lib/graphql/interface_type.rb +0 -72
  196. data/lib/graphql/internal_representation/document.rb +0 -27
  197. data/lib/graphql/internal_representation/node.rb +0 -206
  198. data/lib/graphql/internal_representation/print.rb +0 -51
  199. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  200. data/lib/graphql/internal_representation/scope.rb +0 -88
  201. data/lib/graphql/internal_representation/visit.rb +0 -36
  202. data/lib/graphql/internal_representation.rb +0 -7
  203. data/lib/graphql/language/lexer.rl +0 -260
  204. data/lib/graphql/list_type.rb +0 -80
  205. data/lib/graphql/non_null_type.rb +0 -71
  206. data/lib/graphql/object_type.rb +0 -130
  207. data/lib/graphql/query/arguments.rb +0 -189
  208. data/lib/graphql/query/arguments_cache.rb +0 -24
  209. data/lib/graphql/query/executor.rb +0 -52
  210. data/lib/graphql/query/literal_input.rb +0 -136
  211. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  212. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  213. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  214. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  215. data/lib/graphql/query/serial_execution.rb +0 -40
  216. data/lib/graphql/relay/array_connection.rb +0 -83
  217. data/lib/graphql/relay/base_connection.rb +0 -189
  218. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  219. data/lib/graphql/relay/connection_resolve.rb +0 -43
  220. data/lib/graphql/relay/connection_type.rb +0 -54
  221. data/lib/graphql/relay/edge.rb +0 -27
  222. data/lib/graphql/relay/edge_type.rb +0 -19
  223. data/lib/graphql/relay/edges_instrumentation.rb +0 -39
  224. data/lib/graphql/relay/global_id_resolve.rb +0 -17
  225. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  226. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  227. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  228. data/lib/graphql/relay/mutation/result.rb +0 -38
  229. data/lib/graphql/relay/mutation.rb +0 -106
  230. data/lib/graphql/relay/node.rb +0 -39
  231. data/lib/graphql/relay/page_info.rb +0 -7
  232. data/lib/graphql/relay/relation_connection.rb +0 -188
  233. data/lib/graphql/relay/type_extensions.rb +0 -32
  234. data/lib/graphql/scalar_type.rb +0 -91
  235. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  236. data/lib/graphql/schema/default_parse_error.rb +0 -10
  237. data/lib/graphql/schema/default_type_error.rb +0 -17
  238. data/lib/graphql/schema/member/accepts_definition.rb +0 -164
  239. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
  240. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  241. data/lib/graphql/schema/middleware_chain.rb +0 -82
  242. data/lib/graphql/schema/possible_types.rb +0 -44
  243. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  244. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  245. data/lib/graphql/schema/traversal.rb +0 -228
  246. data/lib/graphql/schema/validation.rb +0 -313
  247. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  248. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  249. data/lib/graphql/string_type.rb +0 -2
  250. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  251. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  252. data/lib/graphql/types/relay/node_field.rb +0 -24
  253. data/lib/graphql/types/relay/nodes_field.rb +0 -43
  254. data/lib/graphql/union_type.rb +0 -115
  255. data/lib/graphql/upgrader/member.rb +0 -937
  256. data/lib/graphql/upgrader/schema.rb +0 -38
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ # This implementation forwards events to a notification handler (i.e.
6
+ # ActiveSupport::Notifications or Dry::Monitor::Notifications)
7
+ # with a `graphql` suffix.
8
+ module NotificationsTrace
9
+ include PlatformTrace
10
+ # Initialize a new NotificationsTracing instance
11
+ #
12
+ # @param engine [#instrument(key, metadata, block)] The notifications engine to use
13
+ def initialize(engine:, **rest)
14
+ @notifications_engine = engine
15
+ super
16
+ end
17
+
18
+ {
19
+ "lex" => "lex.graphql",
20
+ "parse" => "parse.graphql",
21
+ "validate" => "validate.graphql",
22
+ "analyze_multiplex" => "analyze_multiplex.graphql",
23
+ "analyze_query" => "analyze_query.graphql",
24
+ "execute_query" => "execute_query.graphql",
25
+ "execute_query_lazy" => "execute_query_lazy.graphql",
26
+ "execute_field" => "execute_field.graphql",
27
+ "execute_field_lazy" => "execute_field_lazy.graphql",
28
+ "authorized" => "authorized.graphql",
29
+ "authorized_lazy" => "authorized_lazy.graphql",
30
+ "resolve_type" => "resolve_type.graphql",
31
+ "resolve_type_lazy" => "resolve_type.graphql",
32
+ }.each do |trace_method, platform_key|
33
+ module_eval <<-RUBY, __FILE__, __LINE__
34
+ def #{trace_method}(**metadata, &blk)
35
+ @notifications_engine.instrument("#{platform_key}", metadata, &blk)
36
+ end
37
+ RUBY
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ module PlatformTrace
6
+ def initialize(trace_scalars: false, **_options)
7
+ @trace_scalars = trace_scalars
8
+ @platform_field_key_cache = Hash.new { |h, k| h[k] = platform_field_key(k) }
9
+ @platform_authorized_key_cache = Hash.new { |h, k| h[k] = platform_authorized_key(k) }
10
+ @platform_resolve_type_key_cache = Hash.new { |h, k| h[k] = platform_resolve_type_key(k) }
11
+ super
12
+ end
13
+
14
+ def platform_execute_field_lazy(*args, &block)
15
+ platform_execute_field(*args, &block)
16
+ end
17
+
18
+ def platform_authorized_lazy(key, &block)
19
+ platform_authorized(key, &block)
20
+ end
21
+
22
+ def platform_resolve_type_lazy(key, &block)
23
+ platform_resolve_type(key, &block)
24
+ end
25
+
26
+ def self.included(child_class)
27
+ # Don't gather this unless necessary
28
+ pass_data_to_execute_field = child_class.method_defined?(:platform_execute_field) &&
29
+ child_class.instance_method(:platform_execute_field).arity != 1
30
+
31
+ [:execute_field, :execute_field_lazy].each do |field_trace_method|
32
+ child_class.module_eval <<-RUBY, __FILE__, __LINE__
33
+ def #{field_trace_method}(query:, field:, ast_node:, arguments:, object:)
34
+ return_type = field.type.unwrap
35
+ trace_field = if return_type.kind.scalar? || return_type.kind.enum?
36
+ (field.trace.nil? && @trace_scalars) || field.trace
37
+ else
38
+ true
39
+ end
40
+ platform_key = if trace_field
41
+ @platform_field_key_cache[field]
42
+ else
43
+ nil
44
+ end
45
+ if platform_key && trace_field
46
+ platform_#{field_trace_method}(platform_key#{pass_data_to_execute_field ? ", { query: query, field: field, ast_node: ast_node, arguments: arguments, object: object }" : ""}) do
47
+ super
48
+ end
49
+ else
50
+ super
51
+ end
52
+ end
53
+ RUBY
54
+ end
55
+
56
+
57
+ [:authorized, :authorized_lazy].each do |auth_trace_method|
58
+ if !child_class.method_defined?(auth_trace_method)
59
+ child_class.module_eval <<-RUBY, __FILE__, __LINE__
60
+ def #{auth_trace_method}(type:, query:, object:)
61
+ platform_key = @platform_authorized_key_cache[type]
62
+ platform_#{auth_trace_method}(platform_key) do
63
+ super
64
+ end
65
+ end
66
+ RUBY
67
+ end
68
+ end
69
+
70
+ [:resolve_type, :resolve_type_lazy].each do |rt_trace_method|
71
+ if !child_class.method_defined?(rt_trace_method)
72
+ child_class.module_eval <<-RUBY, __FILE__, __LINE__
73
+ def #{rt_trace_method}(query:, type:, object:)
74
+ platform_key = @platform_resolve_type_key_cache[type]
75
+ platform_#{rt_trace_method}(platform_key) do
76
+ super
77
+ end
78
+ end
79
+ RUBY
80
+ end
81
+ end
82
+ end
83
+
84
+
85
+
86
+ private
87
+
88
+ # Get the transaction name based on the operation type and name if possible, or fall back to a user provided
89
+ # one. Useful for anonymous queries.
90
+ def transaction_name(query)
91
+ selected_op = query.selected_operation
92
+ txn_name = if selected_op
93
+ op_type = selected_op.operation_type
94
+ op_name = selected_op.name || fallback_transaction_name(query.context) || "anonymous"
95
+ "#{op_type}.#{op_name}"
96
+ else
97
+ "query.anonymous"
98
+ end
99
+ "GraphQL/#{txn_name}"
100
+ end
101
+
102
+ def fallback_transaction_name(context)
103
+ context[:tracing_fallback_transaction_name]
104
+ end
105
+ end
106
+ end
107
+ end
@@ -30,26 +30,19 @@ module GraphQL
30
30
  yield
31
31
  end
32
32
  when "execute_field", "execute_field_lazy"
33
- if data[:context]
34
- field = data[:context].field
35
- platform_key = field.metadata[:platform_key]
36
- trace_field = true # implemented with instrumenter
33
+ field = data[:field]
34
+ return_type = field.type.unwrap
35
+ trace_field = if return_type.kind.scalar? || return_type.kind.enum?
36
+ (field.trace.nil? && @trace_scalars) || field.trace
37
37
  else
38
- field = data[:field]
39
- # HERE
40
- return_type = field.type.unwrap
41
- trace_field = if return_type.kind.scalar? || return_type.kind.enum?
42
- (field.trace.nil? && @trace_scalars) || field.trace
43
- else
44
- true
45
- end
38
+ true
39
+ end
46
40
 
47
- platform_key = if trace_field
48
- context = data.fetch(:query).context
49
- cached_platform_key(context, field, :field) { platform_field_key(data[:owner], field) }
50
- else
51
- nil
52
- end
41
+ platform_key = if trace_field
42
+ context = data.fetch(:query).context
43
+ cached_platform_key(context, field, :field) { platform_field_key(field.owner, field) }
44
+ else
45
+ nil
53
46
  end
54
47
 
55
48
  if platform_key && trace_field
@@ -79,32 +72,21 @@ module GraphQL
79
72
  end
80
73
  end
81
74
 
82
- def instrument(type, field)
83
- return_type = field.type.unwrap
84
- case return_type
85
- when GraphQL::ScalarType, GraphQL::EnumType
86
- if field.trace || (field.trace.nil? && @trace_scalars)
87
- trace_field(type, field)
75
+ def self.use(schema_defn, options = {})
76
+ if options[:legacy_tracing]
77
+ tracer = self.new(**options)
78
+ schema_defn.tracer(tracer)
79
+ else
80
+ tracing_name = self.name.split("::").last
81
+ trace_name = tracing_name.sub("Tracing", "Trace")
82
+ if GraphQL::Tracing.const_defined?(trace_name, false)
83
+ trace_module = GraphQL::Tracing.const_get(trace_name)
84
+ schema_defn.trace_with(trace_module, **options)
88
85
  else
89
- field
86
+ tracer = self.new(**options)
87
+ schema_defn.tracer(tracer)
90
88
  end
91
- else
92
- trace_field(type, field)
93
- end
94
- end
95
-
96
- def trace_field(type, field)
97
- new_f = field.redefine
98
- new_f.metadata[:platform_key] = platform_field_key(type, field)
99
- new_f
100
- end
101
-
102
- def self.use(schema_defn, options = {})
103
- tracer = self.new(**options)
104
- if !schema_defn.is_a?(Class)
105
- schema_defn.instrument(:field, tracer)
106
89
  end
107
- schema_defn.tracer(tracer)
108
90
  end
109
91
 
110
92
  private
@@ -139,6 +121,9 @@ module GraphQL
139
121
  #
140
122
  # If the key isn't present, the given block is called and the result is cached for `key`.
141
123
  #
124
+ # @param ctx [GraphQL::Query::Context]
125
+ # @param key [Class, GraphQL::Field] A part of the schema
126
+ # @param trace_phase [Symbol] The stage of execution being traced (used by OpenTelementry tracing)
142
127
  # @return [String]
143
128
  def cached_platform_key(ctx, key, trace_phase)
144
129
  cache = ctx.namespace(self.class)[:platform_key_cache] ||= {}
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ module PrometheusTrace
6
+ include PlatformTrace
7
+
8
+ def initialize(client: PrometheusExporter::Client.default, keys_whitelist: ["execute_field", "execute_field_lazy"], collector_type: "graphql", **rest)
9
+ @client = client
10
+ @keys_whitelist = keys_whitelist
11
+ @collector_type = collector_type
12
+
13
+ super(**rest)
14
+ end
15
+
16
+ {
17
+ 'lex' => "graphql.lex",
18
+ 'parse' => "graphql.parse",
19
+ 'validate' => "graphql.validate",
20
+ 'analyze_query' => "graphql.analyze",
21
+ 'analyze_multiplex' => "graphql.analyze",
22
+ 'execute_multiplex' => "graphql.execute",
23
+ 'execute_query' => "graphql.execute",
24
+ 'execute_query_lazy' => "graphql.execute",
25
+ }.each do |trace_method, platform_key|
26
+ module_eval <<-RUBY, __FILE__, __LINE__
27
+ def #{trace_method}(**data, &block)
28
+ instrument_execution("#{platform_key}", "#{trace_method}", &block)
29
+ end
30
+ RUBY
31
+ end
32
+
33
+ def platform_execute_field(platform_key, &block)
34
+ instrument_execution(platform_key, "execute_field", &block)
35
+ end
36
+
37
+ def platform_execute_field_lazy(platform_key, &block)
38
+ instrument_execution(platform_key, "execute_field_lazy", &block)
39
+ end
40
+
41
+ def platform_authorized(platform_key, &block)
42
+ instrument_execution(platform_key, "authorized", &block)
43
+ end
44
+
45
+ def platform_authorized_lazy(platform_key, &block)
46
+ instrument_execution(platform_key, "authorized_lazy", &block)
47
+ end
48
+
49
+ def platform_resolve_type(platform_key, &block)
50
+ instrument_execution(platform_key, "resolve_type", &block)
51
+ end
52
+
53
+ def platform_resolve_type_lazy(platform_key, &block)
54
+ instrument_execution(platform_key, "resolve_type_lazy", &block)
55
+ end
56
+
57
+ def platform_field_key(field)
58
+ field.path
59
+ end
60
+
61
+ def platform_authorized_key(type)
62
+ "#{type.graphql_name}.authorized"
63
+ end
64
+
65
+ def platform_resolve_type_key(type)
66
+ "#{type.graphql_name}.resolve_type"
67
+ end
68
+
69
+ private
70
+
71
+ def instrument_execution(platform_key, key, &block)
72
+ if @keys_whitelist.include?(key)
73
+ start = ::Process.clock_gettime ::Process::CLOCK_MONOTONIC
74
+ result = block.call
75
+ duration = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start
76
+ @client.send_json(
77
+ type: @collector_type,
78
+ duration: duration,
79
+ platform_key: platform_key,
80
+ key: key
81
+ )
82
+ result
83
+ else
84
+ yield
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -27,9 +27,9 @@ module GraphQL
27
27
  super opts
28
28
  end
29
29
 
30
- def platform_trace(platform_key, key, data, &block)
30
+ def platform_trace(platform_key, key, _data, &block)
31
31
  return yield unless @keys_whitelist.include?(key)
32
- instrument_execution(platform_key, key, data, &block)
32
+ instrument_execution(platform_key, key, &block)
33
33
  end
34
34
 
35
35
  def platform_field_key(type, field)
@@ -46,7 +46,7 @@ module GraphQL
46
46
 
47
47
  private
48
48
 
49
- def instrument_execution(platform_key, key, data, &block)
49
+ def instrument_execution(platform_key, key, &block)
50
50
  start = ::Process.clock_gettime ::Process::CLOCK_MONOTONIC
51
51
  result = block.call
52
52
  duration = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ module ScoutTrace
6
+ include PlatformTrace
7
+
8
+ INSTRUMENT_OPTS = { scope: true }
9
+
10
+ # @param set_transaction_name [Boolean] If true, the GraphQL operation name will be used as the transaction name.
11
+ # This is not advised if you run more than one query per HTTP request, for example, with `graphql-client` or multiplexing.
12
+ # It can also be specified per-query with `context[:set_scout_transaction_name]`.
13
+ def initialize(set_transaction_name: false, **_rest)
14
+ self.class.include(ScoutApm::Tracer)
15
+ @set_transaction_name = set_transaction_name
16
+ super
17
+ end
18
+
19
+ {
20
+ "lex" => "lex.graphql",
21
+ "parse" => "parse.graphql",
22
+ "validate" => "validate.graphql",
23
+ "analyze_query" => "analyze.graphql",
24
+ "analyze_multiplex" => "analyze.graphql",
25
+ "execute_multiplex" => "execute.graphql",
26
+ "execute_query" => "execute.graphql",
27
+ "execute_query_lazy" => "execute.graphql",
28
+ }.each do |trace_method, platform_key|
29
+ module_eval <<-RUBY, __FILE__, __LINE__
30
+ def #{trace_method}(**data)
31
+ #{
32
+ if trace_method == "execute_query"
33
+ <<-RUBY
34
+ set_this_txn_name = data[:query].context[:set_scout_transaction_name]
35
+ if set_this_txn_name == true || (set_this_txn_name.nil? && @set_transaction_name)
36
+ ScoutApm::Transaction.rename(transaction_name(data[:query]))
37
+ end
38
+ RUBY
39
+ end
40
+ }
41
+
42
+ self.class.instrument("GraphQL", "#{platform_key}", INSTRUMENT_OPTS) do
43
+ super
44
+ end
45
+ end
46
+ RUBY
47
+ end
48
+
49
+ def platform_execute_field(platform_key, &block)
50
+ self.class.instrument("GraphQL", platform_key, INSTRUMENT_OPTS, &block)
51
+ end
52
+
53
+ def platform_authorized(platform_key, &block)
54
+ self.class.instrument("GraphQL", platform_key, INSTRUMENT_OPTS, &block)
55
+ end
56
+
57
+ alias :platform_resolve_type :platform_authorized
58
+
59
+ def platform_field_key(field)
60
+ field.path
61
+ end
62
+
63
+ def platform_authorized_key(type)
64
+ "#{type.graphql_name}.authorized"
65
+ end
66
+
67
+ def platform_resolve_type_key(type)
68
+ "#{type.graphql_name}.resolve_type"
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ module StatsdTrace
6
+ include PlatformTrace
7
+
8
+ # @param statsd [Object] A statsd client
9
+ def initialize(statsd:, **rest)
10
+ @statsd = statsd
11
+ super(**rest)
12
+ end
13
+
14
+ {
15
+ 'lex' => "graphql.lex",
16
+ 'parse' => "graphql.parse",
17
+ 'validate' => "graphql.validate",
18
+ 'analyze_query' => "graphql.analyze_query",
19
+ 'analyze_multiplex' => "graphql.analyze_multiplex",
20
+ 'execute_multiplex' => "graphql.execute_multiplex",
21
+ 'execute_query' => "graphql.execute_query",
22
+ 'execute_query_lazy' => "graphql.execute_query_lazy",
23
+ }.each do |trace_method, platform_key|
24
+ module_eval <<-RUBY, __FILE__, __LINE__
25
+ def #{trace_method}(**data)
26
+ @statsd.time("#{platform_key}") do
27
+ super
28
+ end
29
+ end
30
+ RUBY
31
+ end
32
+
33
+ def platform_execute_field(platform_key, &block)
34
+ @statsd.time(platform_key, &block)
35
+ end
36
+
37
+ def platform_authorized(key, &block)
38
+ @statsd.time(key, &block)
39
+ end
40
+
41
+ alias :platform_resolve_type :platform_authorized
42
+
43
+ def platform_field_key(field)
44
+ "graphql.#{field.path}"
45
+ end
46
+
47
+ def platform_authorized_key(type)
48
+ "graphql.authorized.#{type.graphql_name}"
49
+ end
50
+
51
+ def platform_resolve_type_key(type)
52
+ "graphql.resolve_type.#{type.graphql_name}"
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # Legacy tracing:
2
3
  require "graphql/tracing/active_support_notifications_tracing"
3
4
  require "graphql/tracing/platform_tracing"
4
5
  require "graphql/tracing/appoptics_tracing"
@@ -6,55 +7,150 @@ require "graphql/tracing/appsignal_tracing"
6
7
  require "graphql/tracing/data_dog_tracing"
7
8
  require "graphql/tracing/new_relic_tracing"
8
9
  require "graphql/tracing/scout_tracing"
9
- require "graphql/tracing/skylight_tracing"
10
10
  require "graphql/tracing/statsd_tracing"
11
11
  require "graphql/tracing/prometheus_tracing"
12
12
 
13
+ # New Tracing:
14
+ require "graphql/tracing/platform_trace"
15
+ require "graphql/tracing/appoptics_trace"
16
+ require "graphql/tracing/appsignal_trace"
17
+ require "graphql/tracing/data_dog_trace"
18
+ require "graphql/tracing/new_relic_trace"
19
+ require "graphql/tracing/notifications_trace"
20
+ require "graphql/tracing/scout_trace"
21
+ require "graphql/tracing/statsd_trace"
22
+ require "graphql/tracing/prometheus_trace"
13
23
  if defined?(PrometheusExporter::Server)
14
24
  require "graphql/tracing/prometheus_tracing/graphql_collector"
15
25
  end
16
26
 
17
27
  module GraphQL
18
- # Library entry point for performance metric reporting.
19
- #
20
- # @example Sending custom events
21
- # query.trace("my_custom_event", { ... }) do
22
- # # do stuff ...
23
- # end
24
- #
25
- # @example Adding a tracer to a schema
26
- # class MySchema < GraphQL::Schema
27
- # tracer MyTracer # <= responds to .trace(key, data, &block)
28
- # end
29
- #
30
- # @example Adding a tracer to a single query
31
- # MySchema.execute(query_str, context: { backtrace: true })
32
- #
33
- # Events:
34
- #
35
- # Key | Metadata
36
- # ----|---------
37
- # lex | `{ query_string: String }`
38
- # parse | `{ query_string: String }`
39
- # validate | `{ query: GraphQL::Query, validate: Boolean }`
40
- # analyze_multiplex | `{ multiplex: GraphQL::Execution::Multiplex }`
41
- # analyze_query | `{ query: GraphQL::Query }`
42
- # execute_multiplex | `{ multiplex: GraphQL::Execution::Multiplex }`
43
- # execute_query | `{ query: GraphQL::Query }`
44
- # execute_query_lazy | `{ query: GraphQL::Query?, multiplex: GraphQL::Execution::Multiplex? }`
45
- # execute_field | `{ owner: Class, field: GraphQL::Schema::Field, query: GraphQL::Query, path: Array<String, Integer>, ast_node: GraphQL::Language::Nodes::Field}`
46
- # execute_field_lazy | `{ owner: Class, field: GraphQL::Schema::Field, query: GraphQL::Query, path: Array<String, Integer>, ast_node: GraphQL::Language::Nodes::Field}`
47
- # authorized | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
48
- # authorized_lazy | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
49
- # resolve_type | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
50
- # resolve_type_lazy | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
51
- #
52
- # Note that `execute_field` and `execute_field_lazy` receive different data in different settings:
53
- #
54
- # - When using {GraphQL::Execution::Interpreter}, they receive `{field:, path:, query:}`
55
- # - Otherwise, they receive `{context: ...}`
56
- #
57
28
  module Tracing
29
+ class Trace
30
+ # @param multiplex [GraphQL::Execution::Multiplex, nil]
31
+ # @param query [GraphQL::Query, nil]
32
+ def initialize(multiplex: nil, query: nil, **_options)
33
+ @multiplex = multiplex
34
+ @query = query
35
+ end
36
+
37
+ def lex(query_string:)
38
+ yield
39
+ end
40
+
41
+ def parse(query_string:)
42
+ yield
43
+ end
44
+
45
+ def validate(query:, validate:)
46
+ yield
47
+ end
48
+
49
+ def analyze_multiplex(multiplex:)
50
+ yield
51
+ end
52
+
53
+ def analyze_query(query:)
54
+ yield
55
+ end
56
+
57
+ def execute_multiplex(multiplex:)
58
+ yield
59
+ end
60
+
61
+ def execute_query(query:)
62
+ yield
63
+ end
64
+
65
+ def execute_query_lazy(query:, multiplex:)
66
+ yield
67
+ end
68
+
69
+ def execute_field(field:, query:, ast_node:, arguments:, object:)
70
+ yield
71
+ end
72
+
73
+ def execute_field_lazy(field:, query:, ast_node:, arguments:, object:)
74
+ yield
75
+ end
76
+
77
+ def authorized(query:, type:, object:)
78
+ yield
79
+ end
80
+
81
+ def authorized_lazy(query:, type:, object:)
82
+ yield
83
+ end
84
+
85
+ def resolve_type(query:, type:, object:)
86
+ yield
87
+ end
88
+
89
+ def resolve_type_lazy(query:, type:, object:)
90
+ yield
91
+ end
92
+ end
93
+
94
+ NullTrace = Trace.new
95
+
96
+ class LegacyTrace < Trace
97
+ def lex(query_string:, &block)
98
+ (@multiplex || @query).trace("lex", { query_string: query_string }, &block)
99
+ end
100
+
101
+ def parse(query_string:, &block)
102
+ (@multiplex || @query).trace("parse", { query_string: query_string }, &block)
103
+ end
104
+
105
+ def validate(query:, validate:, &block)
106
+ query.trace("validate", { validate: validate, query: query }, &block)
107
+ end
108
+
109
+ def analyze_multiplex(multiplex:, &block)
110
+ multiplex.trace("analyze_multiplex", { multiplex: multiplex }, &block)
111
+ end
112
+
113
+ def analyze_query(query:, &block)
114
+ query.trace("analyze_query", { query: query }, &block)
115
+ end
116
+
117
+ def execute_multiplex(multiplex:, &block)
118
+ multiplex.trace("execute_multiplex", { multiplex: multiplex }, &block)
119
+ end
120
+
121
+ def execute_query(query:, &block)
122
+ query.trace("execute_query", { query: query }, &block)
123
+ end
124
+
125
+ def execute_query_lazy(query:, multiplex:, &block)
126
+ multiplex.trace("execute_query_lazy", { multiplex: multiplex, query: query }, &block)
127
+ end
128
+
129
+ def execute_field(field:, query:, ast_node:, arguments:, object:, &block)
130
+ query.trace("execute_field", { field: field, query: query, ast_node: ast_node, arguments: arguments, object: object, owner: field.owner, path: query.context[:current_path] }, &block)
131
+ end
132
+
133
+ def execute_field_lazy(field:, query:, ast_node:, arguments:, object:, &block)
134
+ query.trace("execute_field_lazy", { field: field, query: query, ast_node: ast_node, arguments: arguments, object: object, owner: field.owner, path: query.context[:current_path] }, &block)
135
+ end
136
+
137
+ def authorized(query:, type:, object:, &block)
138
+ query.trace("authorized", { context: query.context, type: type, object: object, path: query.context[:current_path] }, &block)
139
+ end
140
+
141
+ def authorized_lazy(query:, type:, object:, &block)
142
+ query.trace("authorized_lazy", { context: query.context, type: type, object: object, path: query.context[:current_path] }, &block)
143
+ end
144
+
145
+ def resolve_type(query:, type:, object:, &block)
146
+ query.trace("resolve_type", { context: query.context, type: type, object: object, path: query.context[:current_path] }, &block)
147
+ end
148
+
149
+ def resolve_type_lazy(query:, type:, object:, &block)
150
+ query.trace("resolve_type_lazy", { context: query.context, type: type, object: object, path: query.context[:current_path] }, &block)
151
+ end
152
+ end
153
+
58
154
  # Objects may include traceable to gain a `.trace(...)` method.
59
155
  # The object must have a `@tracers` ivar of type `Array<<#trace(k, d, &b)>>`.
60
156
  # @api private