Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add telemetry events to async middleware #1169

Merged

Conversation

andrewhr
Copy link
Contributor

@andrewhr andrewhr commented May 7, 2022

Introduce telemetry events to Async middleware to instrument new Task.async/1 created inside the middleware.

The use-case for this event comes from OpenTelemetry and trace propagation. For OTel, we need to run instrumentation from inside the newly created Task to be able to connect spans. With this event in place, we can track those Tasks without introducing custom wrappers on user code.

This patch adds events only in the case of the middleware creating the task. For tasks created by user code, there is nothing the library can do, unfortunately.

Introduce telemetry events to Async middleware to instrument
new `Task.async/1` created inside the middleware.

The use-case for this event comes from OpenTelemetry and trace
propagation. For OTel, we need to run instrumentation from inside
the newly created Task to be able to connect spans. With this event
in place, we can track those Tasks without introducing custom wrappers
on user code.

This patch adds events only in the case of the middleware creating the
task. For tasks created by user code, there is nothing the library can
do, unfortunately.
@@ -75,12 +75,39 @@ defmodule Absinthe.Middleware.AsyncTest do
assert {:ok, %{data: %{"asyncBareThing" => "bare task"}}} == Absinthe.run(doc, Schema)
end

test "can resolve a field using the normal test helper" do
test "can resolve a field using the normal test helper and emit telemetry event", %{test: test} do
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I extended this existing test with extra telemetry. I'm happy to change to a separate test OR add telemetry assertions on the existing ones - when applicable.

@benwilson512 benwilson512 merged commit 453fd12 into absinthe-graphql:master May 8, 2022
@benwilson512
Copy link
Contributor

Great addition, thanks!

@andrewhr andrewhr deleted the async-middleware-telemetry branch May 9, 2022 01:47
andrewhr added a commit to andrewhr/absinthe that referenced this pull request May 9, 2022
With a similar rationale from [this PR][1], tweak the telemetry events
from batch middleware.

The existing event contract stays the same, but move to run from inside
the Task used for batch execution. There is a small semantic difference
of when the :stop event fires - this patch sends the event at the end of
the task, while the current form may have a delay/sync caused by Task
await.

A complementary event is added as well to announce when the Resolver
continuation - the post batch - happens. Given that piece is part of the
resolver, the resolution struct is included as part of the metadata.

[1]: absinthe-graphql#1169
andrewhr added a commit to andrewhr/opentelemetry-erlang-contrib that referenced this pull request May 27, 2022
Add instrumentation for `Absinthe`, the GraphQL Elixir-framwork. Relies on
some new telemetry work on Absinthe:
* [Added telemetry for async helper][1], used to propagate traces
* [Improved telemetry for batch helper][2], used to propagate traces
* [Tweaked pipeline instrumentation][3], that splits parse/validate/execute
  phases, following the approach of [JavaScript libraries][4]

Span names and attributes also follow the [JavaScript impl][4], the
closes to a future [Semantic Attribute][5] spec.

The "span tracker" used here is to connect traces in a shape that
resembles the query shape instead of execution shape. One example is:

```
query {
  users {
    name
  }
}
```

In case `name` is an async resolver (for example), the execution will
resembles a recursive function, and such our trace will be:

```
RootQueryType.users
  User.name
    User.name
      User.name
```

With the span tracker, the above trace will become:

```
RootQueryType.users
  User.name
  User.name
  User.name
```

That helps visually scan the traces, and it's friendly to folks who
doesn't know much about Absinthe internals.

[1]: absinthe-graphql/absinthe#1169
[2]: absinthe-graphql/absinthe#1170
[3]: absinthe-graphql/absinthe#1172
[4]: https://www.npmjs.com/package/@opentelemetry/instrumentation-graphql
[5]: open-telemetry/opentelemetry-specification#2456
andrewhr added a commit to andrewhr/absinthe that referenced this pull request Jun 15, 2022
With a similar rationale from [this PR][1], tweak the telemetry events
from batch middleware.

The existing event contract stays the same, but move to run from inside
the Task used for batch execution. There is a small semantic difference
of when the :stop event fires - this patch sends the event at the end of
the task, while the current form may have a delay/sync caused by Task
await.

A complementary event is added as well to announce when the Resolver
continuation - the post batch - happens. Given that piece is part of the
resolver, the resolution struct is included as part of the metadata.

[1]: absinthe-graphql#1169
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants