lib/graphql/metrics/tracer.rb in graphql-metrics-4.0.2 vs lib/graphql/metrics/tracer.rb in graphql-metrics-4.0.3

- old
+ new

@@ -2,13 +2,14 @@ module GraphQL module Metrics class Tracer # NOTE: These constants come from the graphql ruby gem. - GRAPHQL_GEM_LEXING_KEY = 'lex' + GRAPHQL_GEM_EXECUTE_MULTIPLEX_KEY = 'execute_multiplex' GRAPHQL_GEM_PARSING_KEY = 'parse' - GRAPHQL_GEM_VALIDATION_KEYS = ['validate', 'analyze_query'] + GRAPHQL_GEM_VALIDATION_KEY = 'validate' + GRAPHQL_GEM_ANALYZE_KEY = 'analyze_query' GRAPHQL_GEM_TRACING_FIELD_KEYS = [ GRAPHQL_GEM_TRACING_FIELD_KEY = 'execute_field', GRAPHQL_GEM_TRACING_LAZY_FIELD_KEY = 'execute_field_lazy' ] @@ -20,25 +21,25 @@ return yield if skip_tracing # NOTE: Not all tracing events are handled here, but those that are are handled in this case statement in # chronological order. case key - when GRAPHQL_GEM_LEXING_KEY - return setup_tracing_before_lexing(&block) + when GRAPHQL_GEM_EXECUTE_MULTIPLEX_KEY + return setup_tracing(&block) when GRAPHQL_GEM_PARSING_KEY return capture_parsing_time(&block) - when *GRAPHQL_GEM_VALIDATION_KEYS + when GRAPHQL_GEM_VALIDATION_KEY context = possible_context - - return yield unless context.query.valid? return capture_validation_time(context, &block) + when GRAPHQL_GEM_ANALYZE_KEY + context = possible_context + return capture_analysis_time(context, &block) + when *GRAPHQL_GEM_TRACING_FIELD_KEYS return yield if data[:query].context[SKIP_FIELD_AND_ARGUMENT_METRICS] return yield unless GraphQL::Metrics.timings_capture_enabled?(data[:query].context) - pre_context = nil - context_key = case key when GRAPHQL_GEM_TRACING_FIELD_KEY GraphQL::Metrics::INLINE_FIELD_TIMINGS when GRAPHQL_GEM_TRACING_LAZY_FIELD_KEY GraphQL::Metrics::LAZY_FIELD_TIMINGS @@ -50,43 +51,73 @@ end end private + PreContext = Struct.new( + :query_start_time, + :query_start_time_monotonic, + :parsing_start_time_offset, + :parsing_duration + ) do + def reset_parsing_timings + self[:parsing_start_time_offset] = nil + self[:parsing_duration] = nil + end + end + def pre_context # NOTE: This is used to store timings from lexing, parsing, validation, before we have a context to store # values in. Uses thread-safe Concurrent::ThreadLocalVar to store a set of values per thread. - @pre_context ||= Concurrent::ThreadLocalVar.new(OpenStruct.new) + @pre_context ||= Concurrent::ThreadLocalVar.new(PreContext.new) + @pre_context.value end - def setup_tracing_before_lexing - pre_context.value.query_start_time = GraphQL::Metrics.current_time - pre_context.value.query_start_time_monotonic = GraphQL::Metrics.current_time_monotonic + def setup_tracing + pre_context.query_start_time = GraphQL::Metrics.current_time + pre_context.query_start_time_monotonic = GraphQL::Metrics.current_time_monotonic yield end def capture_parsing_time timed_result = GraphQL::Metrics.time { yield } - pre_context.value.parsing_start_time_offset = timed_result.start_time - pre_context.value.parsing_duration = timed_result.duration + pre_context.parsing_start_time_offset = timed_result.start_time + pre_context.parsing_duration = timed_result.duration timed_result.result end def capture_validation_time(context) - timed_result = GraphQL::Metrics.time(pre_context.value.query_start_time_monotonic) { yield } + if pre_context.parsing_duration.nil? + pre_context.parsing_start_time_offset = 0 + pre_context.parsing_duration = 0 + end + timed_result = GraphQL::Metrics.time(pre_context.query_start_time_monotonic) { yield } + ns = context.namespace(CONTEXT_NAMESPACE) - previous_validation_duration = ns[GraphQL::Metrics::VALIDATION_DURATION] || 0 - ns[QUERY_START_TIME] = pre_context.value.query_start_time - ns[QUERY_START_TIME_MONOTONIC] = pre_context.value.query_start_time_monotonic - ns[PARSING_START_TIME_OFFSET] = pre_context.value.parsing_start_time_offset - ns[PARSING_DURATION] = pre_context.value.parsing_duration + ns[QUERY_START_TIME] = pre_context.query_start_time + ns[QUERY_START_TIME_MONOTONIC] = pre_context.query_start_time_monotonic + ns[PARSING_START_TIME_OFFSET] = pre_context.parsing_start_time_offset + ns[PARSING_DURATION] = pre_context.parsing_duration ns[VALIDATION_START_TIME_OFFSET] = timed_result.time_since_offset - ns[VALIDATION_DURATION] = timed_result.duration + previous_validation_duration + ns[VALIDATION_DURATION] = timed_result.duration + + pre_context.reset_parsing_timings + + timed_result.result + end + + def capture_analysis_time(context) + ns = context.namespace(CONTEXT_NAMESPACE) + + timed_result = GraphQL::Metrics.time(ns[QUERY_START_TIME_MONOTONIC]) { yield } + + ns[ANALYSIS_START_TIME_OFFSET] = timed_result.time_since_offset + ns[ANALYSIS_DURATION] = timed_result.duration timed_result.result end def trace_field(context_key, data)