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

Provide working TypeScript / ESM examples #4392

Open
2 tasks
shinebayar-g opened this issue Dec 26, 2023 · 11 comments
Open
2 tasks

Provide working TypeScript / ESM examples #4392

shinebayar-g opened this issue Dec 26, 2023 · 11 comments
Labels
document Documentation-related

Comments

@shinebayar-g
Copy link

shinebayar-g commented Dec 26, 2023

  • 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"

@dyladan
Copy link
Member

dyladan commented Jan 3, 2024

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 dyladan added the document Documentation-related label Jan 3, 2024
@shinebayar-g
Copy link
Author

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

I read through the #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".

@dyladan
Copy link
Member

dyladan commented Jan 5, 2024

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.

@JamieDanielson
Copy link
Member

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.

@gajus
Copy link

gajus commented Jan 23, 2024

I believe this to be related #4437

@tobiasmuehl
Copy link

tobiasmuehl commented Feb 18, 2024

🎉 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 🥷🏼

@smnbbrv
Copy link

smnbbrv commented Feb 19, 2024

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

@Mahmaddz
Copy link

Mahmaddz commented Mar 22, 2024

🎉 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();

@tobiasmuehl
Copy link

tobiasmuehl commented Mar 22, 2024

@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

@gajus
Copy link

gajus commented Mar 22, 2024

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

@smnbbrv
Copy link

smnbbrv commented May 16, 2024

@JamieDanielson if I get it right, based on nodejs/node#51196 (comment) 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 open-telemetry/opentelemetry-js-contrib#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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
document Documentation-related
Projects
None yet
Development

No branches or pull requests

7 participants