Commit 70819379 authored by Paul Slaughter's avatar Paul Slaughter

Add ApplicationContextTracer to Graphql Schema

- This helps set up the logging and metrics tracer
parent 3bbc4ef3
......@@ -11,6 +11,7 @@ class GitlabSchema < GraphQL::Schema
AUTHENTICATED_MAX_DEPTH = 20
# Tracers (order is important)
use Gitlab::Graphql::Tracers::ApplicationContextTracer
use Gitlab::Graphql::Tracers::LoggerTracer
use Gitlab::Graphql::GenericTracing # Old tracer which will be removed eventually
use Gitlab::Graphql::Tracers::TimerTracer
......
# frozen_string_literal: true
module Gitlab
module Graphql
module Tracers
# This graphql-ruby tracer sets up `ApplicationContext` for certain operations.
class ApplicationContextTracer
def self.use(schema)
schema.tracer(self.new)
end
# See docs on expected interface for trace
# https://graphql-ruby.org/api-doc/1.12.17/GraphQL/Tracing
def trace(key, data)
case key
when "execute_query"
operation = known_operation(data)
::Gitlab::ApplicationContext.with_context(caller_id: operation.to_caller_id) do
yield
end
else
yield
end
end
private
def known_operation(data)
# The library guarantees that we should have :query for execute_query, but we're being defensive here
query = data.fetch(:query, nil)
return ::Gitlab::Graphql::KnownOperations.UNKNOWN unless query
::Gitlab::Graphql::KnownOperations.default.from_query(query)
end
end
end
end
end
# frozen_string_literal: true
require "fast_spec_helper"
require "support/graphql/fake_tracer"
require "support/graphql/fake_query_type"
RSpec.describe Gitlab::Graphql::Tracers::ApplicationContextTracer do
let(:tracer_spy) { spy('tracer_spy') }
let(:default_known_operations) { ::Gitlab::Graphql::KnownOperations.new(['fooOperation']) }
let(:dummy_schema) do
schema = Class.new(GraphQL::Schema) do
use Gitlab::Graphql::Tracers::ApplicationContextTracer
query Graphql::FakeQueryType
end
fake_tracer = Graphql::FakeTracer.new(lambda do |key, *args|
tracer_spy.trace(key, Gitlab::ApplicationContext.current)
end)
schema.tracer(fake_tracer)
schema
end
before do
allow(::Gitlab::Graphql::KnownOperations).to receive(:default).and_return(default_known_operations)
end
it "sets application context during execute_query and cleans up afterwards", :aggregate_failures do
dummy_schema.execute("query fooOperation { helloWorld }")
# "parse" is just an arbitrary trace event that isn't setting caller_id
expect(tracer_spy).to have_received(:trace).with("parse", hash_excluding("meta.caller_id"))
expect(tracer_spy).to have_received(:trace).with("execute_query", hash_including("meta.caller_id" => "graphql:fooOperation")).once
expect(Gitlab::ApplicationContext.current).not_to include("meta.caller_id")
end
it "sets caller_id when operation is not known" do
dummy_schema.execute("query fuzz { helloWorld }")
expect(tracer_spy).to have_received(:trace).with("execute_query", hash_including("meta.caller_id" => "graphql:unknown")).once
end
end
......@@ -15,7 +15,7 @@ RSpec.describe 'GraphQL' do
let(:expected_execute_query_log) do
{
"correlation_id" => kind_of(String),
"meta.caller_id" => "GraphqlController#execute",
"meta.caller_id" => "graphql:anonymous",
"meta.client_id" => kind_of(String),
"meta.feature_category" => "not_owned",
"meta.remote_ip" => kind_of(String),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment