graphql 2.0.32 → 2.5.22
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/generators/graphql/detailed_trace_generator.rb +77 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +49 -0
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +8 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/create_graphql_detailed_traces.erb +10 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +5 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis/analyzer.rb +90 -0
- data/lib/graphql/analysis/field_usage.rb +82 -0
- data/lib/graphql/analysis/max_query_complexity.rb +20 -0
- data/lib/graphql/analysis/max_query_depth.rb +20 -0
- data/lib/graphql/analysis/query_complexity.rb +263 -0
- data/lib/graphql/analysis/query_depth.rb +58 -0
- data/lib/graphql/analysis/visitor.rb +280 -0
- data/lib/graphql/analysis.rb +95 -1
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +118 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/current.rb +57 -0
- data/lib/graphql/dashboard/application_controller.rb +41 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/landings_controller.rb +9 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +30 -0
- data/lib/graphql/dashboard/statics/dashboard.js +143 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/statics_controller.rb +31 -0
- data/lib/graphql/dashboard/subscriptions.rb +97 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +24 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
- data/lib/graphql/dashboard.rb +96 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
- data/lib/graphql/dataloader/active_record_source.rb +47 -0
- data/lib/graphql/dataloader/async_dataloader.rb +112 -0
- data/lib/graphql/dataloader/null_dataloader.rb +55 -10
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +35 -12
- data/lib/graphql/dataloader.rb +224 -149
- data/lib/graphql/date_encoding_error.rb +1 -1
- data/lib/graphql/dig.rb +2 -1
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/resolve.rb +23 -25
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +228 -0
- data/lib/graphql/execution/interpreter/runtime.rb +363 -434
- data/lib/graphql/execution/interpreter.rb +91 -164
- data/lib/graphql/execution/lookahead.rb +105 -31
- data/lib/graphql/execution/multiplex.rb +7 -6
- data/lib/graphql/execution/next/field_resolve_step.rb +711 -0
- data/lib/graphql/execution/next/load_argument_step.rb +60 -0
- data/lib/graphql/execution/next/prepare_object_step.rb +129 -0
- data/lib/graphql/execution/next/runner.rb +389 -0
- data/lib/graphql/execution/next/selections_step.rb +37 -0
- data/lib/graphql/execution/next.rb +70 -0
- data/lib/graphql/execution.rb +1 -0
- data/lib/graphql/execution_error.rb +13 -10
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +7 -3
- data/lib/graphql/introspection/dynamic_fields.rb +5 -1
- data/lib/graphql/introspection/entry_points.rb +20 -6
- data/lib/graphql/introspection/enum_value_type.rb +5 -5
- data/lib/graphql/introspection/field_type.rb +13 -5
- data/lib/graphql/introspection/input_value_type.rb +21 -13
- data/lib/graphql/introspection/schema_type.rb +8 -11
- data/lib/graphql/introspection/type_type.rb +64 -28
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +26 -17
- data/lib/graphql/language/block_string.rb +34 -18
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +90 -61
- data/lib/graphql/language/lexer.rb +319 -193
- data/lib/graphql/language/nodes.rb +136 -77
- data/lib/graphql/language/parser.rb +807 -1985
- data/lib/graphql/language/printer.rb +324 -151
- data/lib/graphql/language/sanitized_printer.rb +21 -23
- data/lib/graphql/language/static_visitor.rb +171 -0
- data/lib/graphql/language/visitor.rb +23 -83
- data/lib/graphql/language.rb +71 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/pagination/connection.rb +30 -1
- data/lib/graphql/pagination/connections.rb +32 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +82 -144
- data/lib/graphql/query/null_context.rb +15 -18
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query/validation_pipeline.rb +4 -4
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +126 -81
- data/lib/graphql/railtie.rb +16 -6
- data/lib/graphql/rake_task.rb +3 -12
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +2 -0
- data/lib/graphql/schema/addition.rb +26 -13
- data/lib/graphql/schema/always_visible.rb +7 -2
- data/lib/graphql/schema/argument.rb +75 -9
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +123 -60
- data/lib/graphql/schema/directive/flagged.rb +4 -2
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive.rb +54 -2
- data/lib/graphql/schema/enum.rb +110 -27
- data/lib/graphql/schema/enum_value.rb +10 -2
- data/lib/graphql/schema/field/connection_extension.rb +15 -49
- data/lib/graphql/schema/field/scope_extension.rb +23 -7
- data/lib/graphql/schema/field.rb +245 -118
- data/lib/graphql/schema/field_extension.rb +34 -1
- data/lib/graphql/schema/has_single_input_argument.rb +160 -0
- data/lib/graphql/schema/input_object.rb +116 -60
- data/lib/graphql/schema/interface.rb +34 -16
- data/lib/graphql/schema/introspection_system.rb +8 -17
- data/lib/graphql/schema/late_bound_type.rb +4 -0
- data/lib/graphql/schema/list.rb +3 -3
- data/lib/graphql/schema/loader.rb +3 -4
- data/lib/graphql/schema/member/base_dsl_methods.rb +18 -2
- data/lib/graphql/schema/member/has_arguments.rb +132 -100
- data/lib/graphql/schema/member/has_authorization.rb +35 -0
- data/lib/graphql/schema/member/has_dataloader.rb +99 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
- data/lib/graphql/schema/member/has_directives.rb +4 -4
- data/lib/graphql/schema/member/has_fields.rb +115 -15
- data/lib/graphql/schema/member/has_interfaces.rb +26 -12
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +1 -1
- data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -4
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +34 -8
- data/lib/graphql/schema/printer.rb +9 -7
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +6 -129
- data/lib/graphql/schema/resolver.rb +90 -32
- data/lib/graphql/schema/scalar.rb +4 -9
- data/lib/graphql/schema/subscription.rb +63 -10
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/union.rb +2 -2
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +62 -0
- data/lib/graphql/schema/validator/required_validator.rb +92 -11
- data/lib/graphql/schema/validator.rb +3 -1
- data/lib/graphql/schema/visibility/migration.rb +188 -0
- data/lib/graphql/schema/visibility/profile.rb +445 -0
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +311 -0
- data/lib/graphql/schema/warden.rb +275 -103
- data/lib/graphql/schema.rb +950 -210
- data/lib/graphql/static_validation/all_rules.rb +3 -3
- data/lib/graphql/static_validation/base_visitor.rb +7 -6
- data/lib/graphql/static_validation/literal_validator.rb +6 -7
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
- data/lib/graphql/static_validation/validation_context.rb +21 -5
- data/lib/graphql/static_validation/validator.rb +9 -1
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -5
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +21 -4
- data/lib/graphql/subscriptions/serialize.rb +3 -1
- data/lib/graphql/subscriptions.rb +21 -17
- data/lib/graphql/testing/helpers.rb +161 -0
- data/lib/graphql/testing/mock_action_cable.rb +111 -0
- data/lib/graphql/testing.rb +3 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +7 -3
- data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
- data/lib/graphql/tracing/appsignal_trace.rb +32 -59
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +46 -162
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +156 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +75 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +47 -54
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +183 -37
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +864 -0
- data/lib/graphql/tracing/platform_tracing.rb +3 -1
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +5 -1
- data/lib/graphql/tracing/prometheus_trace.rb +73 -73
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +32 -58
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +82 -0
- data/lib/graphql/tracing/statsd_trace.rb +33 -45
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +112 -1
- data/lib/graphql/tracing.rb +31 -28
- data/lib/graphql/type_kinds.rb +2 -1
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +44 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +18 -0
- data/lib/graphql/types/relay/has_node_field.rb +13 -8
- data/lib/graphql/types/relay/has_nodes_field.rb +13 -8
- data/lib/graphql/types/relay/node_behaviors.rb +13 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
- data/lib/graphql/types.rb +18 -10
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/unauthorized_error.rb +5 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +71 -54
- data/readme.md +12 -2
- metadata +233 -37
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -57
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
- data/lib/graphql/analysis/ast/query_depth.rb +0 -55
- data/lib/graphql/analysis/ast/visitor.rb +0 -276
- data/lib/graphql/analysis/ast.rb +0 -81
- data/lib/graphql/backtrace/inspect_result.rb +0 -50
- data/lib/graphql/backtrace/trace.rb +0 -96
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -59
- data/lib/graphql/language/parser.y +0 -560
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
|
@@ -1,187 +1,71 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
require "graphql/tracing/monitor_trace"
|
|
2
3
|
|
|
3
4
|
module GraphQL
|
|
4
5
|
module Tracing
|
|
6
|
+
# A tracer for reporting to DataDog
|
|
7
|
+
# @example Adding this tracer to your schema
|
|
8
|
+
# class MySchema < GraphQL::Schema
|
|
9
|
+
# trace_with GraphQL::Tracing::DataDogTrace
|
|
10
|
+
# end
|
|
11
|
+
# @example Skipping `resolve_type` and `authorized` events
|
|
12
|
+
# trace_with GraphQL::Tracing::DataDogTrace, trace_authorized: false, trace_resolve_type: false
|
|
13
|
+
DataDogTrace = MonitorTrace.create_module("datadog")
|
|
5
14
|
module DataDogTrace
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
class DatadogMonitor < MonitorTrace::Monitor
|
|
16
|
+
def initialize(set_transaction_name:, service: nil, tracer: nil, **_rest)
|
|
17
|
+
super
|
|
18
|
+
if tracer.nil?
|
|
19
|
+
tracer = defined?(Datadog::Tracing) ? Datadog::Tracing : Datadog.tracer
|
|
20
|
+
end
|
|
21
|
+
@tracer = tracer
|
|
22
|
+
@service_name = service
|
|
23
|
+
@has_prepare_span = @trace.respond_to?(:prepare_span)
|
|
12
24
|
end
|
|
13
|
-
@tracer = tracer
|
|
14
|
-
|
|
15
|
-
@analytics_enabled = analytics_enabled
|
|
16
|
-
@analytics_sample_rate = analytics_sample_rate
|
|
17
|
-
|
|
18
|
-
@service_name = service
|
|
19
|
-
@has_prepare_span = respond_to?(:prepare_span)
|
|
20
|
-
super
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
'lex' => 'lex.graphql',
|
|
27
|
-
'parse' => 'parse.graphql',
|
|
28
|
-
'validate' => 'validate.graphql',
|
|
29
|
-
'analyze_query' => 'analyze.graphql',
|
|
30
|
-
'analyze_multiplex' => 'analyze.graphql',
|
|
31
|
-
'execute_multiplex' => 'execute.graphql',
|
|
32
|
-
'execute_query' => 'execute.graphql',
|
|
33
|
-
'execute_query_lazy' => 'execute.graphql',
|
|
34
|
-
}.each do |trace_method, trace_key|
|
|
35
|
-
module_eval <<-RUBY, __FILE__, __LINE__
|
|
36
|
-
def #{trace_method}(**data)
|
|
37
|
-
@tracer.trace("#{trace_key}", service: @service_name, type: 'custom') do |span|
|
|
38
|
-
span.set_tag('component', 'graphql')
|
|
39
|
-
span.set_tag('operation', '#{trace_method}')
|
|
40
25
|
|
|
41
|
-
|
|
42
|
-
if trace_method == 'execute_multiplex'
|
|
43
|
-
<<-RUBY
|
|
44
|
-
operations = data[:multiplex].queries.map(&:selected_operation_name).join(', ')
|
|
26
|
+
attr_reader :tracer, :service_name
|
|
45
27
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
span.set_tag(:selected_operation_type, data[:query].selected_operation.operation_type)
|
|
61
|
-
span.set_tag(:query_string, data[:query].query_string)
|
|
62
|
-
RUBY
|
|
63
|
-
end
|
|
64
|
-
}
|
|
65
|
-
if @has_prepare_span
|
|
66
|
-
prepare_span("#{trace_method.sub("platform_", "")}", data, span)
|
|
28
|
+
def instrument(keyword, object)
|
|
29
|
+
trace_key = name_for(keyword, object)
|
|
30
|
+
@tracer.trace(trace_key, service: @service_name, type: 'custom') do |span|
|
|
31
|
+
span.set_tag('component', 'graphql')
|
|
32
|
+
op_name = keyword.respond_to?(:name) ? keyword.name : keyword.to_s
|
|
33
|
+
span.set_tag('operation', op_name)
|
|
34
|
+
|
|
35
|
+
if keyword == :execute
|
|
36
|
+
operations = object.queries.map(&:selected_operation_name).join(', ')
|
|
37
|
+
first_query = object.queries.first
|
|
38
|
+
resource = if operations.empty?
|
|
39
|
+
fallback_transaction_name(first_query && first_query.context)
|
|
40
|
+
else
|
|
41
|
+
operations
|
|
67
42
|
end
|
|
68
|
-
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
RUBY
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# rubocop:enable Development/NoEvalCop
|
|
43
|
+
span.resource = resource if resource
|
|
75
44
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
else
|
|
81
|
-
true
|
|
82
|
-
end
|
|
83
|
-
platform_key = if trace_field
|
|
84
|
-
@platform_key_cache[DataDogTrace].platform_field_key_cache[field]
|
|
85
|
-
else
|
|
86
|
-
nil
|
|
87
|
-
end
|
|
88
|
-
if platform_key && trace_field
|
|
89
|
-
@tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
|
|
90
|
-
span.set_tag('component', 'graphql')
|
|
91
|
-
span.set_tag('operation', span_key)
|
|
45
|
+
span.set_tag("selected_operation_name", first_query.selected_operation_name)
|
|
46
|
+
span.set_tag("selected_operation_type", first_query.selected_operation&.operation_type)
|
|
47
|
+
span.set_tag("query_string", first_query.query_string)
|
|
48
|
+
end
|
|
92
49
|
|
|
93
50
|
if @has_prepare_span
|
|
94
|
-
|
|
95
|
-
prepare_span(span_key, prepare_span_data, span)
|
|
51
|
+
@trace.prepare_span(keyword, object, span)
|
|
96
52
|
end
|
|
97
53
|
yield
|
|
98
54
|
end
|
|
99
|
-
else
|
|
100
|
-
yield
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
def execute_field(query:, field:, ast_node:, arguments:, object:)
|
|
104
|
-
execute_field_span("execute_field", query, field, ast_node, arguments, object) do
|
|
105
|
-
super(query: query, field: field, ast_node: ast_node, arguments: arguments, object: object)
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def execute_field_lazy(query:, field:, ast_node:, arguments:, object:)
|
|
110
|
-
execute_field_span("execute_field_lazy", query, field, ast_node, arguments, object) do
|
|
111
|
-
super(query: query, field: field, ast_node: ast_node, arguments: arguments, object: object)
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def authorized(query:, type:, object:)
|
|
116
|
-
authorized_span("authorized", object, type, query) do
|
|
117
|
-
super(query: query, type: type, object: object)
|
|
118
55
|
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def authorized_span(span_key, object, type, query)
|
|
122
|
-
platform_key = @platform_key_cache[DataDogTrace].platform_authorized_key_cache[type]
|
|
123
|
-
@tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
|
|
124
|
-
span.set_tag('component', 'graphql')
|
|
125
|
-
span.set_tag('operation', span_key)
|
|
126
56
|
|
|
127
|
-
|
|
128
|
-
|
|
57
|
+
include MonitorTrace::Monitor::GraphQLSuffixNames
|
|
58
|
+
class Event < MonitorTrace::Monitor::Event
|
|
59
|
+
def start
|
|
60
|
+
name = @monitor.name_for(keyword, object)
|
|
61
|
+
@dd_span = @monitor.tracer.trace(name, service: @monitor.service_name, type: 'custom')
|
|
129
62
|
end
|
|
130
|
-
yield
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def authorized_lazy(object:, type:, query:)
|
|
135
|
-
authorized_span("authorized_lazy", object, type, query) do
|
|
136
|
-
super(query: query, type: type, object: object)
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def resolve_type(object:, type:, query:)
|
|
141
|
-
resolve_type_span("resolve_type", object, type, query) do
|
|
142
|
-
super(object: object, query: query, type: type)
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
63
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
super(object: object, query: query, type: type)
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def resolve_type_span(span_key, object, type, query)
|
|
153
|
-
platform_key = @platform_key_cache[DataDogTrace].platform_resolve_type_key_cache[type]
|
|
154
|
-
@tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
|
|
155
|
-
span.set_tag('component', 'graphql')
|
|
156
|
-
span.set_tag('operation', span_key)
|
|
157
|
-
|
|
158
|
-
if @has_prepare_span
|
|
159
|
-
prepare_span(span_key, {object: object, type: type, query: query}, span)
|
|
64
|
+
def finish
|
|
65
|
+
@dd_span.finish
|
|
160
66
|
end
|
|
161
|
-
yield
|
|
162
67
|
end
|
|
163
68
|
end
|
|
164
|
-
|
|
165
|
-
include PlatformTrace
|
|
166
|
-
|
|
167
|
-
# Implement this method in a subclass to apply custom tags to datadog spans
|
|
168
|
-
# @param key [String] The event being traced
|
|
169
|
-
# @param data [Hash] The runtime data for this event (@see GraphQL::Tracing for keys for each event)
|
|
170
|
-
# @param span [Datadog::Tracing::SpanOperation] The datadog span for this event
|
|
171
|
-
# def prepare_span(key, data, span)
|
|
172
|
-
# end
|
|
173
|
-
|
|
174
|
-
def platform_field_key(field)
|
|
175
|
-
field.path
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
def platform_authorized_key(type)
|
|
179
|
-
"#{type.graphql_name}.authorized"
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def platform_resolve_type_key(type)
|
|
183
|
-
"#{type.graphql_name}.resolve_type"
|
|
184
|
-
end
|
|
185
69
|
end
|
|
186
70
|
end
|
|
187
71
|
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GraphQL
|
|
4
|
+
module Tracing
|
|
5
|
+
class DetailedTrace
|
|
6
|
+
class ActiveRecordBackend
|
|
7
|
+
class GraphqlDetailedTrace < ActiveRecord::Base
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize(limit: nil, model_class: nil)
|
|
11
|
+
@limit = limit
|
|
12
|
+
@model_class = model_class || GraphqlDetailedTrace
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def traces(last:, before:)
|
|
16
|
+
gdts = @model_class.all.order("begin_ms DESC")
|
|
17
|
+
if before
|
|
18
|
+
gdts = gdts.where("begin_ms < ?", before)
|
|
19
|
+
end
|
|
20
|
+
if last
|
|
21
|
+
gdts = gdts.limit(last)
|
|
22
|
+
end
|
|
23
|
+
gdts.map { |gdt| record_to_stored_trace(gdt) }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def delete_trace(id)
|
|
27
|
+
@model_class.where(id: id).destroy_all
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def delete_all_traces
|
|
32
|
+
@model_class.all.destroy_all
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def find_trace(id)
|
|
36
|
+
gdt = @model_class.find_by(id: id)
|
|
37
|
+
if gdt
|
|
38
|
+
record_to_stored_trace(gdt)
|
|
39
|
+
else
|
|
40
|
+
nil
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def save_trace(operation_name, duration_ms, begin_ms, trace_data)
|
|
45
|
+
gdt = @model_class.create!(
|
|
46
|
+
begin_ms: begin_ms,
|
|
47
|
+
operation_name: operation_name,
|
|
48
|
+
duration_ms: duration_ms,
|
|
49
|
+
trace_data: trace_data,
|
|
50
|
+
)
|
|
51
|
+
if @limit
|
|
52
|
+
@model_class
|
|
53
|
+
.where("id NOT IN(SELECT id FROM graphql_detailed_traces ORDER BY begin_ms DESC LIMIT ?)", @limit)
|
|
54
|
+
.delete_all
|
|
55
|
+
end
|
|
56
|
+
gdt.id
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def record_to_stored_trace(gdt)
|
|
62
|
+
StoredTrace.new(
|
|
63
|
+
id: gdt.id,
|
|
64
|
+
begin_ms: gdt.begin_ms,
|
|
65
|
+
operation_name: gdt.operation_name,
|
|
66
|
+
duration_ms: gdt.duration_ms,
|
|
67
|
+
trace_data: gdt.trace_data
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GraphQL
|
|
4
|
+
module Tracing
|
|
5
|
+
class DetailedTrace
|
|
6
|
+
# An in-memory trace storage backend. Suitable for testing and development only.
|
|
7
|
+
# It won't work for multi-process deployments and everything is erased when the app is restarted.
|
|
8
|
+
class MemoryBackend
|
|
9
|
+
def initialize(limit: nil)
|
|
10
|
+
@limit = limit
|
|
11
|
+
@traces = {}
|
|
12
|
+
@next_id = 0
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def traces(last:, before:)
|
|
16
|
+
page = []
|
|
17
|
+
@traces.values.reverse_each do |trace|
|
|
18
|
+
if page.size == last
|
|
19
|
+
break
|
|
20
|
+
elsif before.nil? || trace.begin_ms < before
|
|
21
|
+
page << trace
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
page
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def find_trace(id)
|
|
28
|
+
@traces[id]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def delete_trace(id)
|
|
32
|
+
@traces.delete(id.to_i)
|
|
33
|
+
nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def delete_all_traces
|
|
37
|
+
@traces.clear
|
|
38
|
+
nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def save_trace(operation_name, duration, begin_ms, trace_data)
|
|
42
|
+
id = @next_id
|
|
43
|
+
@next_id += 1
|
|
44
|
+
@traces[id] = DetailedTrace::StoredTrace.new(
|
|
45
|
+
id: id,
|
|
46
|
+
operation_name: operation_name,
|
|
47
|
+
duration_ms: duration,
|
|
48
|
+
begin_ms: begin_ms,
|
|
49
|
+
trace_data: trace_data
|
|
50
|
+
)
|
|
51
|
+
if @limit && @traces.size > @limit
|
|
52
|
+
del_keys = @traces.keys[0...-@limit]
|
|
53
|
+
del_keys.each { |k| @traces.delete(k) }
|
|
54
|
+
end
|
|
55
|
+
id
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GraphQL
|
|
4
|
+
module Tracing
|
|
5
|
+
class DetailedTrace
|
|
6
|
+
class RedisBackend
|
|
7
|
+
KEY_PREFIX = "gql:trace:"
|
|
8
|
+
def initialize(redis:, limit: nil)
|
|
9
|
+
@redis = redis
|
|
10
|
+
@key = KEY_PREFIX + "traces"
|
|
11
|
+
@remrangebyrank_limit = limit ? -limit - 1 : nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def traces(last:, before:)
|
|
15
|
+
before = case before
|
|
16
|
+
when Numeric
|
|
17
|
+
"(#{before}"
|
|
18
|
+
when nil
|
|
19
|
+
"+inf"
|
|
20
|
+
end
|
|
21
|
+
str_pairs = @redis.zrange(@key, before, 0, byscore: true, rev: true, limit: [0, last || 100], withscores: true)
|
|
22
|
+
str_pairs.map do |(str_data, score)|
|
|
23
|
+
entry_to_trace(score, str_data)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def delete_trace(id)
|
|
28
|
+
@redis.zremrangebyscore(@key, id, id)
|
|
29
|
+
nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def delete_all_traces
|
|
33
|
+
@redis.del(@key)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def find_trace(id)
|
|
37
|
+
str_data = @redis.zrange(@key, id, id, byscore: true).first
|
|
38
|
+
if str_data.nil?
|
|
39
|
+
nil
|
|
40
|
+
else
|
|
41
|
+
entry_to_trace(id, str_data)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def save_trace(operation_name, duration_ms, begin_ms, trace_data)
|
|
46
|
+
id = begin_ms
|
|
47
|
+
data = JSON.dump({ "o" => operation_name, "d" => duration_ms, "b" => begin_ms, "t" => Base64.encode64(trace_data) })
|
|
48
|
+
@redis.pipelined do |pipeline|
|
|
49
|
+
pipeline.zadd(@key, id, data)
|
|
50
|
+
if @remrangebyrank_limit
|
|
51
|
+
pipeline.zremrangebyrank(@key, 0, @remrangebyrank_limit)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
id
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def entry_to_trace(id, json_str)
|
|
60
|
+
data = JSON.parse(json_str)
|
|
61
|
+
StoredTrace.new(
|
|
62
|
+
id: id,
|
|
63
|
+
operation_name: data["o"],
|
|
64
|
+
duration_ms: data["d"].to_f,
|
|
65
|
+
begin_ms: data["b"].to_i,
|
|
66
|
+
trace_data: Base64.decode64(data["t"]),
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
if defined?(ActiveRecord)
|
|
3
|
+
require "graphql/tracing/detailed_trace/active_record_backend"
|
|
4
|
+
end
|
|
5
|
+
require "graphql/tracing/detailed_trace/memory_backend"
|
|
6
|
+
require "graphql/tracing/detailed_trace/redis_backend"
|
|
7
|
+
|
|
8
|
+
module GraphQL
|
|
9
|
+
module Tracing
|
|
10
|
+
# `DetailedTrace` can make detailed profiles for a subset of production traffic. Install it in Rails with `rails generate graphql:detailed_trace`.
|
|
11
|
+
#
|
|
12
|
+
# When `MySchema.detailed_trace?(query)` returns `true`, a profiler-specific `trace_mode: ...` will be used for the query,
|
|
13
|
+
# overriding the one in `context[:trace_mode]`.
|
|
14
|
+
#
|
|
15
|
+
# By default, the detailed tracer calls `.inspect` on application objects returned from fields. You can customize
|
|
16
|
+
# this behavior by extending {DetailedTrace} and overriding {#inspect_object}. You can opt out of debug annotations
|
|
17
|
+
# entirely with `use ..., debug: false` or for a single query with `context: { detailed_trace_debug: false }`.
|
|
18
|
+
#
|
|
19
|
+
# You can store saved traces in two ways:
|
|
20
|
+
#
|
|
21
|
+
# - __ActiveRecord__: With `rails generate graphql:detailed_trace`, a new migration will be added to your app.
|
|
22
|
+
# That table will be used to store trace data.
|
|
23
|
+
#
|
|
24
|
+
# - __Redis__: Pass `redis: ...` to save trace data to a Redis database. Depending on your needs,
|
|
25
|
+
# you can configure this database to retain all data (persistent) or to expire data according to your rules.
|
|
26
|
+
#
|
|
27
|
+
# If you need to save traces indefinitely, you can download them from Perfetto after opening them there.
|
|
28
|
+
#
|
|
29
|
+
# @example Installing with Rails
|
|
30
|
+
# rails generate graphql:detailed_trace # optional: --redis
|
|
31
|
+
#
|
|
32
|
+
# @example Adding the sampler to your schema
|
|
33
|
+
# class MySchema < GraphQL::Schema
|
|
34
|
+
# # Add the sampler:
|
|
35
|
+
# use GraphQL::Tracing::DetailedTrace, redis: Redis.new(...), limit: 100
|
|
36
|
+
#
|
|
37
|
+
# # And implement this hook to tell it when to take a sample:
|
|
38
|
+
# def self.detailed_trace?(query)
|
|
39
|
+
# # Could use `query.context`, `query.selected_operation_name`, `query.query_string` here
|
|
40
|
+
# # Could call out to Flipper, etc
|
|
41
|
+
# rand <= 0.000_1 # one in ten thousand
|
|
42
|
+
# end
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# @see Graphql::Dashboard GraphQL::Dashboard for viewing stored results
|
|
46
|
+
#
|
|
47
|
+
# @example Customizing debug output in traces
|
|
48
|
+
# class CustomDetailedTrace < GraphQL::Tracing::DetailedTrace
|
|
49
|
+
# def inspect_object(object)
|
|
50
|
+
# if object.is_a?(SomeThing)
|
|
51
|
+
# # handle it specially ...
|
|
52
|
+
# else
|
|
53
|
+
# super
|
|
54
|
+
# end
|
|
55
|
+
# end
|
|
56
|
+
# end
|
|
57
|
+
#
|
|
58
|
+
# @example disabling debug annotations completely
|
|
59
|
+
# use DetailedTrace, debug: false, ...
|
|
60
|
+
#
|
|
61
|
+
# @example disabling debug annotations for one query
|
|
62
|
+
# MySchema.execute(query_str, context: { detailed_trace_debug: false })
|
|
63
|
+
#
|
|
64
|
+
class DetailedTrace
|
|
65
|
+
# @param redis [Redis] If provided, profiles will be stored in Redis for later review
|
|
66
|
+
# @param limit [Integer] A maximum number of profiles to store
|
|
67
|
+
# @param debug [Boolean] if `false`, it won't create `debug` annotations in Perfetto traces (reduces overhead)
|
|
68
|
+
# @param model_class [Class<ActiveRecord::Base>] Overrides {ActiveRecordBackend::GraphqlDetailedTrace} if present
|
|
69
|
+
def self.use(schema, trace_mode: :profile_sample, memory: false, debug: debug?, redis: nil, limit: nil, model_class: nil)
|
|
70
|
+
storage = if redis
|
|
71
|
+
RedisBackend.new(redis: redis, limit: limit)
|
|
72
|
+
elsif memory
|
|
73
|
+
MemoryBackend.new(limit: limit)
|
|
74
|
+
elsif defined?(ActiveRecord)
|
|
75
|
+
ActiveRecordBackend.new(limit: limit, model_class: model_class)
|
|
76
|
+
else
|
|
77
|
+
raise ArgumentError, "To store traces, install ActiveRecord or provide `redis: ...`"
|
|
78
|
+
end
|
|
79
|
+
detailed_trace = self.new(storage: storage, trace_mode: trace_mode, debug: debug)
|
|
80
|
+
schema.detailed_trace = detailed_trace
|
|
81
|
+
schema.trace_with(PerfettoTrace, mode: trace_mode, save_profile: true)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def initialize(storage:, trace_mode:, debug:)
|
|
85
|
+
@storage = storage
|
|
86
|
+
@trace_mode = trace_mode
|
|
87
|
+
@debug = debug
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# @return [Symbol] The trace mode to use when {Schema.detailed_trace?} returns `true`
|
|
91
|
+
attr_reader :trace_mode
|
|
92
|
+
|
|
93
|
+
# @return [String] ID of saved trace
|
|
94
|
+
def save_trace(operation_name, duration_ms, begin_ms, trace_data)
|
|
95
|
+
@storage.save_trace(operation_name, duration_ms, begin_ms, trace_data)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @return [Boolean]
|
|
99
|
+
def debug?
|
|
100
|
+
@debug
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# @param last [Integer]
|
|
104
|
+
# @param before [Integer] Timestamp in milliseconds since epoch
|
|
105
|
+
# @return [Enumerable<StoredTrace>]
|
|
106
|
+
def traces(last: nil, before: nil)
|
|
107
|
+
@storage.traces(last: last, before: before)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# @return [StoredTrace, nil]
|
|
111
|
+
def find_trace(id)
|
|
112
|
+
@storage.find_trace(id)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# @return [void]
|
|
116
|
+
def delete_trace(id)
|
|
117
|
+
@storage.delete_trace(id)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# @return [void]
|
|
121
|
+
def delete_all_traces
|
|
122
|
+
@storage.delete_all_traces
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def inspect_object(object)
|
|
126
|
+
self.class.inspect_object(object)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def self.inspect_object(object)
|
|
130
|
+
if defined?(ActiveRecord::Relation) && object.is_a?(ActiveRecord::Relation)
|
|
131
|
+
"#{object.class}, .to_sql=#{object.to_sql.inspect}"
|
|
132
|
+
else
|
|
133
|
+
object.inspect
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Default debug setting
|
|
138
|
+
# @return [true]
|
|
139
|
+
def self.debug?
|
|
140
|
+
true
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
class StoredTrace
|
|
144
|
+
def initialize(id:, operation_name:, duration_ms:, begin_ms:, trace_data:)
|
|
145
|
+
@id = id
|
|
146
|
+
@operation_name = operation_name
|
|
147
|
+
@duration_ms = duration_ms
|
|
148
|
+
@begin_ms = begin_ms
|
|
149
|
+
@trace_data = trace_data
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
attr_reader :id, :operation_name, :duration_ms, :begin_ms, :trace_data
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GraphQL
|
|
4
|
+
module Tracing
|
|
5
|
+
module LegacyHooksTrace
|
|
6
|
+
def execute_multiplex(multiplex:)
|
|
7
|
+
multiplex_instrumenters = multiplex.schema.instrumenters[:multiplex]
|
|
8
|
+
query_instrumenters = multiplex.schema.instrumenters[:query]
|
|
9
|
+
# First, run multiplex instrumentation, then query instrumentation for each query
|
|
10
|
+
RunHooks.call_hooks(multiplex_instrumenters, multiplex, :before_multiplex, :after_multiplex) do
|
|
11
|
+
RunHooks.each_query_call_hooks(query_instrumenters, multiplex.queries) do
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module RunHooks
|
|
18
|
+
module_function
|
|
19
|
+
# Call the before_ hooks of each query,
|
|
20
|
+
# Then yield if no errors.
|
|
21
|
+
# `call_hooks` takes care of appropriate cleanup.
|
|
22
|
+
def each_query_call_hooks(instrumenters, queries, i = 0)
|
|
23
|
+
if i >= queries.length
|
|
24
|
+
yield
|
|
25
|
+
else
|
|
26
|
+
query = queries[i]
|
|
27
|
+
call_hooks(instrumenters, query, :before_query, :after_query) {
|
|
28
|
+
each_query_call_hooks(instrumenters, queries, i + 1) {
|
|
29
|
+
yield
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Call each before hook, and if they all succeed, yield.
|
|
36
|
+
# If they don't all succeed, call after_ for each one that succeeded.
|
|
37
|
+
def call_hooks(instrumenters, object, before_hook_name, after_hook_name)
|
|
38
|
+
begin
|
|
39
|
+
successful = []
|
|
40
|
+
instrumenters.each do |instrumenter|
|
|
41
|
+
instrumenter.public_send(before_hook_name, object)
|
|
42
|
+
successful << instrumenter
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# if any before hooks raise an exception, quit calling before hooks,
|
|
46
|
+
# but call the after hooks on anything that succeeded but also
|
|
47
|
+
# raise the exception that came from the before hook.
|
|
48
|
+
rescue GraphQL::ExecutionError => err
|
|
49
|
+
object.context.errors << err
|
|
50
|
+
rescue => e
|
|
51
|
+
raise call_after_hooks(successful, object, after_hook_name, e)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
begin
|
|
55
|
+
yield # Call the user code
|
|
56
|
+
ensure
|
|
57
|
+
ex = call_after_hooks(successful, object, after_hook_name, nil)
|
|
58
|
+
raise ex if ex
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def call_after_hooks(instrumenters, object, after_hook_name, ex)
|
|
63
|
+
instrumenters.reverse_each do |instrumenter|
|
|
64
|
+
begin
|
|
65
|
+
instrumenter.public_send(after_hook_name, object)
|
|
66
|
+
rescue => e
|
|
67
|
+
ex = e
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
ex
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|