graphql 2.2.17 → 2.5.16

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.
Files changed (240) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/generators/graphql/install_generator.rb +46 -0
  4. data/lib/generators/graphql/orm_mutations_base.rb +1 -1
  5. data/lib/generators/graphql/templates/base_resolver.erb +2 -0
  6. data/lib/generators/graphql/templates/schema.erb +3 -0
  7. data/lib/generators/graphql/type_generator.rb +1 -1
  8. data/lib/graphql/analysis/analyzer.rb +90 -0
  9. data/lib/graphql/analysis/field_usage.rb +82 -0
  10. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  11. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  12. data/lib/graphql/analysis/query_complexity.rb +263 -0
  13. data/lib/graphql/analysis/{ast/query_depth.rb → query_depth.rb} +23 -25
  14. data/lib/graphql/analysis/visitor.rb +280 -0
  15. data/lib/graphql/analysis.rb +95 -1
  16. data/lib/graphql/autoload.rb +38 -0
  17. data/lib/graphql/backtrace/table.rb +118 -55
  18. data/lib/graphql/backtrace.rb +1 -19
  19. data/lib/graphql/current.rb +57 -0
  20. data/lib/graphql/dashboard/detailed_traces.rb +47 -0
  21. data/lib/graphql/dashboard/installable.rb +22 -0
  22. data/lib/graphql/dashboard/limiters.rb +93 -0
  23. data/lib/graphql/dashboard/operation_store.rb +199 -0
  24. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
  25. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
  26. data/lib/graphql/dashboard/statics/charts.min.css +1 -0
  27. data/lib/graphql/dashboard/statics/dashboard.css +30 -0
  28. data/lib/graphql/dashboard/statics/dashboard.js +143 -0
  29. data/lib/graphql/dashboard/statics/header-icon.png +0 -0
  30. data/lib/graphql/dashboard/statics/icon.png +0 -0
  31. data/lib/graphql/dashboard/subscriptions.rb +96 -0
  32. data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
  33. data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
  34. data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
  35. data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
  36. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
  37. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
  38. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
  39. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
  40. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
  41. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
  42. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
  43. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
  44. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
  45. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
  46. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
  47. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
  48. data/lib/graphql/dashboard.rb +158 -0
  49. data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
  50. data/lib/graphql/dataloader/active_record_source.rb +47 -0
  51. data/lib/graphql/dataloader/async_dataloader.rb +46 -19
  52. data/lib/graphql/dataloader/null_dataloader.rb +51 -10
  53. data/lib/graphql/dataloader/source.rb +20 -9
  54. data/lib/graphql/dataloader.rb +153 -45
  55. data/lib/graphql/date_encoding_error.rb +1 -1
  56. data/lib/graphql/dig.rb +2 -1
  57. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  58. data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
  59. data/lib/graphql/execution/interpreter/resolve.rb +23 -25
  60. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +63 -5
  61. data/lib/graphql/execution/interpreter/runtime.rb +321 -222
  62. data/lib/graphql/execution/interpreter.rb +23 -30
  63. data/lib/graphql/execution/lookahead.rb +18 -11
  64. data/lib/graphql/execution/multiplex.rb +6 -5
  65. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  66. data/lib/graphql/introspection/directive_type.rb +1 -1
  67. data/lib/graphql/introspection/entry_points.rb +2 -2
  68. data/lib/graphql/introspection/field_type.rb +1 -1
  69. data/lib/graphql/introspection/schema_type.rb +6 -11
  70. data/lib/graphql/introspection/type_type.rb +5 -5
  71. data/lib/graphql/invalid_name_error.rb +1 -1
  72. data/lib/graphql/invalid_null_error.rb +20 -17
  73. data/lib/graphql/language/cache.rb +13 -0
  74. data/lib/graphql/language/comment.rb +18 -0
  75. data/lib/graphql/language/document_from_schema_definition.rb +64 -35
  76. data/lib/graphql/language/lexer.rb +72 -42
  77. data/lib/graphql/language/nodes.rb +93 -52
  78. data/lib/graphql/language/parser.rb +168 -61
  79. data/lib/graphql/language/printer.rb +31 -15
  80. data/lib/graphql/language/sanitized_printer.rb +1 -1
  81. data/lib/graphql/language.rb +61 -1
  82. data/lib/graphql/pagination/connection.rb +1 -1
  83. data/lib/graphql/query/context/scoped_context.rb +1 -1
  84. data/lib/graphql/query/context.rb +46 -47
  85. data/lib/graphql/query/null_context.rb +3 -5
  86. data/lib/graphql/query/partial.rb +179 -0
  87. data/lib/graphql/query/validation_pipeline.rb +2 -2
  88. data/lib/graphql/query/variable_validation_error.rb +1 -1
  89. data/lib/graphql/query.rb +123 -69
  90. data/lib/graphql/railtie.rb +7 -0
  91. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  92. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  93. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  94. data/lib/graphql/rubocop.rb +2 -0
  95. data/lib/graphql/schema/addition.rb +26 -13
  96. data/lib/graphql/schema/always_visible.rb +7 -2
  97. data/lib/graphql/schema/argument.rb +57 -8
  98. data/lib/graphql/schema/build_from_definition.rb +116 -49
  99. data/lib/graphql/schema/directive/flagged.rb +4 -2
  100. data/lib/graphql/schema/directive.rb +54 -2
  101. data/lib/graphql/schema/enum.rb +107 -24
  102. data/lib/graphql/schema/enum_value.rb +10 -2
  103. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  104. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  105. data/lib/graphql/schema/field.rb +134 -45
  106. data/lib/graphql/schema/field_extension.rb +1 -1
  107. data/lib/graphql/schema/has_single_input_argument.rb +6 -2
  108. data/lib/graphql/schema/input_object.rb +122 -64
  109. data/lib/graphql/schema/interface.rb +23 -5
  110. data/lib/graphql/schema/introspection_system.rb +6 -17
  111. data/lib/graphql/schema/late_bound_type.rb +4 -0
  112. data/lib/graphql/schema/list.rb +3 -3
  113. data/lib/graphql/schema/loader.rb +3 -2
  114. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
  115. data/lib/graphql/schema/member/has_arguments.rb +44 -58
  116. data/lib/graphql/schema/member/has_dataloader.rb +62 -0
  117. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
  118. data/lib/graphql/schema/member/has_directives.rb +4 -4
  119. data/lib/graphql/schema/member/has_fields.rb +26 -6
  120. data/lib/graphql/schema/member/has_interfaces.rb +6 -6
  121. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  122. data/lib/graphql/schema/member/has_validators.rb +1 -1
  123. data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
  124. data/lib/graphql/schema/member/type_system_helpers.rb +17 -4
  125. data/lib/graphql/schema/member.rb +1 -0
  126. data/lib/graphql/schema/mutation.rb +7 -0
  127. data/lib/graphql/schema/object.rb +25 -8
  128. data/lib/graphql/schema/printer.rb +1 -0
  129. data/lib/graphql/schema/ractor_shareable.rb +79 -0
  130. data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
  131. data/lib/graphql/schema/resolver.rb +29 -23
  132. data/lib/graphql/schema/scalar.rb +1 -6
  133. data/lib/graphql/schema/subscription.rb +52 -6
  134. data/lib/graphql/schema/timeout.rb +19 -2
  135. data/lib/graphql/schema/type_expression.rb +2 -2
  136. data/lib/graphql/schema/union.rb +1 -1
  137. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  138. data/lib/graphql/schema/validator/required_validator.rb +92 -11
  139. data/lib/graphql/schema/validator.rb +3 -1
  140. data/lib/graphql/schema/visibility/migration.rb +188 -0
  141. data/lib/graphql/schema/visibility/profile.rb +445 -0
  142. data/lib/graphql/schema/visibility/visit.rb +190 -0
  143. data/lib/graphql/schema/visibility.rb +311 -0
  144. data/lib/graphql/schema/warden.rb +190 -20
  145. data/lib/graphql/schema.rb +695 -167
  146. data/lib/graphql/static_validation/all_rules.rb +2 -2
  147. data/lib/graphql/static_validation/base_visitor.rb +6 -5
  148. data/lib/graphql/static_validation/literal_validator.rb +4 -4
  149. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  150. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  151. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  152. data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
  153. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
  154. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
  155. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
  156. data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
  157. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
  158. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  159. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
  160. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  161. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  162. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  163. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
  164. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  165. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
  166. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
  167. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
  168. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
  169. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  170. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  171. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
  172. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
  173. data/lib/graphql/static_validation/validation_context.rb +18 -2
  174. data/lib/graphql/static_validation/validator.rb +6 -1
  175. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +5 -3
  176. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  177. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
  178. data/lib/graphql/subscriptions/event.rb +13 -2
  179. data/lib/graphql/subscriptions/serialize.rb +1 -1
  180. data/lib/graphql/subscriptions.rb +7 -5
  181. data/lib/graphql/testing/helpers.rb +48 -16
  182. data/lib/graphql/testing/mock_action_cable.rb +111 -0
  183. data/lib/graphql/testing.rb +1 -0
  184. data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
  185. data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
  186. data/lib/graphql/tracing/appoptics_trace.rb +5 -1
  187. data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
  188. data/lib/graphql/tracing/appsignal_trace.rb +32 -59
  189. data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
  190. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  191. data/lib/graphql/tracing/data_dog_trace.rb +46 -162
  192. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  193. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
  194. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
  195. data/lib/graphql/tracing/detailed_trace.rb +141 -0
  196. data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
  197. data/lib/graphql/tracing/legacy_trace.rb +4 -61
  198. data/lib/graphql/tracing/monitor_trace.rb +283 -0
  199. data/lib/graphql/tracing/new_relic_trace.rb +47 -54
  200. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  201. data/lib/graphql/tracing/notifications_trace.rb +183 -37
  202. data/lib/graphql/tracing/notifications_tracing.rb +2 -0
  203. data/lib/graphql/tracing/null_trace.rb +9 -0
  204. data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
  205. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
  206. data/lib/graphql/tracing/perfetto_trace.rb +818 -0
  207. data/lib/graphql/tracing/platform_tracing.rb +1 -1
  208. data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
  209. data/lib/graphql/tracing/prometheus_trace.rb +73 -73
  210. data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
  211. data/lib/graphql/tracing/scout_trace.rb +32 -58
  212. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  213. data/lib/graphql/tracing/sentry_trace.rb +64 -98
  214. data/lib/graphql/tracing/statsd_trace.rb +33 -45
  215. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  216. data/lib/graphql/tracing/trace.rb +111 -1
  217. data/lib/graphql/tracing.rb +31 -30
  218. data/lib/graphql/type_kinds.rb +2 -1
  219. data/lib/graphql/types/relay/connection_behaviors.rb +12 -2
  220. data/lib/graphql/types/relay/edge_behaviors.rb +11 -1
  221. data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
  222. data/lib/graphql/types.rb +18 -11
  223. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  224. data/lib/graphql/version.rb +1 -1
  225. data/lib/graphql.rb +64 -54
  226. metadata +197 -22
  227. data/lib/graphql/analysis/ast/analyzer.rb +0 -91
  228. data/lib/graphql/analysis/ast/field_usage.rb +0 -82
  229. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  230. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  231. data/lib/graphql/analysis/ast/query_complexity.rb +0 -182
  232. data/lib/graphql/analysis/ast/visitor.rb +0 -276
  233. data/lib/graphql/analysis/ast.rb +0 -94
  234. data/lib/graphql/backtrace/inspect_result.rb +0 -50
  235. data/lib/graphql/backtrace/trace.rb +0 -93
  236. data/lib/graphql/backtrace/tracer.rb +0 -80
  237. data/lib/graphql/language/token.rb +0 -34
  238. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  239. data/lib/graphql/schema/null_mask.rb +0 -11
  240. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
