Skip to content

@opentelemetry/instrumentation _onRequire does not receive the actual import name #4437

@gajus

Description

@gajus

What happened?

I've been debugging for days why tracing does not work as expected.

I've realized that some auto instrumentations are never actually applied.

After a lot of digging, I've landed on issue being that the module name is never matched in the _onRequire function.

private _onRequire<T>(
module: InstrumentationModuleDefinition<T>,
exports: T,
name: string,
baseDir?: string | void
): T {
if (!baseDir) {
if (typeof module.patch === 'function') {
module.moduleExports = exports;
if (this._enabled) {
return module.patch(exports);
}
}
return exports;
}
const version = this._extractPackageVersion(baseDir);
module.moduleVersion = version;
if (module.name === name) {
// main module
if (
isSupported(module.supportedVersions, version, module.includePrerelease)
) {
if (typeof module.patch === 'function') {
module.moduleExports = exports;
if (this._enabled) {
return module.patch(exports, module.moduleVersion);
}
}
}
return exports;
}
// internal file
const files = module.files ?? [];
const supportedFileInstrumentations = files
.filter(f => f.name === name)
.filter(f =>
isSupported(f.supportedVersions, version, module.includePrerelease)
);
return supportedFileInstrumentations.reduce<T>((patchedExports, file) => {
file.moduleExports = patchedExports;
if (this._enabled) {
return file.patch(patchedExports, module.moduleVersion);
}
return patchedExports;
}, exports);
}

If I add a console.log here:

console.log('>>> require', module.name, name);

The only things printed are:

>>> require fastify fastify/lib/logger.js
>>> require fastify fastify/lib/schemas.js
>>> require fastify fastify/lib/error-serializer.js
>>> require fastify fastify/lib/error-handler.js
>>> require fastify fastify/lib/reply.js
>>> require fastify fastify/lib/request.js
>>> require fastify fastify/lib/context.js
>>> require fastify fastify/lib/httpMethods.js
>>> require fastify fastify/lib/decorate.js
>>> require fastify fastify/lib/contentTypeParser.js
>>> require fastify fastify/lib/schema-controller.js
>>> require fastify fastify/lib/pluginUtils.js
>>> require fastify fastify/lib/reqIdGenFactory.js
>>> require fastify fastify/lib/headRoute.js
>>> require fastify fastify/lib/route.js
>>> require fastify fastify/lib/fourOhFour.js
>>> require fastify fastify/lib/configValidator.js
>>> require fastify fastify/lib/initialConfigValidation.js
>>> require fastify fastify/lib/pluginOverride.js
>>> require fastify fastify/lib/noop-set.js

Meanwhile, in our codebase we import it as:

import createFastify, { type FastifyRequest } from 'fastify';

It appears that the require path gets translated somehow before it can be matched.

This means that getNodeAutoInstrumentations never applies the Fastify instrumentation.

Interestingly, not all imports are affected...

graphql

...
>>> require graphql graphql/utilities/index.js
>>> require graphql graphql

@grpc/grpc-js

>>> require @grpc/grpc-js @grpc/grpc-js/package.json
>>> require @grpc/grpc-js @grpc/grpc-js

but these are the exceptions, most never resolve to the actual module name. ioredis is another example:

>>> require ioredis ioredis/built/SubscriptionSet.js
>>> require ioredis ioredis/built/DataHandler.js
>>> require ioredis ioredis/built/redis/event_handler.js
>>> require ioredis ioredis/built/redis/RedisOptions.js
>>> require ioredis ioredis/built/Redis.js

I am able to replicate this with as little code as:

import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';

