diff --git a/Gemfile b/Gemfile index 615cc7bec0d393addbf659c9ca3533aca16b3621..f3c21c720e06e6a7f412ac4c29da3a2608fb6f0d 100644 --- a/Gemfile +++ b/Gemfile @@ -276,7 +276,7 @@ gem 'sentry-raven', '~> 2.7' gem 'premailer-rails', '~> 1.9.7' # LabKit: Tracing and Correlation -gem 'gitlab-labkit', '~> 0.1.2' +gem 'gitlab-labkit', '~> 0.2.0' # I18n gem 'ruby_parser', '~> 3.8', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 3b03a8ef691d2ea205d386bc9a3131a281852fcf..4db00ba4e180a7fb143eb7fbeffc64efd7a4a654 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -288,7 +288,7 @@ GEM github-markup (1.7.0) gitlab-default_value_for (3.1.1) activerecord (>= 3.2.0, < 6.0) - gitlab-labkit (0.1.2) + gitlab-labkit (0.2.0) actionpack (~> 5) activesupport (~> 5) grpc (~> 1.15) @@ -1059,7 +1059,7 @@ DEPENDENCIES gitaly-proto (~> 1.26.0) github-markup (~> 1.7.0) gitlab-default_value_for (~> 3.1.1) - gitlab-labkit (~> 0.1.2) + gitlab-labkit (~> 0.2.0) gitlab-markup (~> 1.7.0) gitlab-sidekiq-fetcher (~> 0.4.0) gitlab-styles (~> 2.5) diff --git a/app/graphql/gitlab_schema.rb b/app/graphql/gitlab_schema.rb index 1afe000c5f85455c4db4229b4551454870603e77..a12568d5d3154ce6a27763249eff15ca9e85c442 100644 --- a/app/graphql/gitlab_schema.rb +++ b/app/graphql/gitlab_schema.rb @@ -11,7 +11,7 @@ class GitlabSchema < GraphQL::Schema use Gitlab::Graphql::Authorize use Gitlab::Graphql::Present use Gitlab::Graphql::Connections - use Gitlab::Graphql::Tracing + use Gitlab::Graphql::GenericTracing query_analyzer Gitlab::Graphql::QueryAnalyzers::LogQueryComplexity.analyzer diff --git a/lib/gitlab/graphql/tracing.rb b/lib/gitlab/graphql/generic_tracing.rb similarity index 59% rename from lib/gitlab/graphql/tracing.rb rename to lib/gitlab/graphql/generic_tracing.rb index 6b505e4262bf18fcb75862ae11559957128910d4..936b22d5afa89a88d7d07e92c10ad7fb803b778b 100644 --- a/lib/gitlab/graphql/tracing.rb +++ b/lib/gitlab/graphql/generic_tracing.rb @@ -1,8 +1,11 @@ # frozen_string_literal: true +# This class is used as a hook to observe graphql runtime events. From this +# hook both gitlab metrics and opentracking measurements are generated + module Gitlab module Graphql - class Tracing < GraphQL::Tracing::PlatformTracing + class GenericTracing < GraphQL::Tracing::PlatformTracing self.platform_keys = { 'lex' => 'graphql.lex', 'parse' => 'graphql.parse', @@ -21,17 +24,30 @@ module Gitlab end def platform_trace(platform_key, key, data, &block) + tags = { platform_key: platform_key, key: key } start = Gitlab::Metrics::System.monotonic_time - yield + with_labkit_tracing(tags, &block) ensure duration = Gitlab::Metrics::System.monotonic_time - start - graphql_duration_seconds.observe({ platform_key: platform_key, key: key }, duration) + graphql_duration_seconds.observe(tags, duration) end private + def with_labkit_tracing(tags, &block) + return yield unless Labkit::Tracing.enabled? + + name = "#{tags[:platform_key]}.#{tags[:key]}" + span_tags = { + 'component' => 'web', + 'span.kind' => 'server' + }.merge(tags.stringify_keys) + + Labkit::Tracing.with_tracing(operation_name: name, tags: span_tags, &block) + end + def graphql_duration_seconds @graphql_duration_seconds ||= Gitlab::Metrics.histogram( :graphql_duration_seconds, diff --git a/spec/lib/gitlab/graphql/generic_tracing_spec.rb b/spec/lib/gitlab/graphql/generic_tracing_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..ae92dcc40af5bbde2e1fc0e3a4a28c95731c68c3 --- /dev/null +++ b/spec/lib/gitlab/graphql/generic_tracing_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Graphql::GenericTracing do + let(:graphql_duration_seconds_histogram) { double('Gitlab::Metrics::NullMetric') } + + it 'updates graphql histogram with expected labels' do + query = 'query { users { id } }' + tracer = described_class.new + + allow(tracer) + .to receive(:graphql_duration_seconds) + .and_return(graphql_duration_seconds_histogram) + + expect_metric('graphql.lex', 'lex') + expect_metric('graphql.parse', 'parse') + expect_metric('graphql.validate', 'validate') + expect_metric('graphql.analyze', 'analyze_multiplex') + expect_metric('graphql.execute', 'execute_query_lazy') + expect_metric('graphql.execute', 'execute_multiplex') + + GitlabSchema.execute(query, context: { tracers: [tracer] }) + end + + context "when labkit tracing is enabled" do + before do + expect(Labkit::Tracing).to receive(:enabled?).and_return(true) + end + + it 'yields with labkit tracing' do + expected_tags = { + 'component' => 'web', + 'span.kind' => 'server', + 'platform_key' => 'pkey', + 'key' => 'key' + } + + expect(Labkit::Tracing) + .to receive(:with_tracing) + .with(operation_name: "pkey.key", tags: expected_tags) + .and_yield + + expect { |b| described_class.new.platform_trace('pkey', 'key', nil, &b) }.to yield_control + end + end + + context "when labkit tracing is disabled" do + before do + expect(Labkit::Tracing).to receive(:enabled?).and_return(false) + end + + it 'yields without measurement' do + expect(Labkit::Tracing).not_to receive(:with_tracing) + + expect { |b| described_class.new.platform_trace('pkey', 'key', nil, &b) }.to yield_control + end + end + + private + + def expect_metric(platform_key, key) + expect(graphql_duration_seconds_histogram) + .to receive(:observe) + .with({ platform_key: platform_key, key: key }, be > 0.0) + end +end diff --git a/spec/lib/gitlab/graphql/tracing_spec.rb b/spec/lib/gitlab/graphql/tracing_spec.rb deleted file mode 100644 index 7300a9a572e5955998b313a66f2fc85c96853fc1..0000000000000000000000000000000000000000 --- a/spec/lib/gitlab/graphql/tracing_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Gitlab::Graphql::Tracing do - let(:graphql_duration_seconds_histogram) { double('Gitlab::Metrics::NullMetric') } - - it 'updates graphql histogram with expected labels' do - query = 'query { users { id } }' - tracer = described_class.new - - allow(tracer) - .to receive(:graphql_duration_seconds) - .and_return(graphql_duration_seconds_histogram) - - expect_metric('graphql.lex', 'lex') - expect_metric('graphql.parse', 'parse') - expect_metric('graphql.validate', 'validate') - expect_metric('graphql.analyze', 'analyze_multiplex') - expect_metric('graphql.execute', 'execute_query_lazy') - expect_metric('graphql.execute', 'execute_multiplex') - - GitlabSchema.execute(query, context: { tracers: [tracer] }) - end - - private - - def expect_metric(platform_key, key) - expect(graphql_duration_seconds_histogram) - .to receive(:observe) - .with({ platform_key: platform_key, key: key }, be > 0.0) - end -end