Effect CommunityEC
Effect Communityโ€ข2y agoโ€ข
30 replies
Martin

Trouble Configuring OpenTelemetry / Sentry in GraphQL with Effect

Hey everyone!
I'm having kind of a hard time figuring out how to properly trace requests using OpenTelemetry / Sentry.

I have my usual NodeSDK Layer (found an example in this channel) which I provide to my AppLive layer like so;
const AppLive = ServerLive.pipe(
  Layer.provide(FastifyLive),
  Layer.provide(TracingLive),
  Layer.provide(TelemetryPluginLive),
  Layer.provide(YogaLive),
  Layer.provide(ResolversLive)
);


Tracing works fine in my regular Effect services, but I can't seem to figure out how to make a GraphQL Yoga resolver the parent of the nested spans in a resolver.
I've tried creating my own plugin for GraphQL Yoga to create a span for each query / mutation / subscription hoping that the children spans would nest, but it doesn't seem to work.

export class TelemetryPlugin extends Context.Tag("TelemetryPlugin")<
  TelemetryPlugin,
  ReturnType<typeof useTelemetry>
>() {}

export const useTelemetry = (): Plugin => ({
  onExecute: (ctx) =>
    pipe(
      E.void,
      E.withSpan(ctx.args.operationName),
      E.provide(TracingLive),
      E.runPromise
    ),
});

export const TelemetryPluginLive = Layer.sync(TelemetryPlugin, useTelemetry);


I provide the plugin to Yoga like this (along with a resolver layer):
class Yoga extends Context.Tag("Yoga")<Yoga, YogaServerInstance<{}, {}>>() {}

const YogaLive = pipe(
  Layer.effect(
    Yoga,
    E.gen(function* () {
      const resolvers = yield* Resolvers;
      const telemetryPlugin = yield* TelemetryPlugin;

      return createYoga({
        schema: createSchema({
          typeDefs: /* GraphQL */ `
            type Query {
              hello: String
            }
          `,
          resolvers: resolvers,
        }),
        plugins: [telemetryPlugin],
      });
    })
  ),
  Layer.provide(ResolversLive),
  Layer.provide(TelemetryPluginLive),
  Layer.provide(TracingLive)
);


Nothing seems to be connected. I'm a beginner at Effect, so any tips would be appreciated.
If I create the span directly in the resolver it works, but I'd like to create the span in the plugin so I don't have to repeat the same code in every resolver.

These are the logs. Hello is the graphql query span, the rest is services running inside the resolver.

Sentry Logger [log]: [Tracing] Starting span "Hello" (88d122e7f503d579)
Sentry Logger [log]: [Tracing] Finishing span "Hello" (88d122e7f503d579)
Sentry Logger [log]: [Tracing] Starting span "CreateBooking" (67bfb1a8b31c1300)
Sentry Logger [log]: [Tracing] Finishing span "CreateBooking" (67bfb1a8b31c1300)
Sentry Logger [log]: [Tracing] Starting span "NotifyPatient" (a70f985defddfa0b)
Sentry Logger [log]: [Tracing] Finishing span "NotifyPatient" (a70f985defddfa0b)
Sentry Logger [log]: [Tracing] Finishing undefined transaction: Hello.
Sentry Logger [log]: [Tracing] Finishing undefined transaction: CreateBooking.
Sentry Logger [log]: [Tracing] Finishing undefined transaction: NotifyPatient.
Was this page helpful?