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

instrumentation-graphql not working for ESM modules #535

Closed
dragonfriend0013 opened this issue Jun 14, 2021 · 3 comments
Closed

instrumentation-graphql not working for ESM modules #535

dragonfriend0013 opened this issue Jun 14, 2021 · 3 comments
Labels
bug Something isn't working stale

Comments

@dragonfriend0013
Copy link

dragonfriend0013 commented Jun 14, 2021

What version of OpenTelemetry are you using?

0.20.0

What version of Node are you using?

v14.15.0

What did you do?

Converting CommonJS code to ESM (.mjs) files breaks @opentelemetry/instrumentation-graphql. CommonJS version of code works perfectly, ESM version of code does not have any GraphQL spans present

What did you expect to see?

The same spans present in CommonJS version of code

What did you see instead?

No GraphQL spans

Additional context

Code

tracer.js

const api = require('@opentelemetry/api');
const { NodeTracerProvider } = require('@opentelemetry/node');
const { ResourceAttributes } = require('@opentelemetry/semantic-conventions');
const { Resource } = require('@opentelemetry/resources');
const { SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
const { GraphQLInstrumentation } = require('@opentelemetry/instrumentation-graphql');
const { B3Propagator } = require('@opentelemetry/propagator-b3');
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');
// const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');

module.exports = (serviceName) => {
  const provider = new NodeTracerProvider({
    resource: new Resource({
      [ResourceAttributes.SERVICE_NAME]: serviceName,
    }),
  });

  api.propagation.setGlobalPropagator(new B3Propagator());
  api.trace.setGlobalTracerProvider(provider);

  provider.addSpanProcessor(
    new SimpleSpanProcessor(
      new ZipkinExporter({
        serviceName,
        url: 'http://localhost:9411/api/v2/spans',
      }),
      // or
      // new JaegerExporter({
      //   serviceName,
      // })
    ),
  );
  provider.register();
  registerInstrumentations({
    instrumentations: [
      new GraphQLInstrumentation(),
    ],
  });

  return api.trace.getTracer(serviceName);
};

service.js

/* eslint-disable no-console */
/* eslint-disable import/order */
// Register tracer
const serviceName = 'service-add';
const tracerInit = require('./tracer.js');

const tracer = tracerInit(serviceName);

const {
  context,
  trace,
} = require('@opentelemetry/api');
const service = require('fastify')({ logger: { level: 'debug' } });
const mercurius = require('mercurius');
const fastifyOTEL = require('@autotelic/fastify-opentelemetry');

const schema = `
extend type Query {
  add(x: Float, y: Float): Float
  split(text: String): Split
}
type Split {
  text1: String
  text2: String
}
`;

const resolvers = {
  Query: {
    add: (_, { x, y }) => {
      const activeSpan = trace.getSpan(context.active());

      activeSpan.setAttribute('arg.x', x);
      activeSpan.setAttribute('arg.y', y);
      const span = tracer.startSpan('compute-add', { parent: activeSpan._spanContext });
      const result = x + y;
      span.end();

      return result;
    },
    split: (_, { text }) => {
      const firstSpace = text.indexOf(' ');
      if (firstSpace === -1) {
        return {
          text1: text,
          text2: null,
        };
      }
      return {
        text1: text.substr(0, firstSpace),
        text2: text.substr(firstSpace + 1),
      };
    },
  },
};

const main = async () => {
  service.register(fastifyOTEL, {
    serviceName,
    wrapRoutes: true,
  });
  service.register(mercurius, {
    schema,
    resolvers,
    federationMetadata: true,
  });

  await service.ready();

  service.listen(4001, 'localhost', (err) => {
    if (err) {
      console.error(err);
      process.exit(1);
    }
  });
};

main();

tracer.mjs

import { propagation, trace } from '@opentelemetry/api';
import { NodeTracerProvider } from '@opentelemetry/node';
import { ResourceAttributes } from '@opentelemetry/semantic-conventions';
import { Resource } from '@opentelemetry/resources';
import { SimpleSpanProcessor } from '@opentelemetry/tracing';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql';
import { B3Propagator } from '@opentelemetry/propagator-b3';
import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';
// const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');

const tracerInit = (serviceName) => {
  const provider = new NodeTracerProvider({
    resource: new Resource({
      [ResourceAttributes.SERVICE_NAME]: serviceName,
    }),
  });

  propagation.setGlobalPropagator(new B3Propagator());
  trace.setGlobalTracerProvider(provider);

  provider.addSpanProcessor(
    new SimpleSpanProcessor(
      new ZipkinExporter({
        serviceName,
        url: 'http://localhost:9411/api/v2/spans',
      }),
      // or
      // new JaegerExporter({
      //   serviceName,
      // })
    ),
  );
  provider.register();

  registerInstrumentations({
    instrumentations: [
      new GraphQLInstrumentation(),
    ],
  });

  return trace.getTracer(serviceName);
};

export default tracerInit;

service.mjs

/* eslint-disable import/first */
/* eslint-disable no-console */
/* eslint-disable import/order */
// Register tracer
const serviceName = 'service-add';
import tracerInit from './tracer.mjs';

const tracer = tracerInit(serviceName);

import { context, trace } from '@opentelemetry/api';
import Fastify from 'fastify';
import mercurius from 'mercurius';
import fastifyOTEL from '@autotelic/fastify-opentelemetry';

const schema = `
extend type Query {
  add(x: Float, y: Float): Float
  split(text: String): Split
}
type Split {
  text1: String
  text2: String
}
`;

const resolvers = {
  Query: {
    add: (_, { x, y }) => {
      const activeSpan = trace.getSpan(context.active());

      activeSpan.setAttribute('arg.x', x);
      activeSpan.setAttribute('arg.y', y);
      const span = tracer.startSpan('compute-add', { parent: activeSpan._spanContext });
      const result = x + y;
      span.end();

      return result;
    },
    split: (_, { text }) => {
      const firstSpace = text.indexOf(' ');
      if (firstSpace === -1) {
        return {
          text1: text,
          text2: null,
        };
      }
      return {
        text1: text.substr(0, firstSpace),
        text2: text.substr(firstSpace + 1),
      };
    },
  },
};

const main = async () => {
  const service = Fastify({ logger: { level: 'debug' } });
  service.register(fastifyOTEL, {
    serviceName,
    wrapRoutes: true,
  });
  service.register(mercurius, {
    schema,
    resolvers,
    federationMetadata: true,
  });

  await service.ready();

  service.listen(4001, 'localhost', (err) => {
    if (err) {
      console.error(err);
      process.exit(1);
    }
  });
};

main();

package.json

{
  "name": "mercury2",
  "version": "1.0.0",
  "description": "",
  "main": "index.mjs",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@autotelic/fastify-opentelemetry": "^0.13.0",
    "@dnlup/fastify-traps": "^1.1.2",
    "@opentelemetry/api": "^0.20.0",
    "@opentelemetry/core": "^0.20.0",
    "@opentelemetry/exporter-collector": "^0.20.0",
    "@opentelemetry/exporter-jaeger": "^0.20.0",
    "@opentelemetry/exporter-zipkin": "^0.20.0",
    "@opentelemetry/instrumentation": "^0.20.0",
    "@opentelemetry/instrumentation-graphql": "^0.20.0",
    "@opentelemetry/instrumentation-http": "^0.20.0",
    "@opentelemetry/node": "^0.20.0",
    "@opentelemetry/propagator-b3": "^0.20.0",
    "@opentelemetry/resources": "^0.20.0",
    "@opentelemetry/semantic-conventions": "^0.20.0",
    "@opentelemetry/tracing": "^0.20.0",
    "convert-hrtime": "^5.0.0",
    "fastify": "^3.16.2",
    "fastify-healthcheck": "^3.1.0",
    "http-cache-semantics": "^4.1.0",
    "lru-cache": "^6.0.0",
    "mercurius": "^7.6.1",
    "moment-timezone": "^0.5.33",
    "node-fetch": "^2.6.1"
  },
  "devDependencies": {
    "eslint": "^7.27.0",
    "eslint-config-airbnb-base": "^14.2.1",
    "eslint-plugin-import": "^2.23.3",
    "nodemon": "^2.0.7",
    "prisma": "^2.24.0"
  }
}
@dragonfriend0013 dragonfriend0013 added the bug Something isn't working label Jun 14, 2021
@vmarchaud
Copy link
Member

I believe no instrumentation currently works with ESM because there are no support for monkey patching ESM modules right now (see open-telemetry/opentelemetry-js#1946)

@github-actions
Copy link
Contributor

github-actions bot commented Nov 8, 2021

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 14 days.

@github-actions github-actions bot added the stale label Nov 8, 2021
@vmarchaud
Copy link
Member

I'll go ahead and close this one since its not linked with graphql per-se and we already have a ticket that track the problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working stale
Projects
None yet
Development

No branches or pull requests

2 participants