(async () => {
  getNodeAutoInstrumentations();

  await import('fastify');
})();
$ node src/bin/server.mjs
>>> require fastify fastify/package.json
>>> require fastify fastify/lib/symbols.js
>>> require fastify fastify/lib/warnings.js
>>> require fastify fastify/lib/errors.js
>>> require fastify fastify/lib/hooks.js
>>> require fastify fastify/lib/server.js
>>> require fastify fastify/lib/validation.js
>>> require fastify fastify/lib/wrapThenable.js
>>> require fastify fastify/lib/handleRequest.js
>>> require pino pino/package.json
>>> require pino pino/lib/caller.js
>>> require pino pino/lib/symbols.js
>>> require pino pino/lib/redaction.js
>>> require pino pino/lib/time.js
>>> require pino pino/lib/transport.js
>>> require pino pino/lib/tools.js
>>> require pino pino/lib/levels.js
>>> require pino pino/lib/meta.js
>>> require pino pino/lib/proto.js
>>> require pino pino/lib/multistream.js
>>> require pino pino ✅
>>> require fastify fastify/lib/logger.js
>>> require fastify fastify/lib/schemas.js
>>> require fastify fastify/lib/error-serializer.js
>>> require fastify fastify/lib/error-handler.js
>>> require fastify fastify/lib/reply.js
>>> require fastify fastify/lib/request.js
>>> require fastify fastify/lib/context.js
>>> require fastify fastify/lib/httpMethods.js
>>> require fastify fastify/lib/decorate.js
>>> require fastify fastify/lib/contentTypeParser.js
>>> require fastify fastify/lib/schema-controller.js
>>> require fastify fastify/lib/pluginUtils.js
>>> require fastify fastify/lib/reqIdGenFactory.js
>>> require fastify fastify/lib/headRoute.js
>>> require fastify fastify/lib/route.js
>>> require fastify fastify/lib/fourOhFour.js
>>> require fastify fastify/lib/configValidator.js
>>> require fastify fastify/lib/initialConfigValidation.js
>>> require fastify fastify/lib/pluginOverride.js
>>> require fastify fastify/lib/noop-set.js

If I update the file server.cjs, then it works as expected:

$ const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');

(async () => {
  getNodeAutoInstrumentations();

  require('fastify');
})();
$ at 16:33:26 ❯ node server.cjs
name http http
name fastify fastify/lib/symbols.js
name fastify fastify/package.json
name https https
name dns dns
name fastify fastify/lib/warnings.js
name fastify fastify/lib/errors.js
name fastify fastify/lib/hooks.js
name fastify fastify/lib/server.js
name fastify fastify/lib/validation.js
name fastify fastify/lib/wrapThenable.js
name fastify fastify/lib/handleRequest.js
name pino pino/lib/caller.js
name pino pino/package.json
name pino pino/lib/symbols.js
name pino pino/lib/redaction.js
name pino pino/lib/time.js
name fs fs
name pino pino/lib/transport.js
name pino pino/lib/tools.js
name pino pino/lib/levels.js
name pino pino/lib/meta.js
name pino pino/lib/proto.js
name pino pino/lib/multistream.js
name pino pino
name fastify fastify/lib/logger.js
name fastify fastify/lib/schemas.js
name fastify fastify/lib/error-serializer.js
name fastify fastify/lib/error-handler.js
name fastify fastify/lib/reply.js
name fastify fastify/lib/request.js
name fastify fastify/lib/context.js
name fastify fastify/lib/httpMethods.js
name fastify fastify/lib/decorate.js
name fastify fastify/lib/contentTypeParser.js
name fastify fastify/lib/schema-controller.js
name fastify fastify/lib/pluginUtils.js
name fastify fastify/lib/reqIdGenFactory.js
name fastify fastify/lib/headRoute.js
name fastify fastify/lib/route.js
name fastify fastify/lib/fourOhFour.js
name fastify fastify/lib/configValidator.js
name fastify fastify/lib/initialConfigValidation.js
name fastify fastify/lib/pluginOverride.js
name fastify fastify/lib/noop-set.js
name fastify fastify

Obviously, that's not an option.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdependenciesPull requests that update a dependency fileinformation-requestedBug is waiting on additional information from the userpriority:p2Bugs and spec inconsistencies which cause telemetry to be incomplete or incorrect

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions