graphql 2.4.5 → 2.5.21

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