Revert "replace graphQL legacy tracer with official version"
This reverts commit 0975b499d1
.
Reason for revert: needs environment change first
Change-Id: I112b37aa92f825e43240dd49225eef887fa50fb1
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/357034
Reviewed-by: Isaac Moore <isaac.moore@instructure.com>
Build-Review: Isaac Moore <isaac.moore@instructure.com>
Tested-by: Aaron Ogata <aogata@instructure.com>
QA-Review: Aaron Ogata <aogata@instructure.com>
Product-Review: Aaron Ogata <aogata@instructure.com>
This commit is contained in:
parent
6addd9afe6
commit
2fdc82c631
|
@ -68,6 +68,12 @@ class GraphQLController < ApplicationController
|
|||
in_app: in_app?,
|
||||
deleted_models: {},
|
||||
request_id: (Thread.current[:context] || {})[:request_id],
|
||||
tracers: [
|
||||
Tracers::DatadogTracer.new(
|
||||
request.headers["GraphQL-Metrics"] == "true",
|
||||
request.host_with_port.sub(":", "_")
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
Timeout.timeout(1.minute) do
|
||||
|
|
|
@ -18,13 +18,11 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require "datadog/auto_instrument"
|
||||
|
||||
class CanvasSchema < GraphQL::Schema
|
||||
query Types::QueryType
|
||||
mutation Types::MutationType
|
||||
trace_with GraphQL::Tracing::DataDogTrace if Rails.env.production?
|
||||
trace_with GraphQL::Tracing::SentryTrace if Rails.env.production?
|
||||
trace_with GraphQL::Tracing::CallLegacyTracers
|
||||
trace_with GraphQL::Tracing::SentryTrace
|
||||
|
||||
use GraphQL::Batch
|
||||
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# Copyright (C) 2018 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require "datadog/statsd"
|
||||
|
||||
module Tracers
|
||||
class DatadogTracer
|
||||
def initialize(first_party, domain)
|
||||
@third_party = !first_party
|
||||
@domain = domain
|
||||
end
|
||||
|
||||
def trace(key, metadata, &)
|
||||
if key == "validate"
|
||||
tags = {}
|
||||
|
||||
tags[:operation_name] = @third_party ? "3rdparty" : metadata[:query].operation_name || "unnamed"
|
||||
|
||||
op, fields = op_type_and_fields(metadata)
|
||||
fields.each do |field|
|
||||
InstStatsd::Statsd.increment("graphql.#{op}.count", tags: tags.merge(field:))
|
||||
end
|
||||
InstStatsd::Statsd.increment("graphql.operation.count", tags:)
|
||||
InstStatsd::Statsd.time("graphql.operation.time", tags:, &)
|
||||
else
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
# easiest to describe what this does by example. if the operation is:
|
||||
# query MyQuery {
|
||||
# course(id: "1") { name }
|
||||
# legacyNode(type: User, id: "5") { sisId }
|
||||
# }
|
||||
# then this will return ["query", ["course", "legacyNode"]]
|
||||
#
|
||||
# if the operation is:
|
||||
# mutation MyMutation {
|
||||
# createAssignment(input: {courseId: "1", name: "Do my bidding"}) {
|
||||
# assignment {
|
||||
# name
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# then this will return ["mutation", ["createAssignment"]]
|
||||
def op_type_and_fields(metadata)
|
||||
op = metadata[:query].selected_operation
|
||||
op_type = op.operation_type || "query"
|
||||
[op_type, op.selections.map(&:name)]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -10,7 +10,6 @@ services:
|
|||
- dynamodb
|
||||
environment:
|
||||
DB_VALIDITY_ENSURED: 1
|
||||
DD_TRACE_ENABLED: 'false'
|
||||
ENCRYPTION_KEY: facdd3a131ddd8988b14f6e4e01039c93cfa0160
|
||||
RAILS_ENV: test
|
||||
POSTGRES_PASSWORD: $POSTGRES_PASSWORD
|
||||
|
|
|
@ -194,6 +194,83 @@ describe GraphQLController do
|
|||
create_discussion_entry("Post 1")
|
||||
end
|
||||
end
|
||||
|
||||
context "datadog metrics" do
|
||||
before { allow(InstStatsd::Statsd).to receive(:increment).and_call_original }
|
||||
|
||||
def expect_increment(metric, tags)
|
||||
expect(InstStatsd::Statsd).to have_received(:increment).with(metric, tags:)
|
||||
end
|
||||
|
||||
context "for first-party queries" do
|
||||
def mark_first_party(request)
|
||||
request.headers["GraphQL-Metrics"] = "true"
|
||||
end
|
||||
|
||||
it "counts each operation and query top-level field" do
|
||||
mark_first_party(request)
|
||||
test_query = <<~GQL
|
||||
query GetStuff {
|
||||
course(id: "1") { name }
|
||||
assignment(id: "1") { name }
|
||||
legacyNode(type: User, id: "1") {
|
||||
... on User { email }
|
||||
}
|
||||
}
|
||||
GQL
|
||||
post :execute, params: { query: test_query }, format: :json
|
||||
expect_increment("graphql.operation.count", operation_name: "GetStuff")
|
||||
expect_increment("graphql.query.count", operation_name: "GetStuff", field: "course")
|
||||
expect_increment("graphql.query.count", operation_name: "GetStuff", field: "assignment")
|
||||
expect_increment("graphql.query.count", operation_name: "GetStuff", field: "legacyNode")
|
||||
end
|
||||
|
||||
it "counts unnamed operations" do
|
||||
mark_first_party(request)
|
||||
test_query = <<~GQL
|
||||
query {
|
||||
course(id: "1") { name }
|
||||
assignment(id: "1") { name }
|
||||
}
|
||||
GQL
|
||||
post :execute, params: { query: test_query }, format: :json
|
||||
expect_increment("graphql.operation.count", operation_name: "unnamed")
|
||||
expect_increment("graphql.query.count", operation_name: "unnamed", field: "course")
|
||||
expect_increment("graphql.query.count", operation_name: "unnamed", field: "assignment")
|
||||
end
|
||||
|
||||
it "counts each mutation top-level field" do
|
||||
mark_first_party(request)
|
||||
test_query = <<~GQL
|
||||
mutation {
|
||||
createAssignment(input: {courseId: "1", name: "Do my bidding"}) {
|
||||
assignment { name }
|
||||
}
|
||||
updateAssignment(input: {id: "1", name: "Do it good"}) {
|
||||
assignment { name }
|
||||
}
|
||||
}
|
||||
GQL
|
||||
post :execute, params: { query: test_query }, format: :json
|
||||
expect_increment("graphql.operation.count", operation_name: "unnamed")
|
||||
expect_increment("graphql.mutation.count", operation_name: "unnamed", field: "createAssignment")
|
||||
expect_increment("graphql.mutation.count", operation_name: "unnamed", field: "updateAssignment")
|
||||
end
|
||||
end
|
||||
|
||||
context "for third-party queries" do
|
||||
it "names all operations '3rdparty' and omits hashes" do
|
||||
test_query = <<~GQL
|
||||
query GetStuff {
|
||||
course(id: "1") { name }
|
||||
}
|
||||
GQL
|
||||
post :execute, params: { query: test_query }, format: :json
|
||||
expect_increment("graphql.operation.count", operation_name: "3rdparty")
|
||||
expect_increment("graphql.query.count", operation_name: "3rdparty", field: "course")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "subgraph_execute" do
|
||||
|
|
Loading…
Reference in New Issue