graphql: data dog instrumentation

closes RECNVS-325

Test plan:
  * do something to monitor statsd traffic (maybe
    `nc -kul 8125`?)
  * queries written in graphiql should not be instrumented
  * student context card queries should be logged

Change-Id: Ie86075b739df36e49b5f9ebcf320e50f8c140ecc
Reviewed-on: https://gerrit.instructure.com/141965
Tested-by: Jenkins
Reviewed-by: Jonathan Featherstone <jfeatherstone@instructure.com>
QA-Review: Collin Parrish <cparrish@instructure.com>
Product-Review: Cameron Matheson <cameron@instructure.com>
This commit is contained in:
Cameron Matheson 2018-02-26 16:05:10 -07:00
parent c2f729c303
commit 29e1b69f06
5 changed files with 54 additions and 1 deletions

View File

@ -163,3 +163,4 @@ gem 'twitter', path: 'gems/twitter'
gem 'vericite_api', '1.5.3'
gem 'utf8_cleaner', path: 'gems/utf8_cleaner'
gem 'workflow', path: 'gems/workflow'
gem 'dogstatsd-ruby', '3.3.0'

View File

@ -4,22 +4,32 @@ class GraphQLController < ApplicationController
before_action :require_user, except: :execute
before_action :require_graphql_feature_flag
def execute
query = params[:query]
variables = params[:variables] || {}
tracers = if request.headers["GraphQL-Metrics"] == "true"
domain = request.host_with_port.sub(':', '_')
[Tracers::DatadogTracer.new(domain)]
else
[]
end
context = {
current_user: @current_user,
session: session,
request: request,
tracers: tracers
}
result = nil
ActiveRecord::Base.transaction do
timeout = Integer(Setting.get('graphql_statement_timeout', '60_000'))
ActiveRecord::Base.connection.execute "SET statement_timeout = #{timeout}"
result = CanvasSchema.execute(query, variables: variables, context: context)
render json: result
end
render json: result
end
def graphiql

View File

@ -0,0 +1,28 @@
require 'datadog/statsd'
module Tracers
class DatadogTracer
def initialize(domain)
@domain = domain
@statsd = Datadog::Statsd.new('localhost', 8125)
end
def trace(key, metadata)
if key == "execute_query"
@statsd.batch do |statsd|
query_name = metadata[:query].operation_name || "unnamed"
tags = [
"query_md5:#{Digest::MD5.hexdigest(metadata[:query].query_string)}",
"domain:#@domain",
]
statsd.increment("graphql.#{query_name}.count", tags: tags)
statsd.time("graphql.#{query_name}.time", tags: tags) do
yield
end
end
else
yield
end
end
end
end

View File

@ -10,6 +10,7 @@ const client = new ApolloClient({
opts: {
headers: {
'X-Requested-With': 'XMLHttpRequest',
'GraphQL-Metrics': true,
'X-CSRF-Token': $.cookie('_csrf_token') // TODO: probably need to move this io a middleware (http://dev.apollodata.com/core/network.html)
},
credentials: 'same-origin'

View File

@ -62,5 +62,18 @@ describe GraphQLController do
post :execute, params: {query: "{}"}
expect(JSON.parse(response.body)["errors"]).not_to be_blank
end
context "data dog metrics" do
it "reports data dog metrics if requested" do
expect_any_instance_of(Tracers::DatadogTracer).to receive :trace
request.headers["GraphQL-Metrics"] = "true"
post :execute, params: {query: '{legacyNode(User, 1) { id }'}
end
it "doesn't report normally" do
expect_any_instance_of(Tracers::DatadogTracer).not_to receive :trace
post :execute, params: {query: '{legacyNode(User, 1) { id }'}
end
end
end
end