opentelemetry-js icon indicating copy to clipboard operation
opentelemetry-js copied to clipboard

Provide working TypeScript / ESM examples

Open shinebayar-g opened this issue 1 year ago • 7 comments

  • [ ] This only affects the JavaScript OpenTelemetry library
  • [ ] This may affect other libraries, but I would like to get opinions here first

Please provide an example for "type": "module" NodeJS projects. Currently all of the examples are using old CommonJS syntax and node --require flag. ~~Why instrumentation.ts is not imported in the main file directly?~~ ( I guess it allows to use auto instrumentation without code modification, but we are willing to modify our code if it's not supported ).

Also example provided in https://opentelemetry.io/docs/instrumentation/js/getting-started/nodejs/ is not working.

❯ npx ts-node --require ./instrumentation.ts app.ts
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module:
...

I guess it assumes some kind of tsconfig.json and other settings available.

Edit: Example is only working when package.json is configured with "type": "commonjs" & tsconfig.json is configured with "module": "Node16", "moduleResolution": "Node16"

shinebayar-g avatar Dec 26 '23 05:12 shinebayar-g

Hmm I think it depends which version of node you're using. The defaults changed with node 20 so the examples likely need to be updated

dyladan avatar Jan 03 '24 21:01 dyladan

We're using latest LTS NodeJS 20.x by default and few apps running on NodeJS 18.x, 16.x.

I read through the https://github.com/open-telemetry/opentelemetry-js/issues/1946 and looks like it is now supported. But it's unclear how to use it. We're currently blocked as we're using some ESM only packages and our apps already setup with "type": "module".

shinebayar-g avatar Jan 03 '24 23:01 shinebayar-g

Actually @JamieDanielson is currently working on or at least thinking about working on this. Right now the ESM support is in a format that is only compatible with some bundlers.

dyladan avatar Jan 05 '24 18:01 dyladan

There is one example I had added when working on instrumentation for ESM-imported libraries, in the examples directory called esm-http-ts. That particular example builds to JS first and then runs with node --experimental-loader=@opentelemetry/instrumentation/hook.mjs ./build/index.js.

We're still sorting through some things trying to figure out what specific setups make things work or not work, as there are many nuances between TS and JS, loaders, Node versions, bundlers, specific package exports, etc.

JamieDanielson avatar Jan 19 '24 16:01 JamieDanielson

I believe this to be related https://github.com/open-telemetry/opentelemetry-js/issues/4437

gajus avatar Jan 23 '24 22:01 gajus

🎉 I found a working solution here! My project is using esm and I switched my runtime from node to jiti and NOW EVERYTHING JUST WORKS!!!!!! I'm using http, express and pg instrumentations. Works on node18 and node20

If we are living in a simulation then this is a complete cheat code 🥷🏼

tobiasmuehl avatar Feb 18 '24 06:02 tobiasmuehl

@tobiasmuehl thanks for sharing, that's nice thing to try out. However I wouldn't call it a solution

smnbbrv avatar Feb 19 '24 07:02 smnbbrv

🎉 I found a working solution here! My project is using esm and I switched my runtime from node to jiti and NOW EVERYTHING JUST WORKS!!!!!! I'm using http, express and pg instrumentations. Works on node18 and node20

If we are living in a simulation then this is a complete cheat code 🥷🏼

can you provide sample or demo? I tried a lot but all in vain,

i am running server using "node --require ./tracer.cjs index.js here is code of my tracer.cjs file:

const jiti =require('jiti')(__filename);
jiti.register()
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { ConsoleSpanExporter } = require('@opentelemetry/sdk-trace-node');
const {
  PeriodicExportingMetricReader,
  ConsoleMetricExporter,
} = require('@opentelemetry/sdk-metrics');
const { GrpcInstrumentation } = require('@opentelemetry/instrumentation-grpc');

const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api');

diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.INFO);

const sdk = new NodeSDK({
  traceExporter: new ConsoleSpanExporter(),
  metricReader: new PeriodicExportingMetricReader({
    exporter: new ConsoleMetricExporter(),
  }),
  instrumentations: [new GrpcInstrumentation()],
});

sdk.start();

Mahmaddz avatar Mar 22 '24 04:03 Mahmaddz

@Mahmaddz

tracer.ts

import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';

 const sdk = new NodeSDK({
    traceExporter: new OTLPTraceExporter({
       // your config
    })
  });
sdk.start();

index.ts

import './tracer.js' // this needs to be the very first import

import 'dotenv/config'
import express from 'express'
const port = Number(process.env.PORT)
const app = express()

// init express, etc

Run with jiti:

npx jiti index.ts

tobiasmuehl avatar Mar 22 '24 04:03 tobiasmuehl

This might be useful to anyone who is trying to figure out all the gotchas https://gajus.com/blog/how-to-add-sentry-tracing-to-your-node-js-app

gajus avatar Mar 22 '24 14:03 gajus

@JamieDanielson if I get it right, based on https://github.com/nodejs/node/issues/51196#issuecomment-1998216742 the correct way would now be

// register.mjs
import { register } from 'node:module';

register('@opentelemetry/instrumentation/hook.mjs', new URL('./', import.meta.url));

and then

node --import=./register.mjs ./main.mjs

This does not only stop throwing a deprecation warning, that's actually quite handy, because it is now possible to drop all relevant opentelemetry config in. That's how a minimal version of this could look like:

// register.mjs
import { register } from 'node:module';
import { context, propagation, trace } from '@opentelemetry/api';
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';

register('@opentelemetry/instrumentation/hook.mjs', new URL('./', import.meta.url));

const sdk = new NodeSDK({
  instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start();

process.on('SIGTERM', () => {
  sdk
    .shutdown()
    .then(() => console.log('tracing terminated'))
    .catch((error) => console.error(error, 'error terminating tracing'))
    .finally(() => process.exit(0));
});

Playing with it for like a day, it works. There are issues however. Probably not all instrumentations are ESM compatible yet (and https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1942 kinda confirms that), e.g.

  • dns instrumentation doesn't work
  • http outgoing requests are not handled, incoming however do work
  • undici works well

Please correct me if I'm wrong.

smnbbrv avatar May 16 '24 15:05 smnbbrv

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[bot] avatar Jul 22 '24 06:07 github-actions[bot]

This issue was closed because it has been stale for 14 days with no activity.

github-actions[bot] avatar Aug 12 '24 06:08 github-actions[bot]