@@ -0,0 +1,818 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Tracing
4
+ # This produces a trace file for inspecting in the [Perfetto Trace Viewer](https://ui.perfetto.dev).
5
+ #
6
+ # To get the file, call {#write} on the trace.
7
+ #
8
+ # Use "trace modes" to configure this to run on command or on a sample of traffic.
9
+ #
10
+ # @example Writing trace output
11
+ #
12
+ # result = MySchema.execute(...)
13
+ # result.query.trace.write(file: "tmp/trace.dump")
14
+ #
15
+ # @example Running this instrumenter when `trace: true` is present in the request
16
+ #
17
+ # class MySchema < GraphQL::Schema
18
+ # # Only run this tracer when `context[:trace_mode]` is `:trace`
19
+ # trace_with GraphQL::Tracing::Perfetto, mode: :trace
20
+ # end
21
+ #
22
+ # # In graphql_controller.rb:
23
+ #
24
+ # context[:trace_mode] = params[:trace] ? :trace : nil
25
+ # result = MySchema.execute(query_str, context: context, variables: variables, ...)
26
+ # if context[:trace_mode] == :trace
27
+ # result.trace.write(file: ...)
28
+ # end
29
+ #
30
+ module PerfettoTrace
31
+ # TODOs:
32
+ # - Make debug annotations visible on both parts when dataloader is involved
33
+
34
+ PROTOBUF_AVAILABLE = begin
35
+ require "google/protobuf"
36
+ true
37
+ rescue LoadError
38
+ false
39
+ end
40
+
41
+ if PROTOBUF_AVAILABLE
42
+ require "graphql/tracing/perfetto_trace/trace_pb"
43
+ end
44
+
45
+ def self.included(_trace_class)
46
+ if !PROTOBUF_AVAILABLE
47
+ raise "#{self} can't be used because the `google-protobuf` gem wasn't available. Add it to your project, then try again."
48
+ end
49
+ end
50
+
51
+ DATALOADER_CATEGORY_IIDS = [5]
52
+ FIELD_EXECUTE_CATEGORY_IIDS = [6]
53
+ ACTIVE_SUPPORT_NOTIFICATIONS_CATEGORY_IIDS = [7]
54
+ AUTHORIZED_CATEGORY_IIDS = [8]
55
+ RESOLVE_TYPE_CATEGORY_IIDS = [9]
56
+
57
+ DA_OBJECT_IID = 10
58
+ DA_RESULT_IID = 11
59
+ DA_ARGUMENTS_IID = 12
60
+ DA_FETCH_KEYS_IID = 13
61
+ DA_STR_VAL_NIL_IID = 14
62
+
63
+ REVERSE_DEBUG_NAME_LOOKUP = {
64
+ DA_OBJECT_IID => "object",
65
+ DA_RESULT_IID => "result",
66
+ DA_ARGUMENTS_IID => "arguments",
67
+ DA_FETCH_KEYS_IID => "fetch keys",
68
+ }
69
+
70
+ DEBUG_INSPECT_CATEGORY_IIDS = [15]
71
+ DA_DEBUG_INSPECT_CLASS_IID = 16
72
+ DEBUG_INSPECT_EVENT_NAME_IID = 17
73
+ DA_DEBUG_INSPECT_FOR_IID = 18
74
+
75
+ # @param active_support_notifications_pattern [String, RegExp, false] A filter for `ActiveSupport::Notifications`, if it's present. Or `false` to skip subscribing.
76
+ def initialize(active_support_notifications_pattern: nil, save_profile: false, **_rest)
77
+ super
78
+ @active_support_notifications_pattern = active_support_notifications_pattern
79
+ @save_profile = save_profile
80
+
81
+ query = if @multiplex
82
+ @multiplex.queries.first
83
+ else
84
+ @query # could still be nil in some initializations
85
+ end
86
+
87
+ @detailed_trace = query&.schema&.detailed_trace || DetailedTrace
88
+ @create_debug_annotations = if (ctx = query&.context).nil? || (ctx_debug = ctx[:detailed_trace_debug]).nil?
89
+ @detailed_trace.debug?
90
+ else
91
+ ctx_debug
92
+ end
93
+
94
+ Fiber[:graphql_flow_stack] = nil
95
+ @sequence_id = object_id
96
+ @pid = Process.pid
97
+ @flow_ids = Hash.new { |h, source_inst| h[source_inst] = [] }.compare_by_identity
98
+ @new_interned_event_names = {}
99
+ @interned_event_name_iids = Hash.new { |h, k|
100
+ new_id = 100 + h.size
101
+ @new_interned_event_names[k] = new_id
102
+ h[k] = new_id
103
+ }
104
+
105
+ @source_name_iids = Hash.new do |h, source_class|
106
+ h[source_class] = @interned_event_name_iids[source_class.name]
107
+ end.compare_by_identity
108
+
109
+ @auth_name_iids = Hash.new do |h, graphql_type|
110
+ h[graphql_type] = @interned_event_name_iids["Authorize: #{graphql_type.graphql_name}"]
111
+ end.compare_by_identity
112
+
113
+ @resolve_type_name_iids = Hash.new do |h, graphql_type|
114
+ h[graphql_type] = @interned_event_name_iids["Resolve Type: #{graphql_type.graphql_name}"]
115
+ end.compare_by_identity
116
+
117
+ @new_interned_da_names = {}
118
+ @interned_da_name_ids = Hash.new { |h, k|
119
+ next_id = 100 + h.size
120
+ @new_interned_da_names[k] = next_id
121
+ h[k] = next_id
122
+ }
123
+
124
+ @new_interned_da_string_values = {}
125
+ @interned_da_string_values = Hash.new do |h, k|
126
+ new_id = 100 + h.size
127
+ @new_interned_da_string_values[k] = new_id
128
+ h[k] = new_id
129
+ end
130
+
131
+ @class_name_iids = Hash.new do |h, k|
132
+ h[k] = @interned_da_string_values[k.name]
133
+ end.compare_by_identity
134
+
135
+ @starting_objects = GC.stat(:total_allocated_objects)
136
+ @objects_counter_id = :objects_counter.object_id
137
+ @fibers_counter_id = :fibers_counter.object_id
138
+ @fields_counter_id = :fields_counter.object_id
139
+ @counts_objects = [@objects_counter_id]
140
+ @counts_objects_and_fields = [@objects_counter_id, @fields_counter_id]
141
+ @counts_fibers = [@fibers_counter_id]
142
+ @counts_fibers_and_objects = [@fibers_counter_id, @objects_counter_id]
143
+ @begin_validate = nil
144
+ @begin_time = nil
145
+ @packets = []
146
+ @packets << TracePacket.new(
147
+ track_descriptor: TrackDescriptor.new(
148
+ uuid: tid,
149
+ name: "Main Thread",
150
+ child_ordering: TrackDescriptor::ChildTracksOrdering::CHRONOLOGICAL,
151
+ ),
152
+ first_packet_on_sequence: true,
153
+ previous_packet_dropped: true,
154
+ trusted_packet_sequence_id: @sequence_id,
155
+ sequence_flags: 3,
156
+ )
157
+ @packets << TracePacket.new(
158
+ interned_data: InternedData.new(
159
+ event_categories: [
160
+ EventCategory.new(name: "Dataloader", iid: DATALOADER_CATEGORY_IIDS.first),
161
+ EventCategory.new(name: "Field Execution", iid: FIELD_EXECUTE_CATEGORY_IIDS.first),
162
+ EventCategory.new(name: "ActiveSupport::Notifications", iid: ACTIVE_SUPPORT_NOTIFICATIONS_CATEGORY_IIDS.first),
163
+ EventCategory.new(name: "Authorized", iid: AUTHORIZED_CATEGORY_IIDS.first),
164
+ EventCategory.new(name: "Resolve Type", iid: RESOLVE_TYPE_CATEGORY_IIDS.first),
165
+ EventCategory.new(name: "Debug Inspect", iid: DEBUG_INSPECT_CATEGORY_IIDS.first),
166
+ ],
167
+ debug_annotation_names: [
168
+ *REVERSE_DEBUG_NAME_LOOKUP.map { |(iid, name)| DebugAnnotationName.new(name: name, iid: iid) },
169
+ DebugAnnotationName.new(name: "inspect instance of", iid: DA_DEBUG_INSPECT_CLASS_IID),
170
+ DebugAnnotationName.new(name: "inspecting for", iid: DA_DEBUG_INSPECT_FOR_IID)
171
+ ],
172
+ debug_annotation_string_values: [
173
+ InternedString.new(str: "(nil)", iid: DA_STR_VAL_NIL_IID),
174
+ ],
175
+ event_names: [
176
+ EventName.new(name: "#{(@detailed_trace.is_a?(Class) ? @detailed_trace : @detailed_trace.class).name}#inspect_object", iid: DEBUG_INSPECT_EVENT_NAME_IID)
177
+ ],
178
+ ),
179
+ trusted_packet_sequence_id: @sequence_id,
180
+ sequence_flags: 2,
181
+ )
182
+ @main_fiber_id = fid
183
+ @packets << track_descriptor_packet(tid, fid, "Main Fiber")
184
+ @packets << track_descriptor_packet(tid, @objects_counter_id, "Allocated Objects", counter: {})
185
+ @packets << trace_packet(
186
+ type: TrackEvent::Type::TYPE_COUNTER,
187
+ track_uuid: @objects_counter_id,
188
+ counter_value: count_allocations,
189
+ )
190
+ @packets << track_descriptor_packet(tid, @fibers_counter_id, "Active Fibers", counter: {})
191
+ @fibers_count = 0
192
+ @packets << trace_packet(
193
+ type: TrackEvent::Type::TYPE_COUNTER,
194
+ track_uuid: @fibers_counter_id,
195
+ counter_value: count_fibers(0),
196
+ )
197
+
198
+ @packets << track_descriptor_packet(tid, @fields_counter_id, "Resolved Fields", counter: {})
199
+ @fields_count = -1
200
+ @packets << trace_packet(
201
+ type: TrackEvent::Type::TYPE_COUNTER,
202
+ track_uuid: @fields_counter_id,
203
+ counter_value: count_fields,
204
+ )
205
+ end
206
+
207
+ def execute_multiplex(multiplex:)
208
+ if defined?(ActiveSupport::Notifications) && @active_support_notifications_pattern != false
209
+ subscribe_to_active_support_notifications(@active_support_notifications_pattern)
210
+ end
211
+ @operation_name = multiplex.queries.map { |q| q.selected_operation_name || "anonymous" }.join(",")
212
+ @begin_time = Time.now
213
+ @packets << trace_packet(
214
+ type: TrackEvent::Type::TYPE_SLICE_BEGIN,
215
+ track_uuid: fid,
216
+ name: "Multiplex"
217
+ ) { [ payload_to_debug("query_string", multiplex.queries.map(&:sanitized_query_string).join("\n\n")) ] }
218
+
219
+ result = super
220
+
221
+ @packets << trace_packet(
222
+ type: TrackEvent::Type::TYPE_SLICE_END,
223
+ track_uuid: fid,
224
+ )
225
+
226
+ result
227
+ ensure
228
+ unsubscribe_from_active_support_notifications
229
+ if @save_profile
230
+ begin_ts = (@begin_time.to_f * 1000).round
231
+ end_ts = (Time.now.to_f * 1000).round
232
+ duration_ms = end_ts - begin_ts
233
+ multiplex.schema.detailed_trace.save_trace(@operation_name, duration_ms, begin_ts, Trace.encode(Trace.new(packet: @packets)))
234
+ end
235
+ end
236
+
237
+ def begin_execute_field(field, object, arguments, query)
238
+ packet = trace_packet(
239
+ type: TrackEvent::Type::TYPE_SLICE_BEGIN,
240
+ track_uuid: fid,
241
+ name: query.context.current_path.join("."),
242
+ category_iids: FIELD_EXECUTE_CATEGORY_IIDS,
243
+ extra_counter_track_uuids: @counts_objects,
244
+ extra_counter_values: [count_allocations],
245
+ )
246
+ @packets << packet
247
+ fiber_flow_stack << packet
248
+ super
249
+ end
250
+
251
+ def end_execute_field(field, object, arguments, query, app_result)
252
+ end_ts = ts
253
+ start_field = fiber_flow_stack.pop
254
+ if @create_debug_annotations
255
+ start_field.track_event = dup_with(start_field.track_event,{
256
+ debug_annotations: [
257
+ payload_to_debug(nil, object.object, iid: DA_OBJECT_IID, intern_value: true),
258
+ payload_to_debug(nil, arguments, iid: DA_ARGUMENTS_IID),
259
+ payload_to_debug(nil, app_result, iid: DA_RESULT_IID, intern_value: true)
260
+ ]
261
+ })
262
+ end
263
+
264
+ @packets << trace_packet(
265
+ timestamp: end_ts,
266
+ type: TrackEvent::Type::TYPE_SLICE_END,
267
+ track_uuid: fid,
268
+ extra_counter_track_uuids: @counts_objects_and_fields,
269
+ extra_counter_values: [count_allocations, count_fields],
270
+ )
271
+ super
272
+ end
273
+
274
+ def begin_analyze_multiplex(m, analyzers)
275
+ @packets << trace_packet(
276
+ type: TrackEvent::Type::TYPE_SLICE_BEGIN,
277
+ track_uuid: fid,
278
+ extra_counter_track_uuids: @counts_objects,
279
+ extra_counter_values: [count_allocations],
280
+ name: "Analysis") {
281
+ [
282
+ payload_to_debug("analyzers_count", analyzers.size),
283
+ payload_to_debug("analyzers", analyzers),
284
+ ]
285
+ }
286
+ super
287
+ end
288
+
289
+ def end_analyze_multiplex(m, analyzers)
290
+ end_ts = ts
291
+ @packets << trace_packet(
292
+ timestamp: end_ts,
293
+ type: TrackEvent::Type::TYPE_SLICE_END,
294
+ track_uuid: fid,
295
+ extra_counter_track_uuids: @counts_objects,
296
+ extra_counter_values: [count_allocations],
297
+ )
298
+ super
299
+ end
300
+
301
+ def parse(query_string:)
302
+ @packets << trace_packet(
303
+ type: TrackEvent::Type::TYPE_SLICE_BEGIN,
304
+ track_uuid: fid,
305
+ extra_counter_track_uuids: @counts_objects,
306
+ extra_counter_values: [count_allocations],
307
+ name: "Parse"
308
+ )
309
+ result = super
310
+ end_ts = ts
311
+ @packets << trace_packet(
312
+ timestamp: end_ts,
313
+ type: TrackEvent::Type::TYPE_SLICE_END,
314
+ track_uuid: fid,
315
+ extra_counter_track_uuids: @counts_objects,
316
+ extra_counter_values: [count_allocations],
317
+ )
318
+ result
319
+ end
320
+
321
+ def begin_validate(query, validate)
322
+ @begin_validate = trace_packet(
323
+ type: TrackEvent::Type::TYPE_SLICE_BEGIN,
324
+ track_uuid: fid,
325
+ extra_counter_track_uuids: @counts_objects,
326
+ extra_counter_values: [count_allocations],
327
+ name: "Validate") {
328
+ [payload_to_debug("validate?", validate)]
329
+ }
330
+
331
+ @packets << @begin_validate
332
+ super
333
+ end
334
+
335
+ def end_validate(query, validate, validation_errors)
336
+ end_ts = ts
337
+ @packets << trace_packet(
338
+ timestamp: end_ts,
339
+ type: TrackEvent::Type::TYPE_SLICE_END,
340
+ track_uuid: fid,
341
+ extra_counter_track_uuids: @counts_objects,
342
+ extra_counter_values: [count_allocations],
343
+ )
344
+
345
+ if @create_debug_annotations
346
+ new_bv_track_event = dup_with(
347
+ @begin_validate.track_event, {
348
+ debug_annotations: [
349
+ @begin_validate.track_event.debug_annotations.first,
350
+ payload_to_debug("valid?", validation_errors.empty?)
351
+ ]
352
+ }
353
+ )
354
+ @begin_validate.track_event = new_bv_track_event
355
+ end
356
+ super
357
+ end
358
+
359
+ def dataloader_spawn_execution_fiber(jobs)
360
+ @packets << trace_packet(
361
+ type: TrackEvent::Type::TYPE_INSTANT,
362
+ track_uuid: fid,
363
+ name: "Create Execution Fiber",
364
+ category_iids: DATALOADER_CATEGORY_IIDS,
365
+ extra_counter_track_uuids: @counts_fibers_and_objects,
366
+ extra_counter_values: [count_fibers(1), count_allocations]
367
+ )
368
+ @packets << track_descriptor_packet(@did, fid, "Exec Fiber ##{fid}")
369
+ super
370
+ end
371
+
372
+ def dataloader_spawn_source_fiber(pending_sources)
373
+ @packets << trace_packet(
374
+ type: TrackEvent::Type::TYPE_INSTANT,
375
+ track_uuid: fid,
376
+ name: "Create Source Fiber",
377
+ category_iids: DATALOADER_CATEGORY_IIDS,
378
+ extra_counter_track_uuids: @counts_fibers_and_objects,
379
+ extra_counter_values: [count_fibers(1), count_allocations]
380
+ )
381
+ @packets << track_descriptor_packet(@did, fid, "Source Fiber ##{fid}")
382
+ super
383
+ end
384
+
385
+ def dataloader_fiber_yield(source)
386
+ ls = fiber_flow_stack.last
387
+ if (flow_id = ls.track_event.flow_ids.first)
388
+ # got it
389
+ else
390
+ flow_id = ls.track_event.name.object_id
391
+ ls.track_event = dup_with(ls.track_event, {flow_ids: [flow_id] }, delete_counters: true)
392
+ end
393
+ @flow_ids[source] << flow_id
394
+ @packets << trace_packet(
395
+ type: TrackEvent::Type::TYPE_SLICE_END,
396
+ track_uuid: fid,
397
+ )
398
+ @packets << trace_packet(
399
+ type: TrackEvent::Type::TYPE_INSTANT,
400
+ track_uuid: fid,
401
+ name: "Fiber Yield",
402
+ category_iids: DATALOADER_CATEGORY_IIDS,
403
+ )
404
+ super
405
+ end
406
+
407
+ def dataloader_fiber_resume(source)
408
+ @packets << trace_packet(
409
+ type: TrackEvent::Type::TYPE_INSTANT,
410
+ track_uuid: fid,
411
+ name: "Fiber Resume",
412
+ category_iids: DATALOADER_CATEGORY_IIDS,
413
+ )
414
+
415
+ ls = fiber_flow_stack.pop
416
+ @packets << packet = TracePacket.new(
417
+ timestamp: ts,
418
+ track_event: dup_with(ls.track_event, { type: TrackEvent::Type::TYPE_SLICE_BEGIN }),
419
+ trusted_packet_sequence_id: @sequence_id,
420
+ )
421
+ fiber_flow_stack << packet
422
+
423
+ super
424
+ end
425
+
426
+ def dataloader_fiber_exit
427
+ @packets << trace_packet(
428
+ type: TrackEvent::Type::TYPE_INSTANT,
429
+ track_uuid: fid,
430
+ name: "Fiber Exit",
431
+ category_iids: DATALOADER_CATEGORY_IIDS,
432
+ extra_counter_track_uuids: @counts_fibers,
433
+ extra_counter_values: [count_fibers(-1)],
434
+ )
435
+ super
436
+ end
437
+
438
+ def begin_dataloader(dl)
439
+ @packets << trace_packet(
440
+ type: TrackEvent::Type::TYPE_COUNTER,
441
+ track_uuid: @fibers_counter_id,
442
+ counter_value: count_fibers(1),
443
+ )
444
+ @did = fid
445
+ @packets << track_descriptor_packet(@main_fiber_id, @did, "Dataloader Fiber ##{@did}")
446
+ super
447
+ end
448
+
449
+ def end_dataloader(dl)
450
+ @packets << trace_packet(
451
+ type: TrackEvent::Type::TYPE_COUNTER,
452
+ track_uuid: @fibers_counter_id,
453
+ counter_value: count_fibers(-1),
454
+ )
455
+ super
456
+ end
457
+
458
+ def begin_dataloader_source(source)
459
+ fds = @flow_ids[source]
460
+ fds_copy = fds.dup
461
+ fds.clear
462
+
463
+ packet = trace_packet(
464
+ type: TrackEvent::Type::TYPE_SLICE_BEGIN,
465
+ track_uuid: fid,
466
+ name_iid: @source_name_iids[source.class],
467
+ category_iids: DATALOADER_CATEGORY_IIDS,
468
+ flow_ids: fds_copy,
469
+ extra_counter_track_uuids: @counts_objects,
470
+ extra_counter_values: [count_allocations]) {
471
+ [
472
+ payload_to_debug(nil, source.pending.values, iid: DA_FETCH_KEYS_IID, intern_value: true),
473
+ *(source.instance_variables - [:@pending, :@fetching, :@results, :@dataloader]).map { |iv|
474
+ payload_to_debug(iv.to_s, source.instance_variable_get(iv), intern_value: true)
475
+ }
476
+ ]
477
+ }
478
+ @packets << packet
479
+ fiber_flow_stack << packet
480
+ super
481
+ end
482
+
483
+ def end_dataloader_source(source)
484
+ end_ts = ts
485
+ @packets << trace_packet(
486
+ timestamp: end_ts,
487
+ type: TrackEvent::Type::TYPE_SLICE_END,
488
+ track_uuid: fid,
489
+ extra_counter_track_uuids: @counts_objects,
490
+ extra_counter_values: [count_allocations],
491
+ )
492
+ fiber_flow_stack.pop
493
+ super
494
+ end
495
+
496
+ def begin_authorized(type, obj, ctx)
497
+ packet = trace_packet(
498
+ type: TrackEvent::Type::TYPE_SLICE_BEGIN,
499
+ track_uuid: fid,
500
+ category_iids: AUTHORIZED_CATEGORY_IIDS,
501
+ extra_counter_track_uuids: @counts_objects,
502
+ extra_counter_values: [count_allocations],
503
+ name_iid: @auth_name_iids[type],
504
+ )
505
+ @packets << packet
506
+ fiber_flow_stack << packet
507
+ super
508
+ end
509
+
510
+ def end_authorized(type, obj, ctx, is_authorized)
511
+ end_ts = ts
512
+ @packets << trace_packet(
513
+ timestamp: end_ts,
514
+ type: TrackEvent::Type::TYPE_SLICE_END,
515
+ track_uuid: fid,
516
+ extra_counter_track_uuids: @counts_objects,
517
+ extra_counter_values: [count_allocations],
518
+ )
519
+ beg_auth = fiber_flow_stack.pop
520
+ if @create_debug_annotations
521
+ beg_auth.track_event = dup_with(beg_auth.track_event, { debug_annotations: [payload_to_debug("authorized?", is_authorized)] })
522
+ end
523
+ super
524
+ end
525
+
526
+ def begin_resolve_type(type, value, context)
527
+ packet = trace_packet(
528
+ type: TrackEvent::Type::TYPE_SLICE_BEGIN,
529
+ track_uuid: fid,
530
+ category_iids: RESOLVE_TYPE_CATEGORY_IIDS,
531
+ extra_counter_track_uuids: @counts_objects,
532
+ extra_counter_values: [count_allocations],
533
+ name_iid: @resolve_type_name_iids[type],
534
+ )
535
+ @packets << packet
536
+ fiber_flow_stack << packet
537
+ super
538
+ end
539
+
540
+ def end_resolve_type(type, value, context, resolved_type)
541
+ end_ts = ts
542
+ @packets << trace_packet(
543
+ timestamp: end_ts,
544
+ type: TrackEvent::Type::TYPE_SLICE_END,
545
+ track_uuid: fid,
546
+ extra_counter_track_uuids: @counts_objects,
547
+ extra_counter_values: [count_allocations],
548
+ )
549
+ rt_begin = fiber_flow_stack.pop
550
+ if @create_debug_annotations
551
+ rt_begin.track_event = dup_with(rt_begin.track_event, { debug_annotations: [payload_to_debug("resolved_type", resolved_type, intern_value: true)] })
552
+ end
553
+ super
554
+ end
555
+
556
+ # Dump protobuf output in the specified file.
557
+ # @param file [String] path to a file in a directory that already exists
558
+ # @param debug_json [Boolean] True to print JSON instead of binary
559
+ # @return [nil, String, Hash] If `file` was given, `nil`. If `file` was `nil`, a Hash if `debug_json: true`, else binary data.
560
+ def write(file:, debug_json: false)
561
+ trace = Trace.new(
562
+ packet: @packets,
563
+ )
564
+ data = if debug_json
565
+ small_json = Trace.encode_json(trace)
566
+ JSON.pretty_generate(JSON.parse(small_json))
567
+ else
568
+ Trace.encode(trace)
569
+ end
570
+
571
+ if file
572
+ File.write(file, data, mode: 'wb')
573
+ nil
574
+ else
575
+ data
576
+ end
577
+ end
578
+
579
+ private
580
+
581
+ def ts
582
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
583
+ end
584
+
585
+ def tid
586
+ Thread.current.object_id
587
+ end
588
+
589
+ def fid
590
+ Fiber.current.object_id
591
+ end
592
+
593
+ def debug_annotation(iid, value_key, value)
594
+ if iid
595
+ DebugAnnotation.new(name_iid: iid, value_key => value)
596
+ else
597
+ DebugAnnotation.new(value_key => value)
598
+ end
599
+ end
600
+
601
+ def payload_to_debug(k, v, iid: nil, intern_value: false)
602
+ if iid.nil?
603
+ iid = @interned_da_name_ids[k]
604
+ end
605
+ case v
606
+ when String
607
+ if intern_value
608
+ v = @interned_da_string_values[v]
609
+ debug_annotation(iid, :string_value_iid, v)
610
+ else
611
+ debug_annotation(iid, :string_value, v)
612
+ end
613
+ when Float
614
+ debug_annotation(iid, :double_value, v)
615
+ when Integer
616
+ debug_annotation(iid, :int_value, v)
617
+ when true, false
618
+ debug_annotation(iid, :bool_value, v)
619
+ when nil
620
+ if iid
621
+ DebugAnnotation.new(name_iid: iid, string_value_iid: DA_STR_VAL_NIL_IID)
622
+ else
623
+ DebugAnnotation.new(name: k, string_value_iid: DA_STR_VAL_NIL_IID)
624
+ end
625
+ when Module
626
+ if intern_value
627
+ val_iid = @class_name_iids[v]
628
+ debug_annotation(iid, :string_value_iid, val_iid)
629
+ else
630
+ debug_annotation(iid, :string_value, v.name)
631
+ end
632
+ when Symbol
633
+ debug_annotation(iid, :string_value, v.inspect)
634
+ when Array
635
+ debug_annotation(iid, :array_values, v.each_with_index.map { |v2, idx| payload_to_debug((k ? "#{k}.#{idx}" : String(idx)), v2, intern_value: intern_value) }.compact)
636
+ when Hash
637
+ debug_annotation(iid, :dict_entries, v.map { |k2, v2| payload_to_debug(k2, v2, intern_value: intern_value) }.compact)
638
+ else
639
+ class_name_iid = @interned_da_string_values[v.class.name]
640
+ da = [
641
+ debug_annotation(DA_DEBUG_INSPECT_CLASS_IID, :string_value_iid, class_name_iid),
642
+ ]
643
+ if k
644
+ k_str_value_iid = @interned_da_string_values[k]
645
+ da << debug_annotation(DA_DEBUG_INSPECT_FOR_IID, :string_value_iid, k_str_value_iid)
646
+ elsif iid
647
+ k = REVERSE_DEBUG_NAME_LOOKUP[iid] || @interned_da_name_ids.key(iid)
648
+ if k.nil?
649
+ da << debug_annotation(DA_DEBUG_INSPECT_FOR_IID, :string_value_iid, DA_STR_VAL_NIL_IID)
650
+ else
651
+ k_str_value_iid = @interned_da_string_values[k]
652
+ da << debug_annotation(DA_DEBUG_INSPECT_FOR_IID, :string_value_iid, k_str_value_iid)
653
+ end
654
+ end
655
+
656
+ @packets << trace_packet(
657
+ type: TrackEvent::Type::TYPE_SLICE_BEGIN,
658
+ track_uuid: fid,
659
+ name_iid: DEBUG_INSPECT_EVENT_NAME_IID,
660
+ category_iids: DEBUG_INSPECT_CATEGORY_IIDS,
661
+ extra_counter_track_uuids: @counts_objects,
662
+ extra_counter_values: [count_allocations],
663
+ debug_annotations: da,
664
+ )
665
+ debug_str = @detailed_trace.inspect_object(v)
666
+ @packets << trace_packet(
667
+ type: TrackEvent::Type::TYPE_SLICE_END,
668
+ track_uuid: fid,
669
+ )
670
+ if intern_value
671
+ str_iid = @interned_da_string_values[debug_str]
672
+ debug_annotation(iid, :string_value_iid, str_iid)
673
+ else
674
+ debug_annotation(iid, :string_value, debug_str)
675
+ end
676
+ end
677
+ end
678
+
679
+ def count_allocations
680
+ GC.stat(:total_allocated_objects) - @starting_objects
681
+ end
682
+
683
+ def count_fibers(diff)
684
+ @fibers_count += diff
685
+ end
686
+
687
+ def count_fields
688
+ @fields_count += 1
689
+ end
690
+
691
+ def dup_with(message, attrs, delete_counters: false)
692
+ new_attrs = message.to_h
693
+ if delete_counters
694
+ new_attrs.delete(:extra_counter_track_uuids)
695
+ new_attrs.delete(:extra_counter_values)
696
+ end
697
+ new_attrs.merge!(attrs)
698
+ message.class.new(**new_attrs)
699
+ end
700
+
701
+ def fiber_flow_stack
702
+ Fiber[:graphql_flow_stack] ||= []
703
+ end
704
+
705
+ def trace_packet(timestamp: ts, **event_attrs)
706
+ if @create_debug_annotations && block_given?
707
+ event_attrs[:debug_annotations] = yield
708
+ end
709
+ track_event = TrackEvent.new(event_attrs)
710
+ TracePacket.new(
711
+ timestamp: timestamp,
712
+ track_event: track_event,
713
+ trusted_packet_sequence_id: @sequence_id,
714
+ sequence_flags: 2,
715
+ interned_data: new_interned_data
716
+ )
717
+ end
718
+
719
+ def new_interned_data
720
+ if !@new_interned_da_names.empty?
721
+ da_names = @new_interned_da_names.map { |(name, iid)| DebugAnnotationName.new(iid: iid, name: name) }
722
+ @new_interned_da_names.clear
723
+ end
724
+
725
+ if !@new_interned_event_names.empty?
726
+ ev_names = @new_interned_event_names.map { |(name, iid)| EventName.new(iid: iid, name: name) }
727
+ @new_interned_event_names.clear
728
+ end
729
+
730
+ if !@new_interned_da_string_values.empty?
731
+ str_vals = @new_interned_da_string_values.map { |name, iid| InternedString.new(iid: iid, str: name.b) }
732
+ @new_interned_da_string_values.clear
733
+ end
734
+
735
+ if ev_names || da_names || str_vals
736
+ InternedData.new(
737
+ event_names: ev_names,
738
+ debug_annotation_names: da_names,
739
+ debug_annotation_string_values: str_vals,
740
+ )
741
+ else
742
+ nil
743
+ end
744
+ end
745
+
746
+ def track_descriptor_packet(parent_uuid, uuid, name, counter: nil)
747
+ td = if counter
748
+ TrackDescriptor.new(
749
+ parent_uuid: parent_uuid,
750
+ uuid: uuid,
751
+ name: name,
752
+ counter: counter
753
+ )
754
+ else
755
+ TrackDescriptor.new(
756
+ parent_uuid: parent_uuid,
757
+ uuid: uuid,
758
+ name: name,
759
+ child_ordering: TrackDescriptor::ChildTracksOrdering::CHRONOLOGICAL,
760
+ )
761
+ end
762
+ TracePacket.new(
763
+ track_descriptor: td,
764
+ trusted_packet_sequence_id: @sequence_id,
765
+ sequence_flags: 2,
766
+ )
767
+ end
768
+
769
+ def unsubscribe_from_active_support_notifications
770
+ if defined?(@as_subscriber)
771
+ ActiveSupport::Notifications.unsubscribe(@as_subscriber)
772
+ end
773
+ end
774
+
775
+ def subscribe_to_active_support_notifications(pattern)
776
+ @as_subscriber = ActiveSupport::Notifications.monotonic_subscribe(pattern) do |name, start, finish, id, payload|
777
+ metadata = @create_debug_annotations ? payload.map { |k, v| payload_to_debug(String(k), v, intern_value: true) } : nil
778
+ metadata&.compact!
779
+ te = if metadata.nil? || metadata.empty?
780
+ TrackEvent.new(
781
+ type: TrackEvent::Type::TYPE_SLICE_BEGIN,
782
+ track_uuid: fid,
783
+ category_iids: ACTIVE_SUPPORT_NOTIFICATIONS_CATEGORY_IIDS,
784
+ name: name,
785
+ )
786
+ else
787
+ TrackEvent.new(
788
+ type: TrackEvent::Type::TYPE_SLICE_BEGIN,
789
+ track_uuid: fid,
790
+ name: name,
791
+ category_iids: ACTIVE_SUPPORT_NOTIFICATIONS_CATEGORY_IIDS,
792
+ debug_annotations: metadata,
793
+ )
794
+ end
795
+ @packets << TracePacket.new(
796
+ timestamp: (start * 1_000_000_000).to_i,
797
+ track_event: te,
798
+ trusted_packet_sequence_id: @sequence_id,
799
+ sequence_flags: 2,
800
+ interned_data: new_interned_data
801
+ )
802
+ @packets << TracePacket.new(
803
+ timestamp: (finish * 1_000_000_000).to_i,
804
+ track_event: TrackEvent.new(
805
+ type: TrackEvent::Type::TYPE_SLICE_END,
806
+ track_uuid: fid,
807
+ name: name,
808
+ extra_counter_track_uuids: @counts_objects,
809
+ extra_counter_values: [count_allocations]
810
+ ),
811
+ trusted_packet_sequence_id: @sequence_id,
812
+ sequence_flags: 2,
813
+ )
814
+ end
815
+ end
816
+ end
817
+ end
818
+ end