Home

Awesome

Opencensus.Absinthe

CircleCI Hex version badge

Extends Absinthe to automatically create OpenCensus spans. Designed to work with whatever is producing spans upstream, e.g. Opencensus.Plug.

Installation

Dependency

If you're using Absinthe.Plug, add opencensus_absinthe to your deps in mix.exs using a tighter version constraint than:

{:absinthe_plug, ">= 0.0.0"},
{:opencensus_absinthe, ">= 0.0.0"},

Pipeline

Add a :pipeline to your t:Absinthe.Plug.opts/0 to have it call Opencensus.Absinthe.Plug.traced_pipeline/2. If you're using Phoenix.Router.forward/4, for example:

forward(
  path,
  Absinthe.Plug,
  # ... existing config ...
  pipeline: {Opencensus.Absinthe.Plug, :traced_pipeline}
)

If you already have a pipeline, you can define your own and call both to insert their phases. To work with ApolloTracing, for example:

def your_custom_pipeline(config, pipeline_opts \\ []) do
  config
  |> Absinthe.Plug.default_pipeline(pipeline_opts)
  |> ApolloTracing.Pipeline.add_phases()
  |> Opencensus.Absinthe.add_phases()
end

Worst case, you'll need to copy the code from the current pipeline target and add a call to Opencensus.Absinthe.add_phases/1 as above.

Middleware

Your middleware callback needs to run its output through the matching function in Opencensus.Absinthe.Middleware to add the middleware to only the fields that need it:

def middleware(middleware, field, object) do
  Opencensus.Absinthe.middleware(middleware, field, object)
end

If you've already got some middleware, like above, you might need to copy some code around to get the job done:

def middleware(middleware, field, object) do
  ([ApolloTracing.Middleware.Tracing, ApolloTracing.Middleware.Caching] ++ middleware)
  |> Opencensus.Absinthe.middleware(field, object)
end

Schema

Until Absinthe merge and publish their telemetry support (see below) and you upgrade, you'll also need to set :trace in the metadata for any field for which you want tracing to happen:

  query do
    @desc "List all the things"
    field :things, list_of(:thing), meta: [trace: true] do
      resolve(&Resolvers.Account.all_things/2)
    end

Once you're on a telemetry-capable Absinthe, you'll get tracing for every field containing a resolve.

Verification

Check your installation with iex -S mix phx.server, assuming Phoenix, and:

iex> :oc_reporter.register(:oc_reporter_stdout)
:ok

Fire off a few requests and check the {span, <<NAME> lines on standard output.

Behaviour

Each Absinthe query runs in the process of its caller. If you hook up opencensus_plug, or something else that'll take trace details off the wire, the process dictionary will have an :oc_span_ctx_key key used by opencensus to keep track of spans in flight.

This package adds new phases to your Absinthe Pipeline to start new spans for each resolution and call, using both methods available:

opencensus provides two methods for tracking [trace and span] context, the process dictionary and a variable holding a ctx record.

Specifically, this package:

The latter is necessary because the fields don't necessarily start and stop without overlap. Naïve use of :ocp.with_child_span and :ocp.finish_span will yield incorrect traces.

Development

Dependency management:

Finding problems:

Documentation:

Next Steps

Obvious next steps include stronger tests and many minor tweaks:

The biggest looming change would be telemetry integration:

absinthe-graphql/absinthe#663 to add telemetry to Absinthe could give us start and stop calls from within the calling process suitable for calling :ocp.with_child_span and :ocp.finish_span to maintain the main trace. In turn, that'd mean we didn't need the pipeline.

#663 won't help us generate spans for fields, because there's no way to pass state back through :telemetry.execute. That said, it'll automatically set :absinthe_telemetry in the field metadata if query is present.

Rather than push back on the telemetry support to make it better support tracing, we could integrate this capability directly with Absinthe if:

We could then retire this module except for users with older versions.