Skip to content

Commit

Permalink
[PLATFORM-1689]: Attach to subscription publish events (#148)
Browse files Browse the repository at this point in the history
  • Loading branch information
cpiemontese authored Apr 18, 2024
1 parent 329f138 commit 91a1f79
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 25 deletions.
3 changes: 3 additions & 0 deletions .versions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
files:
- path: mix.exs
pattern: '@version \"{version}\"'
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

---

## [2.2.2-rc.0] - 2024-04-18

### Added

- Allow attaching to `[:absinthe, :subscription, :publish]` (both `:start` and `:stop`) given a `trace_subscription: true` config
- New `graphql.event.type` trace attribute, with value `operation` or `publish`

## [2.2.1] - 2024-02-21

### Changed
Expand Down Expand Up @@ -64,7 +73,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
If you're upgrading to opentelemetry_absinthe 1.1.0, it is therefore recommended to also upgrade to OpenTelemetry API 1.1.0
in order to keep the opentelemetry log metadata.

[Unreleased]: https://github.com/primait/opentelemetry_absinthe/compare/2.0.1...HEAD

[Unreleased]: https://github.com/primait/opentelemetry_absinthe/compare/2.2.2-rc.0...HEAD
[2.2.2-rc.0]: https://github.com/primait/opentelemetry_absinthe/compare/2.2.1...2.2.2-rc.0
[2.0.0]: https://github.com/primait/opentelemetry_absinthe/compare/2.0.0...2.0.1
[2.0.0]: https://github.com/primait/opentelemetry_absinthe/compare/1.1.0...2.0.0
[1.1.0]: https://github.com/primait/opentelemetry_absinthe/compare/1.0.0...1.1.0
51 changes: 36 additions & 15 deletions lib/instrumentation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ defmodule OpentelemetryAbsinthe.Instrumentation do
require Logger
require Record

@telemetry [:opentelemetry_absinthe, :graphql, :handled]

@type graphql_handled_event_metadata :: %{
operation_name: String.t() | nil,
operation_type: :query | :mutation,
Expand Down Expand Up @@ -54,7 +52,8 @@ defmodule OpentelemetryAbsinthe.Instrumentation do
trace_request_variables: false,
trace_request_selections: true,
trace_response_result: false,
trace_response_errors: false
trace_response_errors: false,
trace_subscriptions: false
]

def setup(instrumentation_opts \\ []) do
Expand All @@ -68,27 +67,45 @@ defmodule OpentelemetryAbsinthe.Instrumentation do
Logger.warning("The opentelemetry_absinthe span_name option is deprecated and will be removed in the future")
end

:telemetry.attach(
telemetry_provider().attach(
{__MODULE__, :operation_start},
[:absinthe, :execute, :operation, :start],
&__MODULE__.handle_operation_start/4,
config
&__MODULE__.handle_start/4,
Map.put(config, :type, :operation)
)

:telemetry.attach(
telemetry_provider().attach(
{__MODULE__, :operation_stop},
[:absinthe, :execute, :operation, :stop],
&__MODULE__.handle_operation_stop/4,
config
&__MODULE__.handle_stop/4,
Map.put(config, :type, :operation)
)

if config.trace_subscriptions do
telemetry_provider().attach(
{__MODULE__, :publish_start},
[:absinthe, :subscription, :publish, :start],
&__MODULE__.handle_start/4,
Map.put(config, :type, :publish)
)

telemetry_provider().attach(
{__MODULE__, :publish_stop},
[:absinthe, :subscription, :publish, :stop],
&__MODULE__.handle_stop/4,
Map.put(config, :type, :publish)
)
end
end

def teardown do
:telemetry.detach({__MODULE__, :operation_start})
:telemetry.detach({__MODULE__, :operation_stop})
telemetry_provider().detach({__MODULE__, :operation_start})
telemetry_provider().detach({__MODULE__, :operation_stop})
telemetry_provider().detach({__MODULE__, :publish_start})
telemetry_provider().detach({__MODULE__, :publish_stop})
end

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

Expand All @@ -99,6 +116,7 @@ defmodule OpentelemetryAbsinthe.Instrumentation do
{:"graphql.request.variables", Jason.encode!(variables)}
)
|> put_if(config.trace_request_query, {@graphql_document, document})
|> List.insert_at(0, {:"graphql.event.type", config.type})

save_parent_ctx()

Expand All @@ -108,7 +126,7 @@ defmodule OpentelemetryAbsinthe.Instrumentation do
Tracer.set_current_span(new_ctx)
end

def handle_operation_stop(_event_name, measurements, data, config) do
def handle_stop(_event_name, measurements, data, config) do
operation_type = get_operation_type(data)
operation_name = get_operation_name(data)

Expand All @@ -129,10 +147,11 @@ defmodule OpentelemetryAbsinthe.Instrumentation do
config.trace_request_selections,
fn -> {:"graphql.request.selections", data |> get_graphql_selections() |> Jason.encode!()} end
)
|> List.insert_at(0, {:"graphql.event.type", config.type})
|> Tracer.set_attributes()

:telemetry.execute(
@telemetry,
telemetry_provider().execute(
[:opentelemetry_absinthe, :graphql, :handled],
measurements,
%{
operation_name: operation_name,
Expand Down Expand Up @@ -202,4 +221,6 @@ defmodule OpentelemetryAbsinthe.Instrumentation do

defp set_status(:ok), do: :ok
defp set_status(:error), do: Tracer.set_status(OpenTelemetry.status(:error, ""))

defp telemetry_provider, do: Application.get_env(:opentelemetry_absinthe, :telemetry_provider, :telemetry)
end
7 changes: 5 additions & 2 deletions lib/opentelemetry_absinthe.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ defmodule OpentelemetryAbsinthe do
config :opentelemetry_absinthe,
trace_options: [
trace_request_query: false,
trace_response_error: true
trace_response_error: true,
...
]
```
configuration can also be passed directly to the setup function
```
OpentelemetryAbsinthe.setup(
trace_request_query: false,
trace_response_error: true
trace_response_error: true,
...
)
```
Expand Down Expand Up @@ -70,6 +72,7 @@ defmodule OpentelemetryAbsinthe do
* `trace_response_result`(default: #{Keyword.fetch!(@config, :trace_response_result)}): attaches the result returned by the server as an attribute
* `trace_response_errors`(default: #{Keyword.fetch!(@config, :trace_response_errors)}): attaches the errors returned by the server as an attribute
* `trace_subscriptions`(default: #{Keyword.fetch!(@config, :trace_subscriptions)}): attaches to `[:absinthe, :subscription, :publish]` (`:start` and `:stop`)
## Telemetry
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule OpentelemetryAbsinthe.MixProject do
use Mix.Project

@source_url "https://github.com/primait/opentelemetry_absinthe"
@version "2.2.1"
@version "2.2.2-rc.0"

def project do
[
Expand Down
4 changes: 4 additions & 0 deletions test/configuration_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defmodule OpentelemetryAbsintheTest.Configuration do
@graphql_operation_name :"graphql.operation.name"
@graphql_operation_type :"graphql.operation.type"
@graphql_request_selections :"graphql.request.selections"
@graphql_event_type :"graphql.event.type"

doctest OpentelemetryAbsinthe.Instrumentation

Expand All @@ -19,6 +20,7 @@ defmodule OpentelemetryAbsintheTest.Configuration do

assert [
@graphql_document,
@graphql_event_type,
@graphql_operation_name,
@graphql_operation_type,
@graphql_request_selections
Expand All @@ -35,6 +37,7 @@ defmodule OpentelemetryAbsintheTest.Configuration do
attributes = Query.query_for_attrs(Queries.query(), variables: %{"isbn" => "A1"})

assert [
@graphql_event_type,
@graphql_operation_name,
@graphql_operation_type,
@graphql_request_selections,
Expand All @@ -53,6 +56,7 @@ defmodule OpentelemetryAbsintheTest.Configuration do

assert [
@graphql_document,
@graphql_event_type,
@graphql_operation_name,
@graphql_operation_type
] = attributes |> Map.keys() |> Enum.sort()
Expand Down
69 changes: 69 additions & 0 deletions test/event_type_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
defmodule OpentelemetryAbsintheTest.EventTypeTest do
use OpentelemetryAbsintheTest.Case

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

alias OpentelemetryAbsintheTest.EventTypeTest.TelemetryProvider

@graphql_event_type :"graphql.event.type"

doctest OpentelemetryAbsinthe.Instrumentation

test "records operation on query" do
OpentelemetryAbsinthe.Instrumentation.setup()

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

assert @graphql_event_type in Map.keys(attributes)
assert :operation == Map.get(attributes, @graphql_event_type)
end

describe "subscription" do
test "doesn't attach to subscription if not enabled" do
Application.put_env(:opentelemetry_absinthe, :telemetry_provider, TelemetryProvider)

on_exit(fn ->
Application.put_env(:opentelemetry_absinthe, :telemetry_provider, :telemetry)
end)

{:ok, _} = TelemetryProvider.start_link([])

OpentelemetryAbsinthe.Instrumentation.setup()

# Attaches only to operation start/stop
assert 2 == TelemetryProvider.count()
end

test "attaches to subscription if enabled" do
Application.put_env(:opentelemetry_absinthe, :telemetry_provider, TelemetryProvider)

on_exit(fn ->
Application.put_env(:opentelemetry_absinthe, :telemetry_provider, :telemetry)
end)

{:ok, _} = TelemetryProvider.start_link([])

OpentelemetryAbsinthe.Instrumentation.setup(trace_subscriptions: true)

# Attaches also to subscription start/stop
assert 4 == TelemetryProvider.count()
end
end
end

defmodule OpentelemetryAbsintheTest.EventTypeTest.TelemetryProvider do
use Agent

@me __MODULE__

def start_link(_opts) do
Agent.start_link(fn -> 0 end, name: @me)
end

def count, do: Agent.get(@me, & &1)

defp increment, do: Agent.update(@me, &(&1 + 1))

def attach(_, _, _, _), do: increment()
end
11 changes: 5 additions & 6 deletions test/instrumentation_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ defmodule OpentelemetryAbsintheTest.Instrumentation do

@trace_attributes [
:"graphql.document",
:"graphql.event.type",
:"graphql.operation.name",
:"graphql.operation.type",
:"graphql.request.selections",
Expand All @@ -22,13 +23,11 @@ defmodule OpentelemetryAbsintheTest.Instrumentation do
:"graphql.response.result"
]

describe "query" do
test "doesn't crash when empty" do
OpentelemetryAbsinthe.Instrumentation.setup(@capture_all)
attrs = Query.query_for_attrs(Queries.empty_query())
test "doesn't crash when query is empty" do
OpentelemetryAbsinthe.Instrumentation.setup(@capture_all)
attrs = Query.query_for_attrs(Queries.empty_query())

assert @trace_attributes = attrs |> Map.keys() |> Enum.sort()
end
assert @trace_attributes = attrs |> Map.keys() |> Enum.sort()
end

test "handles multiple queries properly" do
Expand Down

0 comments on commit 91a1f79

Please sign in to comment.