graphql 2.5.14 → 2.5.15
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.
- checksums.yaml +4 -4
- data/lib/graphql/date_encoding_error.rb +1 -1
- data/lib/graphql/execution/interpreter.rb +0 -1
- data/lib/graphql/language/document_from_schema_definition.rb +2 -1
- data/lib/graphql/schema/directive.rb +8 -1
- data/lib/graphql/schema/validator/required_validator.rb +33 -2
- data/lib/graphql/schema/visibility.rb +2 -2
- data/lib/graphql/schema.rb +20 -3
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +2 -2
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -0
- data/lib/graphql/testing/mock_action_cable.rb +111 -0
- data/lib/graphql/testing.rb +1 -0
- data/lib/graphql/tracing/detailed_trace.rb +52 -4
- data/lib/graphql/tracing/perfetto_trace.rb +161 -77
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +1 -1
- metadata +3 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a45427a56efb8b050895ed510b7519a7d6093940220141c5a3853af60cf666b5
|
|
4
|
+
data.tar.gz: 5d7d99e8b9ceb05b43995cb2095bbf317b379ed659b8df4783716989f0eb2105
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 45080489ddda5c4d9f50eb3cfdc63cb21bfbe8b0f7890ca68e21d9533e8f794ce466eaab8986b1c7356e4f1a1aaf6811baf451ab41a0ee94320a520037e5f442
|
|
7
|
+
data.tar.gz: 97581b7186279e55ac3465546d99d46f03638be88662b09c6d0423ff238e69d7ff56860f8cea50b1fbb62b7c6a89c9ea344b4d69f71ffc5f36780b956f1e9228
|
|
@@ -10,7 +10,7 @@ module GraphQL
|
|
|
10
10
|
|
|
11
11
|
def initialize(value)
|
|
12
12
|
@date_value = value
|
|
13
|
-
super("Date cannot be parsed: #{value}. \nDate must be
|
|
13
|
+
super("Date cannot be parsed: #{value}. \nDate must be able to be parsed as a Ruby Date object.")
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
end
|
|
@@ -52,8 +52,9 @@ module GraphQL
|
|
|
52
52
|
|
|
53
53
|
def build_object_type_node(object_type)
|
|
54
54
|
ints = @types.interfaces(object_type)
|
|
55
|
+
|
|
55
56
|
if !ints.empty?
|
|
56
|
-
ints.sort_by
|
|
57
|
+
ints = ints.sort_by(&:graphql_name)
|
|
57
58
|
ints.map! { |iface| build_type_name_node(iface) }
|
|
58
59
|
end
|
|
59
60
|
|
|
@@ -142,7 +142,14 @@ module GraphQL
|
|
|
142
142
|
# However, we're using result coercion here to go from Ruby value
|
|
143
143
|
# to GraphQL value, so it doesn't have that feature.
|
|
144
144
|
# Keep the GraphQL-type behavior but implement it manually:
|
|
145
|
-
|
|
145
|
+
wrap_type = arg_type
|
|
146
|
+
while wrap_type.list?
|
|
147
|
+
if wrap_type.non_null?
|
|
148
|
+
wrap_type = wrap_type.of_type
|
|
149
|
+
end
|
|
150
|
+
wrap_type = wrap_type.of_type
|
|
151
|
+
coerce_value = [coerce_value]
|
|
152
|
+
end
|
|
146
153
|
end
|
|
147
154
|
arg_type.coerce_isolated_result(coerce_value)
|
|
148
155
|
rescue GraphQL::Schema::Enum::UnresolvedValueError
|
|
@@ -8,6 +8,13 @@ module GraphQL
|
|
|
8
8
|
#
|
|
9
9
|
# (This is for specifying mutually exclusive sets of arguments.)
|
|
10
10
|
#
|
|
11
|
+
# If you use {GraphQL::Schema::Visibility} to hide all the arguments in a `one_of: [..]` set,
|
|
12
|
+
# then a developer-facing {GraphQL::Error} will be raised during execution. Pass `allow_all_hidden: true` to
|
|
13
|
+
# skip validation in this case instead.
|
|
14
|
+
#
|
|
15
|
+
# This validator also implements `argument ... required: :nullable`. If an argument has `required: :nullable`
|
|
16
|
+
# but it's hidden with {GraphQL::Schema::Visibility}, then this validator doesn't run.
|
|
17
|
+
#
|
|
11
18
|
# @example Require exactly one of these arguments
|
|
12
19
|
#
|
|
13
20
|
# field :update_amount, IngredientAmount, null: false do
|
|
@@ -37,15 +44,17 @@ module GraphQL
|
|
|
37
44
|
class RequiredValidator < Validator
|
|
38
45
|
# @param one_of [Array<Symbol>] A list of arguments, exactly one of which is required for this field
|
|
39
46
|
# @param argument [Symbol] An argument that is required for this field
|
|
47
|
+
# @param allow_all_hidden [Boolean] If `true`, then this validator won't run if all the `one_of: ...` arguments have been hidden
|
|
40
48
|
# @param message [String]
|
|
41
|
-
def initialize(one_of: nil, argument: nil, message: nil, **default_options)
|
|
49
|
+
def initialize(one_of: nil, argument: nil, allow_all_hidden: nil, message: nil, **default_options)
|
|
42
50
|
@one_of = if one_of
|
|
43
51
|
one_of
|
|
44
52
|
elsif argument
|
|
45
|
-
[argument]
|
|
53
|
+
[ argument ]
|
|
46
54
|
else
|
|
47
55
|
raise ArgumentError, "`one_of:` or `argument:` must be given in `validates required: {...}`"
|
|
48
56
|
end
|
|
57
|
+
@allow_all_hidden = allow_all_hidden.nil? ? !!argument : allow_all_hidden
|
|
49
58
|
@message = message
|
|
50
59
|
super(**default_options)
|
|
51
60
|
end
|
|
@@ -54,10 +63,17 @@ module GraphQL
|
|
|
54
63
|
fully_matched_conditions = 0
|
|
55
64
|
partially_matched_conditions = 0
|
|
56
65
|
|
|
66
|
+
visible_keywords = context.types.arguments(@validated).map(&:keyword)
|
|
67
|
+
no_visible_conditions = true
|
|
68
|
+
|
|
57
69
|
if !value.nil?
|
|
58
70
|
@one_of.each do |one_of_condition|
|
|
59
71
|
case one_of_condition
|
|
60
72
|
when Symbol
|
|
73
|
+
if no_visible_conditions && visible_keywords.include?(one_of_condition)
|
|
74
|
+
no_visible_conditions = false
|
|
75
|
+
end
|
|
76
|
+
|
|
61
77
|
if value.key?(one_of_condition)
|
|
62
78
|
fully_matched_conditions += 1
|
|
63
79
|
end
|
|
@@ -66,6 +82,9 @@ module GraphQL
|
|
|
66
82
|
full_match = true
|
|
67
83
|
|
|
68
84
|
one_of_condition.each do |k|
|
|
85
|
+
if no_visible_conditions && visible_keywords.include?(k)
|
|
86
|
+
no_visible_conditions = false
|
|
87
|
+
end
|
|
69
88
|
if value.key?(k)
|
|
70
89
|
any_match = true
|
|
71
90
|
else
|
|
@@ -88,6 +107,18 @@ module GraphQL
|
|
|
88
107
|
end
|
|
89
108
|
end
|
|
90
109
|
|
|
110
|
+
if no_visible_conditions
|
|
111
|
+
if @allow_all_hidden
|
|
112
|
+
return nil
|
|
113
|
+
else
|
|
114
|
+
raise GraphQL::Error, <<~ERR
|
|
115
|
+
#{@validated.path} validates `required: ...` but all required arguments were hidden.
|
|
116
|
+
|
|
117
|
+
Update your schema definition to allow the client to see some fields or skip validation by adding `required: { ..., allow_all_hidden: true }`
|
|
118
|
+
ERR
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
91
122
|
if fully_matched_conditions == 1 && partially_matched_conditions == 0
|
|
92
123
|
nil # OK
|
|
93
124
|
else
|
|
@@ -10,9 +10,9 @@ module GraphQL
|
|
|
10
10
|
class Visibility
|
|
11
11
|
# @param schema [Class<GraphQL::Schema>]
|
|
12
12
|
# @param profiles [Hash<Symbol => Hash>] A hash of `name => context` pairs for preloading visibility profiles
|
|
13
|
-
# @param preload [Boolean] if `true`, load the default schema profile and all named profiles immediately (defaults to `true` for `Rails.env.production?`)
|
|
13
|
+
# @param preload [Boolean] if `true`, load the default schema profile and all named profiles immediately (defaults to `true` for `Rails.env.production?` and `Rails.env.staging?`)
|
|
14
14
|
# @param migration_errors [Boolean] if `true`, raise an error when `Visibility` and `Warden` return different results
|
|
15
|
-
def self.use(schema, dynamic: false, profiles: EmptyObjects::EMPTY_HASH, preload: (defined?(Rails.env) ? Rails.env.production? : nil), migration_errors: false)
|
|
15
|
+
def self.use(schema, dynamic: false, profiles: EmptyObjects::EMPTY_HASH, preload: (defined?(Rails.env) ? (Rails.env.production? || Rails.env.staging?) : nil), migration_errors: false)
|
|
16
16
|
profiles&.each { |name, ctx|
|
|
17
17
|
ctx[:visibility_profile] = name
|
|
18
18
|
ctx.freeze
|
data/lib/graphql/schema.rb
CHANGED
|
@@ -1708,7 +1708,7 @@ module GraphQL
|
|
|
1708
1708
|
# If you need to support previous, non-spec behavior which allowed selecting union fields
|
|
1709
1709
|
# but *not* selecting any fields on that union, set this to `true` to continue allowing that behavior.
|
|
1710
1710
|
#
|
|
1711
|
-
# If this is `true`, then {.
|
|
1711
|
+
# If this is `true`, then {.legacy_invalid_empty_selections_on_union_with_type} will be called with {Query} objects
|
|
1712
1712
|
# with that kind of selections. You must implement that method
|
|
1713
1713
|
# @param new_value [Boolean]
|
|
1714
1714
|
# @return [true, false, nil]
|
|
@@ -1724,6 +1724,22 @@ module GraphQL
|
|
|
1724
1724
|
end
|
|
1725
1725
|
end
|
|
1726
1726
|
|
|
1727
|
+
# This method is called during validation when a previously-allowed, but non-spec
|
|
1728
|
+
# query is encountered where a union field has no child selections on it.
|
|
1729
|
+
#
|
|
1730
|
+
# If `legacy_invalid_empty_selections_on_union_with_type` is overridden, this method will not be called.
|
|
1731
|
+
#
|
|
1732
|
+
# You should implement this method or `legacy_invalid_empty_selections_on_union_with_type`
|
|
1733
|
+
# to log the violation so that you can contact clients and notify them about changing their queries.
|
|
1734
|
+
# Then return a suitable value to tell GraphQL-Ruby how to continue.
|
|
1735
|
+
# @param query [GraphQL::Query]
|
|
1736
|
+
# @return [:return_validation_error] Let GraphQL-Ruby return the (new) normal validation error for this query
|
|
1737
|
+
# @return [String] A validation error to return for this query
|
|
1738
|
+
# @return [nil] Don't send the client an error, continue the legacy behavior (allow this query to execute)
|
|
1739
|
+
def legacy_invalid_empty_selections_on_union(query)
|
|
1740
|
+
raise "Implement `def self.legacy_invalid_empty_selections_on_union_with_type(query, type)` or `def self.legacy_invalid_empty_selections_on_union(query)` to handle this scenario"
|
|
1741
|
+
end
|
|
1742
|
+
|
|
1727
1743
|
# This method is called during validation when a previously-allowed, but non-spec
|
|
1728
1744
|
# query is encountered where a union field has no child selections on it.
|
|
1729
1745
|
#
|
|
@@ -1731,11 +1747,12 @@ module GraphQL
|
|
|
1731
1747
|
# and notify them about changing their queries. Then return a suitable value to
|
|
1732
1748
|
# tell GraphQL-Ruby how to continue.
|
|
1733
1749
|
# @param query [GraphQL::Query]
|
|
1750
|
+
# @param type1 [Module] A GraphQL type definition
|
|
1734
1751
|
# @return [:return_validation_error] Let GraphQL-Ruby return the (new) normal validation error for this query
|
|
1735
1752
|
# @return [String] A validation error to return for this query
|
|
1736
1753
|
# @return [nil] Don't send the client an error, continue the legacy behavior (allow this query to execute)
|
|
1737
|
-
def
|
|
1738
|
-
|
|
1754
|
+
def legacy_invalid_empty_selections_on_union_with_type(query, type)
|
|
1755
|
+
legacy_invalid_empty_selections_on_union(query)
|
|
1739
1756
|
end
|
|
1740
1757
|
|
|
1741
1758
|
# This setting controls how GraphQL-Ruby handles overlapping selections on scalar types when the types
|
|
@@ -49,7 +49,7 @@ module GraphQL
|
|
|
49
49
|
if !resolved_type.kind.fields?
|
|
50
50
|
case @schema.allow_legacy_invalid_empty_selections_on_union
|
|
51
51
|
when true
|
|
52
|
-
legacy_invalid_empty_selection_result = @schema.
|
|
52
|
+
legacy_invalid_empty_selection_result = @schema.legacy_invalid_empty_selections_on_union_with_type(@context.query, resolved_type)
|
|
53
53
|
case legacy_invalid_empty_selection_result
|
|
54
54
|
when :return_validation_error
|
|
55
55
|
# keep `return_validation_error = true`
|
|
@@ -61,7 +61,7 @@ module GraphQL
|
|
|
61
61
|
return_validation_error = false
|
|
62
62
|
legacy_invalid_empty_selection_result = nil
|
|
63
63
|
else
|
|
64
|
-
raise GraphQL::InvariantError, "Unexpected return value from
|
|
64
|
+
raise GraphQL::InvariantError, "Unexpected return value from legacy_invalid_empty_selections_on_union_with_type, must be `:return_validation_error`, String, or nil (got: #{legacy_invalid_empty_selection_result.inspect})"
|
|
65
65
|
end
|
|
66
66
|
when false
|
|
67
67
|
# pass -- error below
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
module Testing
|
|
4
|
+
# A stub implementation of ActionCable.
|
|
5
|
+
# Any methods to support the mock backend have `mock` in the name.
|
|
6
|
+
#
|
|
7
|
+
# @example Configuring your schema to use MockActionCable in the test environment
|
|
8
|
+
# class MySchema < GraphQL::Schema
|
|
9
|
+
# # Use MockActionCable in test:
|
|
10
|
+
# use GraphQL::Subscriptions::ActionCableSubscriptions,
|
|
11
|
+
# action_cable: Rails.env.test? ? GraphQL::Testing::MockActionCable : ActionCable
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# @example Clearing old data before each test
|
|
15
|
+
# setup do
|
|
16
|
+
# GraphQL::Testing::MockActionCable.clear_mocks
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# @example Using MockActionCable in a test case
|
|
20
|
+
# # Create a channel to use in the test, pass it to GraphQL
|
|
21
|
+
# mock_channel = GraphQL::Testing::MockActionCable.get_mock_channel
|
|
22
|
+
# ActionCableTestSchema.execute("subscription { newsFlash { text } }", context: { channel: mock_channel })
|
|
23
|
+
#
|
|
24
|
+
# # Trigger a subscription update
|
|
25
|
+
# ActionCableTestSchema.subscriptions.trigger(:news_flash, {}, {text: "After yesterday's rain, someone stopped on Rio Road to help a box turtle across five lanes of traffic"})
|
|
26
|
+
#
|
|
27
|
+
# # Check messages on the channel
|
|
28
|
+
# expected_msg = {
|
|
29
|
+
# result: {
|
|
30
|
+
# "data" => {
|
|
31
|
+
# "newsFlash" => {
|
|
32
|
+
# "text" => "After yesterday's rain, someone stopped on Rio Road to help a box turtle across five lanes of traffic"
|
|
33
|
+
# }
|
|
34
|
+
# }
|
|
35
|
+
# },
|
|
36
|
+
# more: true,
|
|
37
|
+
# }
|
|
38
|
+
# assert_equal [expected_msg], mock_channel.mock_broadcasted_messages
|
|
39
|
+
#
|
|
40
|
+
class MockActionCable
|
|
41
|
+
class MockChannel
|
|
42
|
+
def initialize
|
|
43
|
+
@mock_broadcasted_messages = []
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @return [Array<Hash>] Payloads "sent" to this channel by GraphQL-Ruby
|
|
47
|
+
attr_reader :mock_broadcasted_messages
|
|
48
|
+
|
|
49
|
+
# Called by ActionCableSubscriptions. Implements a Rails API.
|
|
50
|
+
def stream_from(stream_name, coder: nil, &block)
|
|
51
|
+
# Rails uses `coder`, we don't
|
|
52
|
+
block ||= ->(msg) { @mock_broadcasted_messages << msg }
|
|
53
|
+
MockActionCable.mock_stream_for(stream_name).add_mock_channel(self, block)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Used by mock code
|
|
58
|
+
# @api private
|
|
59
|
+
class MockStream
|
|
60
|
+
def initialize
|
|
61
|
+
@mock_channels = {}
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def add_mock_channel(channel, handler)
|
|
65
|
+
@mock_channels[channel] = handler
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def mock_broadcast(message)
|
|
69
|
+
@mock_channels.each do |channel, handler|
|
|
70
|
+
handler && handler.call(message)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
class << self
|
|
76
|
+
# Call this before each test run to make sure that MockActionCable's data is empty
|
|
77
|
+
def clear_mocks
|
|
78
|
+
@mock_streams = {}
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Implements Rails API
|
|
82
|
+
def server
|
|
83
|
+
self
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Implements Rails API
|
|
87
|
+
def broadcast(stream_name, message)
|
|
88
|
+
stream = @mock_streams[stream_name]
|
|
89
|
+
stream && stream.mock_broadcast(message)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Used by mock code
|
|
93
|
+
def mock_stream_for(stream_name)
|
|
94
|
+
@mock_streams[stream_name] ||= MockStream.new
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Use this as `context[:channel]` to simulate an ActionCable channel
|
|
98
|
+
#
|
|
99
|
+
# @return [GraphQL::Testing::MockActionCable::MockChannel]
|
|
100
|
+
def get_mock_channel
|
|
101
|
+
MockChannel.new
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# @return [Array<String>] Streams that currently have subscribers
|
|
105
|
+
def mock_stream_names
|
|
106
|
+
@mock_streams.keys
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
data/lib/graphql/testing.rb
CHANGED
|
@@ -9,8 +9,12 @@ module GraphQL
|
|
|
9
9
|
# When `MySchema.detailed_trace?(query)` returns `true`, a profiler-specific `trace_mode: ...` will be used for the query,
|
|
10
10
|
# overriding the one in `context[:trace_mode]`.
|
|
11
11
|
#
|
|
12
|
+
# By default, the detailed tracer calls `.inspect` on application objects returned from fields. You can customize
|
|
13
|
+
# this behavior by extending {DetailedTrace} and overriding {#inspect_object}. You can opt out of debug annotations
|
|
14
|
+
# entirely with `use ..., debug: false` or for a single query with `context: { detailed_trace_debug: false }`.
|
|
15
|
+
#
|
|
12
16
|
# __Redis__: The sampler stores its results in a provided Redis database. Depending on your needs,
|
|
13
|
-
# You can configure this database to
|
|
17
|
+
# You can configure this database to retain all data (persistent) or to expire data according to your rules.
|
|
14
18
|
# If you need to save traces indefinitely, you can download them from Perfetto after opening them there.
|
|
15
19
|
#
|
|
16
20
|
# @example Adding the sampler to your schema
|
|
@@ -27,10 +31,29 @@ module GraphQL
|
|
|
27
31
|
# end
|
|
28
32
|
#
|
|
29
33
|
# @see Graphql::Dashboard GraphQL::Dashboard for viewing stored results
|
|
34
|
+
#
|
|
35
|
+
# @example Customizing debug output in traces
|
|
36
|
+
# class CustomDetailedTrace < GraphQL::Tracing::DetailedTrace
|
|
37
|
+
# def inspect_object(object)
|
|
38
|
+
# if object.is_a?(SomeThing)
|
|
39
|
+
# # handle it specially ...
|
|
40
|
+
# else
|
|
41
|
+
# super
|
|
42
|
+
# end
|
|
43
|
+
# end
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# @example disabling debug annotations completely
|
|
47
|
+
# use DetailedTrace, debug: false, ...
|
|
48
|
+
#
|
|
49
|
+
# @example disabling debug annotations for one query
|
|
50
|
+
# MySchema.execute(query_str, context: { detailed_trace_debug: false })
|
|
51
|
+
#
|
|
30
52
|
class DetailedTrace
|
|
31
53
|
# @param redis [Redis] If provided, profiles will be stored in Redis for later review
|
|
32
54
|
# @param limit [Integer] A maximum number of profiles to store
|
|
33
|
-
|
|
55
|
+
# @param debug [Boolean] if `false`, it won't create `debug` annotations in Perfetto traces (reduces overhead)
|
|
56
|
+
def self.use(schema, trace_mode: :profile_sample, memory: false, debug: debug?, redis: nil, limit: nil)
|
|
34
57
|
storage = if redis
|
|
35
58
|
RedisBackend.new(redis: redis, limit: limit)
|
|
36
59
|
elsif memory
|
|
@@ -38,13 +61,15 @@ module GraphQL
|
|
|
38
61
|
else
|
|
39
62
|
raise ArgumentError, "Pass `redis: ...` to store traces in Redis for later review"
|
|
40
63
|
end
|
|
41
|
-
|
|
64
|
+
detailed_trace = self.new(storage: storage, trace_mode: trace_mode, debug: debug)
|
|
65
|
+
schema.detailed_trace = detailed_trace
|
|
42
66
|
schema.trace_with(PerfettoTrace, mode: trace_mode, save_profile: true)
|
|
43
67
|
end
|
|
44
68
|
|
|
45
|
-
def initialize(storage:, trace_mode:)
|
|
69
|
+
def initialize(storage:, trace_mode:, debug:)
|
|
46
70
|
@storage = storage
|
|
47
71
|
@trace_mode = trace_mode
|
|
72
|
+
@debug = debug
|
|
48
73
|
end
|
|
49
74
|
|
|
50
75
|
# @return [Symbol] The trace mode to use when {Schema.detailed_trace?} returns `true`
|
|
@@ -55,6 +80,11 @@ module GraphQL
|
|
|
55
80
|
@storage.save_trace(operation_name, duration_ms, begin_ms, trace_data)
|
|
56
81
|
end
|
|
57
82
|
|
|
83
|
+
# @return [Boolean]
|
|
84
|
+
def debug?
|
|
85
|
+
@debug
|
|
86
|
+
end
|
|
87
|
+
|
|
58
88
|
# @param last [Integer]
|
|
59
89
|
# @param before [Integer] Timestamp in milliseconds since epoch
|
|
60
90
|
# @return [Enumerable<StoredTrace>]
|
|
@@ -77,6 +107,24 @@ module GraphQL
|
|
|
77
107
|
@storage.delete_all_traces
|
|
78
108
|
end
|
|
79
109
|
|
|
110
|
+
def inspect_object(object)
|
|
111
|
+
self.class.inspect_object(object)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def self.inspect_object(object)
|
|
115
|
+
if defined?(ActiveRecord::Relation) && object.is_a?(ActiveRecord::Relation)
|
|
116
|
+
"#{object.class}, .to_sql=#{object.to_sql.inspect}"
|
|
117
|
+
else
|
|
118
|
+
object.inspect
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Default debug setting
|
|
123
|
+
# @return [true]
|
|
124
|
+
def self.debug?
|
|
125
|
+
true
|
|
126
|
+
end
|
|
127
|
+
|
|
80
128
|
class StoredTrace
|
|
81
129
|
def initialize(id:, operation_name:, duration_ms:, begin_ms:, trace_data:)
|
|
82
130
|
@id = id
|
|
@@ -60,11 +60,37 @@ module GraphQL
|
|
|
60
60
|
DA_FETCH_KEYS_IID = 13
|
|
61
61
|
DA_STR_VAL_NIL_IID = 14
|
|
62
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
|
+
|
|
63
75
|
# @param active_support_notifications_pattern [String, RegExp, false] A filter for `ActiveSupport::Notifications`, if it's present. Or `false` to skip subscribing.
|
|
64
76
|
def initialize(active_support_notifications_pattern: nil, save_profile: false, **_rest)
|
|
65
77
|
super
|
|
66
78
|
@active_support_notifications_pattern = active_support_notifications_pattern
|
|
67
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
|
+
|
|
68
94
|
Fiber[:graphql_flow_stack] = nil
|
|
69
95
|
@sequence_id = object_id
|
|
70
96
|
@pid = Process.pid
|
|
@@ -110,6 +136,10 @@ module GraphQL
|
|
|
110
136
|
@objects_counter_id = :objects_counter.object_id
|
|
111
137
|
@fibers_counter_id = :fibers_counter.object_id
|
|
112
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]
|
|
113
143
|
@begin_validate = nil
|
|
114
144
|
@begin_time = nil
|
|
115
145
|
@packets = []
|
|
@@ -132,16 +162,19 @@ module GraphQL
|
|
|
132
162
|
EventCategory.new(name: "ActiveSupport::Notifications", iid: ACTIVE_SUPPORT_NOTIFICATIONS_CATEGORY_IIDS.first),
|
|
133
163
|
EventCategory.new(name: "Authorized", iid: AUTHORIZED_CATEGORY_IIDS.first),
|
|
134
164
|
EventCategory.new(name: "Resolve Type", iid: RESOLVE_TYPE_CATEGORY_IIDS.first),
|
|
165
|
+
EventCategory.new(name: "Debug Inspect", iid: DEBUG_INSPECT_CATEGORY_IIDS.first),
|
|
135
166
|
],
|
|
136
167
|
debug_annotation_names: [
|
|
137
|
-
DebugAnnotationName.new(name:
|
|
138
|
-
DebugAnnotationName.new(name: "
|
|
139
|
-
DebugAnnotationName.new(name: "
|
|
140
|
-
DebugAnnotationName.new(name: "fetch keys", iid: DA_FETCH_KEYS_IID),
|
|
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)
|
|
141
171
|
],
|
|
142
172
|
debug_annotation_string_values: [
|
|
143
173
|
InternedString.new(str: "(nil)", iid: DA_STR_VAL_NIL_IID),
|
|
144
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
|
+
],
|
|
145
178
|
),
|
|
146
179
|
trusted_packet_sequence_id: @sequence_id,
|
|
147
180
|
sequence_flags: 2,
|
|
@@ -180,11 +213,9 @@ module GraphQL
|
|
|
180
213
|
@packets << trace_packet(
|
|
181
214
|
type: TrackEvent::Type::TYPE_SLICE_BEGIN,
|
|
182
215
|
track_uuid: fid,
|
|
183
|
-
name: "Multiplex"
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
]
|
|
187
|
-
)
|
|
216
|
+
name: "Multiplex"
|
|
217
|
+
) { [ payload_to_debug("query_string", multiplex.queries.map(&:sanitized_query_string).join("\n\n")) ] }
|
|
218
|
+
|
|
188
219
|
result = super
|
|
189
220
|
|
|
190
221
|
@packets << trace_packet(
|
|
@@ -209,7 +240,7 @@ module GraphQL
|
|
|
209
240
|
track_uuid: fid,
|
|
210
241
|
name: query.context.current_path.join("."),
|
|
211
242
|
category_iids: FIELD_EXECUTE_CATEGORY_IIDS,
|
|
212
|
-
extra_counter_track_uuids:
|
|
243
|
+
extra_counter_track_uuids: @counts_objects,
|
|
213
244
|
extra_counter_values: [count_allocations],
|
|
214
245
|
)
|
|
215
246
|
@packets << packet
|
|
@@ -218,19 +249,23 @@ module GraphQL
|
|
|
218
249
|
end
|
|
219
250
|
|
|
220
251
|
def end_execute_field(field, object, arguments, query, app_result)
|
|
252
|
+
end_ts = ts
|
|
221
253
|
start_field = fiber_flow_stack.pop
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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
|
|
229
263
|
|
|
230
264
|
@packets << trace_packet(
|
|
265
|
+
timestamp: end_ts,
|
|
231
266
|
type: TrackEvent::Type::TYPE_SLICE_END,
|
|
232
267
|
track_uuid: fid,
|
|
233
|
-
extra_counter_track_uuids:
|
|
268
|
+
extra_counter_track_uuids: @counts_objects_and_fields,
|
|
234
269
|
extra_counter_values: [count_allocations, count_fields],
|
|
235
270
|
)
|
|
236
271
|
super
|
|
@@ -240,22 +275,24 @@ module GraphQL
|
|
|
240
275
|
@packets << trace_packet(
|
|
241
276
|
type: TrackEvent::Type::TYPE_SLICE_BEGIN,
|
|
242
277
|
track_uuid: fid,
|
|
243
|
-
extra_counter_track_uuids:
|
|
278
|
+
extra_counter_track_uuids: @counts_objects,
|
|
244
279
|
extra_counter_values: [count_allocations],
|
|
245
|
-
name: "Analysis"
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
280
|
+
name: "Analysis") {
|
|
281
|
+
[
|
|
282
|
+
payload_to_debug("analyzers_count", analyzers.size),
|
|
283
|
+
payload_to_debug("analyzers", analyzers),
|
|
284
|
+
]
|
|
285
|
+
}
|
|
251
286
|
super
|
|
252
287
|
end
|
|
253
288
|
|
|
254
289
|
def end_analyze_multiplex(m, analyzers)
|
|
290
|
+
end_ts = ts
|
|
255
291
|
@packets << trace_packet(
|
|
292
|
+
timestamp: end_ts,
|
|
256
293
|
type: TrackEvent::Type::TYPE_SLICE_END,
|
|
257
294
|
track_uuid: fid,
|
|
258
|
-
extra_counter_track_uuids:
|
|
295
|
+
extra_counter_track_uuids: @counts_objects,
|
|
259
296
|
extra_counter_values: [count_allocations],
|
|
260
297
|
)
|
|
261
298
|
super
|
|
@@ -265,50 +302,57 @@ module GraphQL
|
|
|
265
302
|
@packets << trace_packet(
|
|
266
303
|
type: TrackEvent::Type::TYPE_SLICE_BEGIN,
|
|
267
304
|
track_uuid: fid,
|
|
268
|
-
extra_counter_track_uuids:
|
|
305
|
+
extra_counter_track_uuids: @counts_objects,
|
|
269
306
|
extra_counter_values: [count_allocations],
|
|
270
307
|
name: "Parse"
|
|
271
308
|
)
|
|
272
309
|
result = super
|
|
310
|
+
end_ts = ts
|
|
273
311
|
@packets << trace_packet(
|
|
312
|
+
timestamp: end_ts,
|
|
274
313
|
type: TrackEvent::Type::TYPE_SLICE_END,
|
|
275
314
|
track_uuid: fid,
|
|
276
|
-
extra_counter_track_uuids:
|
|
315
|
+
extra_counter_track_uuids: @counts_objects,
|
|
277
316
|
extra_counter_values: [count_allocations],
|
|
278
317
|
)
|
|
279
318
|
result
|
|
280
319
|
end
|
|
281
320
|
|
|
282
321
|
def begin_validate(query, validate)
|
|
283
|
-
@
|
|
322
|
+
@begin_validate = trace_packet(
|
|
284
323
|
type: TrackEvent::Type::TYPE_SLICE_BEGIN,
|
|
285
324
|
track_uuid: fid,
|
|
286
|
-
extra_counter_track_uuids:
|
|
325
|
+
extra_counter_track_uuids: @counts_objects,
|
|
287
326
|
extra_counter_values: [count_allocations],
|
|
288
|
-
name: "Validate"
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
327
|
+
name: "Validate") {
|
|
328
|
+
[payload_to_debug("validate?", validate)]
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
@packets << @begin_validate
|
|
293
332
|
super
|
|
294
333
|
end
|
|
295
334
|
|
|
296
335
|
def end_validate(query, validate, validation_errors)
|
|
336
|
+
end_ts = ts
|
|
297
337
|
@packets << trace_packet(
|
|
338
|
+
timestamp: end_ts,
|
|
298
339
|
type: TrackEvent::Type::TYPE_SLICE_END,
|
|
299
340
|
track_uuid: fid,
|
|
300
|
-
extra_counter_track_uuids:
|
|
341
|
+
extra_counter_track_uuids: @counts_objects,
|
|
301
342
|
extra_counter_values: [count_allocations],
|
|
302
343
|
)
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
|
312
356
|
super
|
|
313
357
|
end
|
|
314
358
|
|
|
@@ -318,7 +362,7 @@ module GraphQL
|
|
|
318
362
|
track_uuid: fid,
|
|
319
363
|
name: "Create Execution Fiber",
|
|
320
364
|
category_iids: DATALOADER_CATEGORY_IIDS,
|
|
321
|
-
extra_counter_track_uuids:
|
|
365
|
+
extra_counter_track_uuids: @counts_fibers_and_objects,
|
|
322
366
|
extra_counter_values: [count_fibers(1), count_allocations]
|
|
323
367
|
)
|
|
324
368
|
@packets << track_descriptor_packet(@did, fid, "Exec Fiber ##{fid}")
|
|
@@ -331,7 +375,7 @@ module GraphQL
|
|
|
331
375
|
track_uuid: fid,
|
|
332
376
|
name: "Create Source Fiber",
|
|
333
377
|
category_iids: DATALOADER_CATEGORY_IIDS,
|
|
334
|
-
extra_counter_track_uuids:
|
|
378
|
+
extra_counter_track_uuids: @counts_fibers_and_objects,
|
|
335
379
|
extra_counter_values: [count_fibers(1), count_allocations]
|
|
336
380
|
)
|
|
337
381
|
@packets << track_descriptor_packet(@did, fid, "Source Fiber ##{fid}")
|
|
@@ -385,7 +429,7 @@ module GraphQL
|
|
|
385
429
|
track_uuid: fid,
|
|
386
430
|
name: "Fiber Exit",
|
|
387
431
|
category_iids: DATALOADER_CATEGORY_IIDS,
|
|
388
|
-
extra_counter_track_uuids:
|
|
432
|
+
extra_counter_track_uuids: @counts_fibers,
|
|
389
433
|
extra_counter_values: [count_fibers(-1)],
|
|
390
434
|
)
|
|
391
435
|
super
|
|
@@ -415,31 +459,34 @@ module GraphQL
|
|
|
415
459
|
fds = @flow_ids[source]
|
|
416
460
|
fds_copy = fds.dup
|
|
417
461
|
fds.clear
|
|
462
|
+
|
|
418
463
|
packet = trace_packet(
|
|
419
464
|
type: TrackEvent::Type::TYPE_SLICE_BEGIN,
|
|
420
465
|
track_uuid: fid,
|
|
421
466
|
name_iid: @source_name_iids[source.class],
|
|
422
467
|
category_iids: DATALOADER_CATEGORY_IIDS,
|
|
423
468
|
flow_ids: fds_copy,
|
|
424
|
-
extra_counter_track_uuids:
|
|
425
|
-
extra_counter_values: [count_allocations]
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
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
|
+
}
|
|
433
478
|
@packets << packet
|
|
434
479
|
fiber_flow_stack << packet
|
|
435
480
|
super
|
|
436
481
|
end
|
|
437
482
|
|
|
438
483
|
def end_dataloader_source(source)
|
|
484
|
+
end_ts = ts
|
|
439
485
|
@packets << trace_packet(
|
|
486
|
+
timestamp: end_ts,
|
|
440
487
|
type: TrackEvent::Type::TYPE_SLICE_END,
|
|
441
488
|
track_uuid: fid,
|
|
442
|
-
extra_counter_track_uuids:
|
|
489
|
+
extra_counter_track_uuids: @counts_objects,
|
|
443
490
|
extra_counter_values: [count_allocations],
|
|
444
491
|
)
|
|
445
492
|
fiber_flow_stack.pop
|
|
@@ -451,7 +498,7 @@ module GraphQL
|
|
|
451
498
|
type: TrackEvent::Type::TYPE_SLICE_BEGIN,
|
|
452
499
|
track_uuid: fid,
|
|
453
500
|
category_iids: AUTHORIZED_CATEGORY_IIDS,
|
|
454
|
-
extra_counter_track_uuids:
|
|
501
|
+
extra_counter_track_uuids: @counts_objects,
|
|
455
502
|
extra_counter_values: [count_allocations],
|
|
456
503
|
name_iid: @auth_name_iids[type],
|
|
457
504
|
)
|
|
@@ -461,14 +508,18 @@ module GraphQL
|
|
|
461
508
|
end
|
|
462
509
|
|
|
463
510
|
def end_authorized(type, obj, ctx, is_authorized)
|
|
511
|
+
end_ts = ts
|
|
464
512
|
@packets << trace_packet(
|
|
513
|
+
timestamp: end_ts,
|
|
465
514
|
type: TrackEvent::Type::TYPE_SLICE_END,
|
|
466
515
|
track_uuid: fid,
|
|
467
|
-
extra_counter_track_uuids:
|
|
516
|
+
extra_counter_track_uuids: @counts_objects,
|
|
468
517
|
extra_counter_values: [count_allocations],
|
|
469
518
|
)
|
|
470
519
|
beg_auth = fiber_flow_stack.pop
|
|
471
|
-
|
|
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
|
|
472
523
|
super
|
|
473
524
|
end
|
|
474
525
|
|
|
@@ -477,7 +528,7 @@ module GraphQL
|
|
|
477
528
|
type: TrackEvent::Type::TYPE_SLICE_BEGIN,
|
|
478
529
|
track_uuid: fid,
|
|
479
530
|
category_iids: RESOLVE_TYPE_CATEGORY_IIDS,
|
|
480
|
-
extra_counter_track_uuids:
|
|
531
|
+
extra_counter_track_uuids: @counts_objects,
|
|
481
532
|
extra_counter_values: [count_allocations],
|
|
482
533
|
name_iid: @resolve_type_name_iids[type],
|
|
483
534
|
)
|
|
@@ -487,14 +538,18 @@ module GraphQL
|
|
|
487
538
|
end
|
|
488
539
|
|
|
489
540
|
def end_resolve_type(type, value, context, resolved_type)
|
|
541
|
+
end_ts = ts
|
|
490
542
|
@packets << trace_packet(
|
|
543
|
+
timestamp: end_ts,
|
|
491
544
|
type: TrackEvent::Type::TYPE_SLICE_END,
|
|
492
545
|
track_uuid: fid,
|
|
493
|
-
extra_counter_track_uuids:
|
|
546
|
+
extra_counter_track_uuids: @counts_objects,
|
|
494
547
|
extra_counter_values: [count_allocations],
|
|
495
548
|
)
|
|
496
549
|
rt_begin = fiber_flow_stack.pop
|
|
497
|
-
|
|
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
|
|
498
553
|
super
|
|
499
554
|
end
|
|
500
555
|
|
|
@@ -546,7 +601,6 @@ module GraphQL
|
|
|
546
601
|
def payload_to_debug(k, v, iid: nil, intern_value: false)
|
|
547
602
|
if iid.nil?
|
|
548
603
|
iid = @interned_da_name_ids[k]
|
|
549
|
-
k = nil
|
|
550
604
|
end
|
|
551
605
|
case v
|
|
552
606
|
when String
|
|
@@ -578,15 +632,41 @@ module GraphQL
|
|
|
578
632
|
when Symbol
|
|
579
633
|
debug_annotation(iid, :string_value, v.inspect)
|
|
580
634
|
when Array
|
|
581
|
-
debug_annotation(iid, :array_values, v.map { |v2| payload_to_debug(
|
|
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)
|
|
582
636
|
when Hash
|
|
583
637
|
debug_annotation(iid, :dict_entries, v.map { |k2, v2| payload_to_debug(k2, v2, intern_value: intern_value) }.compact)
|
|
584
638
|
else
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
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
|
|
589
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
|
+
)
|
|
590
670
|
if intern_value
|
|
591
671
|
str_iid = @interned_da_string_values[debug_str]
|
|
592
672
|
debug_annotation(iid, :string_value_iid, str_iid)
|
|
@@ -622,10 +702,14 @@ module GraphQL
|
|
|
622
702
|
Fiber[:graphql_flow_stack] ||= []
|
|
623
703
|
end
|
|
624
704
|
|
|
625
|
-
def trace_packet(event_attrs)
|
|
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)
|
|
626
710
|
TracePacket.new(
|
|
627
|
-
timestamp:
|
|
628
|
-
track_event:
|
|
711
|
+
timestamp: timestamp,
|
|
712
|
+
track_event: track_event,
|
|
629
713
|
trusted_packet_sequence_id: @sequence_id,
|
|
630
714
|
sequence_flags: 2,
|
|
631
715
|
interned_data: new_interned_data
|
|
@@ -690,9 +774,9 @@ module GraphQL
|
|
|
690
774
|
|
|
691
775
|
def subscribe_to_active_support_notifications(pattern)
|
|
692
776
|
@as_subscriber = ActiveSupport::Notifications.monotonic_subscribe(pattern) do |name, start, finish, id, payload|
|
|
693
|
-
metadata = payload.map { |k, v| payload_to_debug(k, v, intern_value: true) }
|
|
694
|
-
metadata
|
|
695
|
-
te = if metadata.empty?
|
|
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?
|
|
696
780
|
TrackEvent.new(
|
|
697
781
|
type: TrackEvent::Type::TYPE_SLICE_BEGIN,
|
|
698
782
|
track_uuid: fid,
|
|
@@ -721,7 +805,7 @@ module GraphQL
|
|
|
721
805
|
type: TrackEvent::Type::TYPE_SLICE_END,
|
|
722
806
|
track_uuid: fid,
|
|
723
807
|
name: name,
|
|
724
|
-
extra_counter_track_uuids:
|
|
808
|
+
extra_counter_track_uuids: @counts_objects,
|
|
725
809
|
extra_counter_values: [count_allocations]
|
|
726
810
|
),
|
|
727
811
|
trusted_packet_sequence_id: @sequence_id,
|
data/lib/graphql/version.rb
CHANGED
data/lib/graphql.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: graphql
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.5.
|
|
4
|
+
version: 2.5.15
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Mosolgo
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2025-
|
|
10
|
+
date: 2025-12-09 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: base64
|
|
@@ -23,20 +23,6 @@ dependencies:
|
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '0'
|
|
26
|
-
- !ruby/object:Gem::Dependency
|
|
27
|
-
name: fiber-storage
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - ">="
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '0'
|
|
33
|
-
type: :runtime
|
|
34
|
-
prerelease: false
|
|
35
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - ">="
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '0'
|
|
40
26
|
- !ruby/object:Gem::Dependency
|
|
41
27
|
name: logger
|
|
42
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -729,6 +715,7 @@ files:
|
|
|
729
715
|
- lib/graphql/subscriptions/serialize.rb
|
|
730
716
|
- lib/graphql/testing.rb
|
|
731
717
|
- lib/graphql/testing/helpers.rb
|
|
718
|
+
- lib/graphql/testing/mock_action_cable.rb
|
|
732
719
|
- lib/graphql/tracing.rb
|
|
733
720
|
- lib/graphql/tracing/active_support_notifications_trace.rb
|
|
734
721
|
- lib/graphql/tracing/active_support_notifications_tracing.rb
|