From 2a93c2d9890800a0c4b6505063c31324b69a382f Mon Sep 17 00:00:00 2001 From: Leonardo Donelli Date: Tue, 30 Jun 2020 14:45:14 +0200 Subject: [PATCH] Initial commit --- .gitignore | 24 +++++++++++++++ README.md | 3 ++ lib/helpers.ex | 56 +++++++++++++++++++++++++++++++++++ lib/opentelemetry_absinthe.ex | 5 ++++ mix.exs | 26 ++++++++++++++++ mix.lock | 6 ++++ 6 files changed, 120 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 lib/helpers.ex create mode 100644 lib/opentelemetry_absinthe.ex create mode 100644 mix.exs create mode 100644 mix.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b981cc --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +opentelemetry_absinthe-*.tar + diff --git a/README.md b/README.md new file mode 100644 index 0000000..54ab466 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# OpentelemetryAbsinthe + +OpentelemetryAbsinthe is a [OpenTelemetry](https://opentelemetry.io) instrumentation library for [Absinthe](https://github.com/absinthe-graphql/absinthe). diff --git a/lib/helpers.ex b/lib/helpers.ex new file mode 100644 index 0000000..04bfb5b --- /dev/null +++ b/lib/helpers.ex @@ -0,0 +1,56 @@ +defmodule OpentelemetryAbsinthe.Helpers do + @moduledoc """ + OpenTelemetry-friendly alternatives of Absinthe.Resolution.Helpers functions + + Some of the standard absinthe resolution helpers, like `batch` or `async`, + are not "opentelemetry-friendly": the resolvers, when invoked, lose the active span + and break the trace propagation. + + This module defines compatible alternatives that can be used in the same way, + but don't lose the trace information. + """ + + require OpenTelemetry.Tracer + alias Absinthe.Middleware.Batch + + @doc """ + Works like Absinthe.Resolution.Helpers.batch, but preserves the active span. + + The function supplied to the `batch` helper is executed in a Task by Absinthe, + which means that the erlang opentelemetry SDK would lose track of the currently + active span, because they are kept in a pdict. + + To work around this, you can just replace `batch` with `batch_keep_span`, + and the active span will be automatically passed and reset as the active one + inside the batch function. + """ + @spec batch_keep_span(Batch.batch_fun(), any(), Batch.post_batch_fun()) :: + {:middleware, Batch, term} + @spec batch_keep_span( + Batch.batch_fun(), + any(), + Batch.post_batch_fun(), + opts :: [{:timeout, pos_integer}] + ) :: {:middleware, Batch, term} + + def batch_keep_span(batch_key, batch_data, post_batch_fn) do + batch_keep_span(batch_key, batch_data, post_batch_fn, []) + end + + def batch_keep_span({module, func}, batch_data, post_batch_fn, opts) do + batch_keep_span({module, func, []}, batch_data, post_batch_fn, opts) + end + + def batch_keep_span({module, func, param}, batch_data, post_batch_fn, opts) do + span_ctx = OpenTelemetry.Tracer.current_span_ctx() + batch_key = {__MODULE__, :batch_fun_wrapper, {{module, func, param}, span_ctx}} + batch_config = {batch_key, batch_data, post_batch_fn, opts} + {:middleware, Absinthe.Middleware.Batch, batch_config} + end + + # This is executed by the Absinthe.Middleware.Batch middleware in a Task + defp batch_fun_wrapper({{module, func, param}, span}, aggregate) do + OpenTelemetry.Tracer.set_span(span) + apply(module, func, [param, aggregate]) + end +end diff --git a/lib/opentelemetry_absinthe.ex b/lib/opentelemetry_absinthe.ex new file mode 100644 index 0000000..d9fc705 --- /dev/null +++ b/lib/opentelemetry_absinthe.ex @@ -0,0 +1,5 @@ +defmodule OpentelemetryAbsinthe do + @moduledoc """ + OpentelemetryAbsinthe is an opentelemetry instrumentation library for Absinthe + """ +end diff --git a/mix.exs b/mix.exs new file mode 100644 index 0000000..f02b016 --- /dev/null +++ b/mix.exs @@ -0,0 +1,26 @@ +defmodule OpentelemetryAbsinthe.MixProject do + use Mix.Project + + def project do + [ + app: :opentelemetry_absinthe, + version: "0.1.0", + elixir: "~> 1.10", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [ + extra_applications: [:logger] + ] + end + + defp deps do + [ + {:absinthe, ">= 1.4.0"}, + {:opentelemetry_api, "~> 0.3.1"} + ] + end +end diff --git a/mix.lock b/mix.lock new file mode 100644 index 0000000..9983c41 --- /dev/null +++ b/mix.lock @@ -0,0 +1,6 @@ +%{ + "absinthe": {:hex, :absinthe, "1.5.1", "2f462f5849b2a4f72889d5a131ca6760b47ca8c5de2ba21c1dca3889634f2277", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b264eeb69605c6012f563e240edcca3d8abc5a725cab6f58ad82510a0283618b"}, + "nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"}, + "opentelemetry_api": {:hex, :opentelemetry_api, "0.3.2", "b474cd21af5855a6dfff0912f26c7c40fbf1fd05b045d8e29fd53edeb4c3ec99", [:mix, :rebar3], [], "hexpm", "39b0ef74906e5d001ad244307337d168c594c2a05b67beaddad48ceaebfee352"}, + "telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"}, +}