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

Cucumber instrumentation not creating spans #2502

Open
1 of 2 tasks
sergimola opened this issue Oct 24, 2024 · 2 comments
Open
1 of 2 tasks

Cucumber instrumentation not creating spans #2502

sergimola opened this issue Oct 24, 2024 · 2 comments

Comments

@sergimola
Copy link

sergimola commented Oct 24, 2024

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

I am trying to instrument my cucumber tests in NodeJS but I can't make it trace anything at all.

I tried using both
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
and
import { CucumberInstrumentation } from '@opentelemetry/instrumentation-cucumber'
but had no luck with either.

This is the file I have that sets up the telemetry:

/* eslint-disable @typescript-eslint/no-unused-vars */
import { After, Before, BeforeStep, AfterStep, Status, BeforeAll } from '@cucumber/cucumber'
import { NodeSDK } from '@opentelemetry/sdk-node'
import { CucumberInstrumentation } from '@opentelemetry/instrumentation-cucumber'
import { Resource } from '@opentelemetry/resources'
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'
import * as api from '@opentelemetry/api'
import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'
import * as grpc from '@grpc/grpc-js'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'

const collectorOptions = {
    url: 'localhost:4317',
    credentials: grpc.credentials.createInsecure(),
}

const sdk = new NodeSDK({
    resource: new Resource({
        [ATTR_SERVICE_NAME]: 'E2E System Tests'
    }),
    traceExporter: new OTLPTraceExporter(collectorOptions),
    instrumentations: [new CucumberInstrumentation()],
})

const contextManager = new AsyncHooksContextManager().enable()
api.context.setGlobalContextManager(contextManager)

try {
    sdk.start()
    console.log('Tracing initialized')
} catch (error) {
    console.log('Error initializing tracing', error)
}

// Executed after all scenarios
AfterAll(function () {
    sdk.shutdown()
        .then(() => console.log('Tracing terminated'))
        .catch((error) => console.log('Error terminating tracing', error))
})

It gets called and if I create spans manually they show up in the OTELCollector, so telemetry seems to be properly set up.

Does anyone have a real example of to set it up for a real cucumber project?

@pichlermarc
Copy link
Member

do you compile your code to ESM or commonjs? 🤔
There's an extra step for ESM users that needs to be followed, because we only hook require calls by default but they don't exist in ESM, so we need a loader hook - details here https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md

@sergimola
Copy link
Author

sergimola commented Oct 28, 2024

do you compile your code to ESM or commonjs? 🤔 There's an extra step for ESM users that needs to be followed, because we only hook require calls by default but they don't exist in ESM, so we need a loader hook - details here https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md

Yes, it turns out that was the problem.
I followed your suggestion and after quite some trial and error I made it work.

If this is useful for anyone, this is what my execution command looks like to run cucumber-js tests:
npm run build && node --experimental-loader=@opentelemetry/instrumentation/hook.mjs --import ./build/tracing.js ./node_modules/@cucumber/cucumber/bin/cucumber-js --tags "not @ignore"

And this is my tracing.ts file:

import { NodeSDK } from '@opentelemetry/sdk-node'
import { Resource } from '@opentelemetry/resources'
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions'
import * as api from '@opentelemetry/api'
import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'
import * as grpc from '@grpc/grpc-js'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'
import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
import TracingConstants from './src/tracing/constants'
import { Constants } from './src/shared/constants'
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'

const collectorOptions = {
    url: TracingConstants.OTEL_EXPORTER_OTLP_ENDPOINT,
    credentials: grpc.credentials.createInsecure(),
}

const spanProcessors = [new SimpleSpanProcessor(new OTLPTraceExporter(collectorOptions))]

if (Constants.ERROR_LEVEL === 'DEBUG') {
    spanProcessors.push(new SimpleSpanProcessor(new ConsoleSpanExporter()))
}

export const sdk = new NodeSDK({
    resource: new Resource({
        [ATTR_SERVICE_NAME]: TracingConstants.SERVICE_NAME,
        [ATTR_SERVICE_VERSION]: TracingConstants.SERVICE_VERSION,
    }),
    spanProcessors: spanProcessors,
    instrumentations: [getNodeAutoInstrumentations()],
})

const contextManager = new AsyncHooksContextManager().enable()
api.context.setGlobalContextManager(contextManager)

try {
    sdk.start()
    console.log('Tracing initialized')
} catch (error) {
    console.log('Error initializing tracing', error)
}

Edit:
I used SimpleSpanProcessor also with the OTLPTraceExporter because otherwise the traces were not being pushed to the OTEL Collector before the process exited.

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

No branches or pull requests

2 participants