graphql-metrics 2.0.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,107 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GraphQLMetrics
4
- class Instrumentation
5
- extend Forwardable
6
-
7
- CONTEXT_NAMESPACE = :extracted_metrics
8
- TIMING_CACHE_KEY = :timing_cache
9
- START_TIME_KEY = :query_start_time
10
-
11
- attr_reader :ctx_namespace, :query
12
- def_delegators :extractor, :extractor_defines_any_visitors?
13
-
14
- def self.use(schema_definition)
15
- instrumentation = self.new
16
- return unless instrumentation.extractor_defines_any_visitors?
17
-
18
- instrumentation.setup_instrumentation(schema_definition)
19
- end
20
-
21
- def self.current_time
22
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
23
- end
24
-
25
- def use(schema_definition)
26
- return unless extractor_defines_any_visitors?
27
-
28
- setup_instrumentation(schema_definition)
29
- end
30
-
31
- def setup_instrumentation(schema_definition)
32
- schema_definition.instrument(:query, self)
33
- schema_definition.instrument(:field, self)
34
- end
35
-
36
- def extractor
37
- @extractor ||= Extractor.new(self)
38
- end
39
-
40
- def before_query(query)
41
- return unless extractor_defines_any_visitors?
42
-
43
- ns = query.context.namespace(CONTEXT_NAMESPACE)
44
- ns[TIMING_CACHE_KEY] = {}
45
- ns[START_TIME_KEY] = self.class.current_time
46
- rescue StandardError => ex
47
- extractor.handle_extraction_exception(ex)
48
- end
49
-
50
- def after_query(query)
51
- @query = query
52
-
53
- return unless extractor_defines_any_visitors?
54
- return if respond_to?(:skip_extraction?) && skip_extraction?(query)
55
- return unless @ctx_namespace = query.context.namespace(CONTEXT_NAMESPACE)
56
-
57
- before_query_extracted(query, query.context) if respond_to?(:before_query_extracted)
58
-
59
- extractor.extract!(query)
60
-
61
- after_query_teardown(query) if respond_to?(:after_query_teardown)
62
- rescue StandardError => ex
63
- extractor.handle_extraction_exception(ex)
64
- end
65
-
66
- def instrument(type, field)
67
- return field unless respond_to?(:field_extracted) || extractor.respond_to?(:field_extracted)
68
- return field if type.introspection?
69
-
70
- old_resolve_proc = field.resolve_proc
71
- new_resolve_proc = ->(obj, args, ctx) do
72
- start_time = self.class.current_time
73
- result = old_resolve_proc.call(obj, args, ctx)
74
-
75
- begin
76
- next result if respond_to?(:skip_field_resolution_timing?) &&
77
- skip_field_resolution_timing?(query, ctx)
78
-
79
- end_time = self.class.current_time
80
-
81
- ns = ctx.namespace(CONTEXT_NAMESPACE)
82
-
83
- ns[TIMING_CACHE_KEY][ctx.ast_node] ||= []
84
- ns[TIMING_CACHE_KEY][ctx.ast_node] << end_time - start_time
85
-
86
- result
87
- rescue StandardError => ex
88
- extractor.handle_extraction_exception(ex)
89
- result
90
- end
91
- end
92
-
93
- field.redefine { resolve(new_resolve_proc) }
94
- end
95
-
96
- def after_query_resolver_times(ast_node)
97
- ctx_namespace.dig(Instrumentation::TIMING_CACHE_KEY).fetch(ast_node, [])
98
- end
99
-
100
- def after_query_start_and_end_time
101
- start_time = ctx_namespace[Instrumentation::START_TIME_KEY]
102
- return unless start_time
103
-
104
- [start_time, self.class.current_time]
105
- end
106
- end
107
- end
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GraphQLMetrics
4
- BASE_CLASS = if defined?(GraphQL::Batch::Executor)
5
- GraphQL::Batch::Executor
6
- else
7
- class NoExecutor
8
- class << self
9
- def resolve(_loader)
10
- super
11
- end
12
-
13
- def around_promise_callbacks
14
- super
15
- end
16
- end
17
- end
18
-
19
- NoExecutor
20
- end
21
-
22
- class TimedBatchExecutor < BASE_CLASS
23
- TIMINGS = {}
24
- private_constant :TIMINGS
25
-
26
- class << self
27
- def timings
28
- TIMINGS
29
- end
30
-
31
- def clear_timings
32
- TIMINGS.clear
33
- end
34
-
35
- def serialize_loader_key(loader_key)
36
- identifiers = []
37
-
38
- serialized = loader_key.map do |group_arg|
39
- if [Class, Symbol, String].include?(group_arg.class)
40
- group_arg
41
- elsif group_arg.is_a?(Numeric)
42
- identifiers << group_arg
43
- '_'
44
- elsif group_arg.respond_to?(:id)
45
- identifiers << group_arg.id
46
- "#{group_arg.class}/_"
47
- else
48
- '?'
49
- end
50
- end
51
-
52
- [serialized.map(&:to_s).join('/'), identifiers.map(&:to_s)]
53
- end
54
- end
55
-
56
- def resolve(loader)
57
- @resolve_meta = {
58
- start_time: Instrumentation.current_time,
59
- current_loader: loader,
60
- perform_queue_sizes: loader.send(:queue).size
61
- }
62
-
63
- super
64
- end
65
-
66
- def around_promise_callbacks
67
- return super unless @resolve_meta
68
-
69
- end_time = Instrumentation.current_time
70
-
71
- TIMINGS[@resolve_meta[:current_loader].loader_key] ||= { times: [], perform_queue_sizes: [] }
72
- TIMINGS[@resolve_meta[:current_loader].loader_key][:times] << end_time - @resolve_meta[:start_time]
73
- TIMINGS[@resolve_meta[:current_loader].loader_key][:perform_queue_sizes] << @resolve_meta[:perform_queue_sizes]
74
-
75
- @resolve_meta = nil
76
-
77
- super
78
- end
79
- end
80
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GraphQLMetrics
4
- VERSION = "2.0.1"
5
- end