Skip to content

Unable to use OTLPMetricExporter (from @opentelemetry/exporter-metrics-otlp-proto) with commonjs and jest #6035

@matthelliwell2

Description

@matthelliwell2

What happened?

Steps to Reproduce

Create an OTLPMetricsExporter from @opentelemetry/exporter-metrics-otlp-proto. Use this in a PeriodicExportingMetricReader. Add a value to a counter and flush.

This is a small Typescript commonjs jest test case to demonstrate the problem:

import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto'
import { AggregationTemporality, MeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'
import { diag, DiagLogLevel } from '@opentelemetry/api'

describe('Exporter', () => {
    it('runs without errors', async function () {
        diag.setLogger(logger, DiagLogLevel.ERROR)
        const exporter = new OTLPMetricExporter({
            url: 'http://localhost:3000/metrics',
            temporalityPreference: AggregationTemporality.CUMULATIVE,
            headers: {
                Authorization: 'Api-Token my-token',
            },
        })

        const reader = new PeriodicExportingMetricReader({
            exporter: exporter,
            exportIntervalMillis: 30000,
        })

        const provider = new MeterProvider({
            readers: [reader],
        })

        const meter = provider.getMeter('my-name-space')

        const counter = meter.createCounter('my-counter')
        counter.add(100)

        await reader.forceFlush()
    })
})

const logger = {
    error: (message: string, ...args: unknown[]) => {
        console.error('OTLP Error:', message, ...args)
    },
    warn: (message: string, ...args: unknown[]) => {
        console.warn(message, ...args)
    },
    info: (message: string, ...args: unknown[]) => {
        console.info(message, ...args)
    },
    debug: (message: string, ...args: unknown[]) => {
        console.debug(message, ...args)
    },
    verbose: (message: string, ...args: unknown[]) => {
        console.log(message, ...args)
    },
}

Expected Result

A metric is written to the provided URL

Actual Result

No metric is written. An error is logged:
{"stack":"Error: PeriodicExportingMetricReader: metrics export failed (error TypeError [ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG]: A dynamic import callback was invoked without --experimental-vm-modules)
at PeriodicExportingMetricReader._doRun (/@opentelemetry/sdk-metrics/src/export/PeriodicExportingMetricReader.ts:144:13)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at PeriodicExportingMetricReader._runOnce (/node_modules/@opentelemetry/sdk-metrics/src/export/PeriodicExportingMetricReader.ts:103:7)
at PeriodicExportingMetricReader.onForceFlush (/node_modules/@opentelemetry/sdk-metrics/src/export/PeriodicExportingMetricReader.ts:160:5)
at PeriodicExportingMetricReader.forceFlush (/node_modules/@opentelemetry/sdk-metrics/src/export/MetricReader.ts:277:7)
at Object. (/test/metrics/Exporter.spec.ts:30:9)","message":"PeriodicExportingMetricReader:
metrics export failed (error TypeError [ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG]: A dynamic import callback was invoked without --experimental-vm-modules)","name":"Error"}

Additional Details

Passing the --experimental-vm-modules fixes the problem. But this code needs to run in an AWS Lambda so I don't have control over the node runtime. Running in a container is a possibility but I have a lot of lambdas that would need migrating to containers so this would be expensive.

The problem looks like it is in @opentelemetry/otlp-exporter-base/build/src/transport/http-exporter-transport.js. The requestFunctionFactory function has a conditional import:

const module = protocol === 'http:' ? import('http') : import('https')

OpenTelemetry Setup Code

See above example

package.json

{
  "scripts": {
    "test": "npx jest --detectOpenHandles --coverage --reporters=jest-junit --reporters=default"
  },
  "dependencies": {
    "@opentelemetry/api": "1.9.0",
    "@opentelemetry/exporter-metrics-otlp-proto": "0.206.0",
    "@opentelemetry/resources": "2.1.0",
    "@opentelemetry/sdk-metrics": "2.1.0",
    "@opentelemetry/sdk-node": "0.206.0",
    "@opentelemetry/semantic-conventions": "1.37.0"
  },
  "devDependencies": {
    "@types/jest": "30.0.0",
    "jest": "30.2.0",
    "jest-junit": "16.0.0",
    "jest-junit-reporter": "1.1.0",
    "ts-jest": "29.4.5",
    "typescript": "5.9.3",
    "typescript-eslint": "8.46.0"
  },
  "jest": {
    "testMatch": [
      "**/Exporter.spec.ts"
    ],
    "transform": {
      ".+\\.(ts|tsx)?$": "ts-jest"
    },
    "verbose": true,
    "silent": false,
    "detectOpenHandles": true,
    "forceExit": true,
    "testTimeout": 30000
  }
}

Relevant log output

{"stack":"Error: PeriodicExportingMetricReader: metrics export failed (error TypeError [ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG]: A dynamic import callback was invoked without --experimental-vm-modules)
    at PeriodicExportingMetricReader._doRun (<redacted>/@opentelemetry/sdk-metrics/src/export/PeriodicExportingMetricReader.ts:144:13)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at PeriodicExportingMetricReader._runOnce (<redacted>/node_modules/@opentelemetry/sdk-metrics/src/export/PeriodicExportingMetricReader.ts:103:7)
    at PeriodicExportingMetricReader.onForceFlush (<redacted>/node_modules/@opentelemetry/sdk-metrics/src/export/PeriodicExportingMetricReader.ts:160:5)
    at PeriodicExportingMetricReader.forceFlush (<redacted>/node_modules/@opentelemetry/sdk-metrics/src/export/MetricReader.ts:277:7)
    at Object.<anonymous> (<redacted>/test/metrics/Exporter.spec.ts:30:9)","message":"PeriodicExportingMetricReader: 
metrics export failed (error TypeError [ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG]: A dynamic import callback was invoked without --experimental-vm-modules)","name":"Error"}

Operating System and Version

No response

Runtime and Version

Node.js 20.18.0

Tip

React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingpkg:otlp-exporter-basepriority:p3Bugs which cause problems in user apps not related to correctness (performance, memory use, etc)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions