graphql-metrics 2.0.1 → 3.0.0

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.
@@ -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