Skip to content

Commit

Permalink
[PLATFORM-991]: graphql.request.query and graphql.request.variables a…
Browse files Browse the repository at this point in the history
…re not extracted (#83)
  • Loading branch information
MaeIsBad authored Mar 6, 2023
1 parent 7d21519 commit 38f1e60
Show file tree
Hide file tree
Showing 11 changed files with 347 additions and 210 deletions.
26 changes: 12 additions & 14 deletions lib/instrumentation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defmodule OpentelemetryAbsinthe.Instrumentation do
(you can still call `OpentelemetryAbsinthe.Instrumentation.setup()` in your application startup
code, it just won't do anything.)
"""
alias Absinthe.Blueprint

require OpenTelemetry.Tracer, as: Tracer
require Record
Expand Down Expand Up @@ -55,15 +56,16 @@ defmodule OpentelemetryAbsinthe.Instrumentation do
end

def handle_operation_start(_event_name, _measurements, metadata, config) do
params = metadata |> Map.get(:options, []) |> Keyword.get(:params, %{})
document = metadata.blueprint.input
variables = metadata |> Map.get(:options, []) |> Keyword.get(:variables, %{})

attributes =
[]
|> put_if(
config.trace_request_variables,
{"graphql.request.variables", Jason.encode!(params["variables"])}
{"graphql.request.variables", Jason.encode!(variables)}
)
|> put_if(config.trace_request_query, {"graphql.request.query", params["query"]})
|> put_if(config.trace_request_query, {"graphql.request.query", document})

save_parent_ctx()

Expand Down Expand Up @@ -99,17 +101,13 @@ defmodule OpentelemetryAbsinthe.Instrumentation do
:ok
end

defp get_graphql_selections(data) do
case data do
%{blueprint: %{operations: [_ | _] = operations}} ->
operations
|> Enum.flat_map(& &1.selections)
|> Enum.map(& &1.name)
|> Enum.uniq()

_ ->
[]
end
defp get_graphql_selections(%{blueprint: %Blueprint{} = blueprint}) do
blueprint
|> Blueprint.current_operation()
|> Kernel.||(%{})
|> Map.get(:selections, [])
|> Enum.map(& &1.name)
|> Enum.uniq()
end

# Surprisingly, that doesn't seem to by anything in the stdlib to conditionally
Expand Down
13 changes: 10 additions & 3 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,23 @@ defmodule OpentelemetryAbsinthe.MixProject do
app: :opentelemetry_absinthe,
version: "1.1.0",
elixir: "~> 1.11",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
deps: deps(),
dialyzer: [
# Since absinthe is an optional dependency we need to tell dialyxir to include it
plt_add_apps: [:absinthe]
],
package: package(),
aliases: aliases(),
description: description()
]
end

# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]

def application do
[
extra_applications: [:logger]
Expand All @@ -22,7 +31,7 @@ defmodule OpentelemetryAbsinthe.MixProject do

defp deps do
[
{:absinthe, ">= 1.5.0", optional: true},
{:absinthe, "~> 1.7.0", optional: true},
{:jason, "~> 1.2"},
{:opentelemetry_api, "~> 1.1"},
{:telemetry, "~> 0.4 or ~> 1.0.0"}
Expand All @@ -31,10 +40,8 @@ defmodule OpentelemetryAbsinthe.MixProject do

defp dev_deps do
[
{:absinthe_plug, "~> 1.5", only: :test},
{:opentelemetry, "~> 1.1", only: :test},
{:opentelemetry_exporter, "~> 1.1", only: :test},
{:plug_cowboy, "~> 2.2", only: :test},
{:credo, "~> 1.4", only: [:dev, :test]},
{:dialyxir, "~> 1.0", only: [:dev, :test], runtime: false},
{:ex_doc, ">= 0.0.0", only: :dev, runtime: false}
Expand Down
9 changes: 0 additions & 9 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
%{
"absinthe": {:hex, :absinthe, "1.7.0", "36819e7b1fd5046c9c734f27fe7e564aed3bda59f0354c37cd2df88fd32dd014", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0 or ~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "566a5b5519afc9b29c4d367f0c6768162de3ec03e9bf9916f9dc2bcbe7c09643"},
"absinthe_plug": {:hex, :absinthe_plug, "1.5.8", "38d230641ba9dca8f72f1fed2dfc8abd53b3907d1996363da32434ab6ee5d6ab", [:mix], [{:absinthe, "~> 1.5", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bbb04176647b735828861e7b2705465e53e2cf54ccf5a73ddd1ebd855f996e5a"},
"acceptor_pool": {:hex, :acceptor_pool, "1.0.0", "43c20d2acae35f0c2bcd64f9d2bde267e459f0f3fd23dab26485bf518c281b21", [:rebar3], [], "hexpm", "0cbcd83fdc8b9ad2eee2067ef8b91a14858a5883cb7cd800e6fcd5803e158788"},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"},
"chatterbox": {:hex, :ts_chatterbox, "0.12.0", "4e54f199e15c0320b85372a24e35554a2ccfc4342e0b7cd8daed9a04f9b8ef4a", [:rebar3], [{:hpack, "~>0.2.3", [hex: :hpack_erl, repo: "hexpm", optional: false]}], "hexpm", "6478c161bc60244f41cd5847cc3accd26d997883e9f7facd36ff24533b2fa579"},
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"},
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
"credo": {:hex, :credo, "1.6.6", "f51f8d45db1af3b2e2f7bee3e6d3c871737bda4a91bff00c5eec276517d1a19c", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "625520ce0984ee0f9f1f198165cd46fa73c1e59a17ebc520038b8fce056a5bdc"},
"ctx": {:hex, :ctx, "0.6.0", "8ff88b70e6400c4df90142e7f130625b82086077a45364a78d208ed3ed53c7fe", [:rebar3], [], "hexpm", "a14ed2d1b67723dbebbe423b28d7615eb0bdcba6ff28f2d1f1b0a7e1d4aa5fc2"},
"dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"},
Expand All @@ -21,15 +17,10 @@
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
"mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"},
"nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"},
"opentelemetry": {:hex, :opentelemetry, "1.1.1", "02de53d7dcafc087793ddf98cac946aaaa13c99cb6a7e568d9bb5ce4552b340e", [:rebar3], [{:opentelemetry_api, "~> 1.1", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "43a807d536bca55542731ddb5ecf68c0b3b433ff98713a6496058075bac70031"},
"opentelemetry_api": {:hex, :opentelemetry_api, "1.1.0", "156366bfbf249f54daf2626e087e29ad91201eab670993fd9ae1bd278d03a096", [:mix, :rebar3], [], "hexpm", "e0d0b49e21e5785da675c97104c385283cae84fcc0d8522932a5dcf55489ead1"},
"opentelemetry_exporter": {:hex, :opentelemetry_exporter, "1.2.0", "c78a4fecba55a54ed2d4559f55addb88b37fc31820d7d0b2964aaebccd8b0614", [:rebar3], [{:grpcbox, ">= 0.0.0", [hex: :grpcbox, repo: "hexpm", optional: false]}, {:opentelemetry, "~> 1.1", [hex: :opentelemetry, repo: "hexpm", optional: false]}, {:opentelemetry_api, "~> 1.1", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:tls_certificate_check, "~> 1.11", [hex: :tls_certificate_check, repo: "hexpm", optional: false]}], "hexpm", "358d13805ef9f0521160ccca4ab533d3c8b1ca7561f72a90d3dd7ef30877c159"},
"plug": {:hex, :plug, "1.13.6", "187beb6b67c6cec50503e940f0434ea4692b19384d47e5fdfd701e93cadb4cc2", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02b9c6b9955bce92c829f31d6284bf53c591ca63c4fb9ff81dfd0418667a34ff"},
"plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"},
"plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"},
"tls_certificate_check": {:hex, :tls_certificate_check, "1.15.0", "1c0377617a1111000bca3f4cd530b62690c9bd2dc9b868b4459203cd4d7f16ab", [:rebar3], [{:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "87fd2e865078fdf8913a8c27bd8fe2be986383e31011f21d7f92cc5f7bc90731"},
Expand Down
57 changes: 57 additions & 0 deletions test/configuration_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
defmodule OpentelemetryAbsintheTest.Configuration do
use OpentelemetryAbsintheTest.Case

alias OpentelemetryAbsintheTest.Support.GraphQL.Queries
alias OpentelemetryAbsintheTest.Support.Query

doctest OpentelemetryAbsinthe.Instrumentation

describe "trace configuration" do
test "records all graphql stuff in attributes by default" do
OpentelemetryAbsinthe.Instrumentation.setup()

attributes = Query.query_for_attrs(Queries.query(), variables: %{"isbn" => "A1"})

assert [
"graphql.request.query",
"graphql.request.selections",
"graphql.request.variables",
"graphql.response.errors",
"graphql.response.result"
] = attributes |> Map.keys() |> Enum.sort()
end

test "gives options provided via application env have precedence over defaults" do
Application.put_env(:opentelemetry_absinthe, :trace_options,
trace_request_query: false,
trace_response_result: false
)

OpentelemetryAbsinthe.Instrumentation.setup()
attributes = Query.query_for_attrs(Queries.query(), variables: %{"isbn" => "A1"})

assert [
"graphql.request.selections",
"graphql.request.variables",
"graphql.response.errors"
] = attributes |> Map.keys() |> Enum.sort()
end

test "gives options provided to setup() precedence over defaults and application env" do
Application.put_env(:opentelemetry_absinthe, :trace_options,
trace_request_query: false,
trace_response_result: false
)

OpentelemetryAbsinthe.Instrumentation.setup(trace_request_query: true)
attributes = Query.query_for_attrs(Queries.query(), variables: %{"isbn" => "A1"})

assert [
"graphql.request.query",
"graphql.request.selections",
"graphql.request.variables",
"graphql.response.errors"
] = attributes |> Map.keys() |> Enum.sort()
end
end
end
105 changes: 105 additions & 0 deletions test/extraction_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
defmodule OpentelemetryAbsintheTest.Extraction do
use OpentelemetryAbsintheTest.Case

alias OpentelemetryAbsintheTest.Support.GraphQL.Queries
alias OpentelemetryAbsintheTest.Support.Query

describe "extracts" do
test "request query" do
OpentelemetryAbsinthe.Instrumentation.setup(trace_request_query: true)
query = Queries.query()

assert ^query = query |> Query.query_for_attrs() |> Map.fetch!("graphql.request.query")
end

test "request variables" do
OpentelemetryAbsinthe.Instrumentation.setup(trace_request_variables: true)
variables = %{"isbn" => "A1", "author" => "Mara Bos"}

assert ^variables =
Queries.query()
|> Query.query_for_attrs(variables: variables)
|> Map.fetch!("graphql.request.variables")
|> Jason.decode!()
end

test "request selections" do
OpentelemetryAbsinthe.Instrumentation.setup(trace_request_selections: true)

assert ["book"] =
Queries.query()
|> Query.query_for_attrs(variables: %{"isbn" => "A1"})
|> Map.fetch!("graphql.request.selections")
|> Jason.decode!()
end

test "request selections on a mutation" do
OpentelemetryAbsinthe.Instrumentation.setup(trace_request_selections: true)

assert ["create_book"] =
Queries.mutation()
|> Query.query_for_attrs(variables: %{"isbn" => "A1"})
|> Map.fetch!("graphql.request.selections")
|> Jason.decode!()
end

test "aliased request selections as their un-aliased name" do
OpentelemetryAbsinthe.Instrumentation.setup(trace_request_selections: true)

assert ["book"] =
Queries.aliased_query()
|> Query.query_for_attrs(variables: %{"isbn" => "A1"})
|> Map.fetch!("graphql.request.selections")
|> Jason.decode!()
end

test "request selections on multiple queries" do
OpentelemetryAbsinthe.Instrumentation.setup(trace_request_selections: true)

assert ["book"] =
Queries.batch_queries()
|> Query.query_for_attrs(variables: %{"isbn" => "A1"}, operation_name: "OperationOne")
|> Map.fetch!("graphql.request.selections")
|> Jason.decode!()

assert ["books"] =
Queries.batch_queries()
|> Query.query_for_attrs(variables: %{"isbn" => "A1"}, operation_name: "OperationTwo")
|> Map.fetch!("graphql.request.selections")
|> Jason.decode!()
end

test "response result" do
OpentelemetryAbsinthe.Instrumentation.setup(trace_response_results: true)

result =
Queries.query()
|> Query.query_for_attrs(variables: %{"isbn" => "A1"})
|> Map.fetch!("graphql.response.result")
|> Jason.decode!()

assert %{"data" => %{"book" => %{"author" => %{"age" => 18, "name" => "Ale Ali"}, "title" => "Fire"}}} = result
end

test "response errors" do
OpentelemetryAbsinthe.Instrumentation.setup(trace_response_errors: true)

errors =
Queries.query()
|> Query.query_for_attrs()
|> Map.fetch!("graphql.response.errors")
|> Jason.decode!()

assert [
%{
"locations" => [%{"column" => 8, "line" => 2}],
"message" => "In argument \"isbn\": Expected type \"String!\", found null."
},
%{
"locations" => [%{"column" => 7, "line" => 1}],
"message" => "Variable \"isbn\": Expected non-null, found null."
}
] = errors
end
end
end
Loading

0 comments on commit 38f1e60

Please sign in to comment.