diff --git a/.chloggen/node-import.yaml b/.chloggen/node-import.yaml
new file mode 100644
index 0000000000..8ec124c59b
--- /dev/null
+++ b/.chloggen/node-import.yaml
@@ -0,0 +1,18 @@
+# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
+change_type: enhancement
+
+# The name of the component, or a single word describing the area of concern, (e.g. collector, target allocator, auto-instrumentation, opamp, github action)
+component: auto-instrumentation
+
+# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
+note: Add Node.js support for `--import` flag
+
+# One or more tracking issues related to the change
+issues: [3414]
+
+# (Optional) One or more lines of additional information to render under the primary note.
+# These lines will be padded with 2 spaces and then inserted directly into the document.
+# Use pipe (|) for multiline entries.
+subtext: |
+ The new UseImport option overrides the default injected --require flag with an --import flag.
+ Node.js ^18.19.0 || ^20.6.0 || >=22 is required for the flag to be supported.
diff --git a/apis/v1alpha1/instrumentation_types.go b/apis/v1alpha1/instrumentation_types.go
index 5caf3fb0ea..ffe580e6b5 100644
--- a/apis/v1alpha1/instrumentation_types.go
+++ b/apis/v1alpha1/instrumentation_types.go
@@ -212,6 +212,11 @@ type NodeJS struct {
// Resources describes the compute resource requirements.
// +optional
Resources corev1.ResourceRequirements `json:"resourceRequirements,omitempty"`
+
+ // UseImport overrides the default injected --require flag with an --import flag.
+ // Node.js ^18.19.0 || ^20.6.0 || >=22 is required for the flag to be supported.
+ // +optional
+ UseImport bool `json:"useImport,omitempty"`
}
// Python defines Python SDK and instrumentation configuration.
diff --git a/autoinstrumentation/nodejs/Dockerfile b/autoinstrumentation/nodejs/Dockerfile
index 70106ecd6b..703dac21d2 100644
--- a/autoinstrumentation/nodejs/Dockerfile
+++ b/autoinstrumentation/nodejs/Dockerfile
@@ -9,6 +9,8 @@
# - Grant the necessary access to `/autoinstrumentation` directory. `chmod -R go+r /autoinstrumentation`
# - For auto-instrumentation by container injection, the Linux command cp is
# used and must be available in the image.
+# - By default a file named autoinstrumentation.js is loaded using `require`, but the UseImport configuration option
+# overrides this default behaviour and loads it autoinstrumentation.mjs using `import`.
FROM node:20 AS build
WORKDIR /operator-build
diff --git a/autoinstrumentation/nodejs/package.json b/autoinstrumentation/nodejs/package.json
index 9611d2af29..74047250f2 100644
--- a/autoinstrumentation/nodejs/package.json
+++ b/autoinstrumentation/nodejs/package.json
@@ -4,12 +4,11 @@
"private": true,
"scripts": {
"clean": "rimraf build/*",
- "postinstall": "copyfiles -f 'build/src/**' build/workspace/ && copyfiles 'node_modules/**' package.json build/workspace/ && npm -C build/workspace prune --omit=dev --no-package-lock"
+ "postinstall": "copyfiles 'node_modules/**' package.json build/workspace/ && npm -C build/workspace prune --omit=dev --no-package-lock"
},
"devDependencies": {
"copyfiles": "^2.4.1",
- "rimraf": "^6.0.1",
- "typescript": "^5.6.3"
+ "rimraf": "^6.0.1"
},
"dependencies": {
"@opentelemetry/api": "1.9.0",
diff --git a/autoinstrumentation/nodejs/tsconfig.json b/autoinstrumentation/nodejs/tsconfig.json
deleted file mode 100644
index 38012118db..0000000000
--- a/autoinstrumentation/nodejs/tsconfig.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "compilerOptions": {
- "rootDir": ".",
- "outDir": "build",
-
- "allowUnreachableCode": false,
- "allowUnusedLabels": false,
- "composite": true,
- "declaration": true,
- "declarationMap": true,
- "forceConsistentCasingInFileNames": true,
- "incremental": true,
- "inlineSources": true,
- "module": "commonjs",
- "newLine": "LF",
- "noEmitOnError": true,
- "noFallthroughCasesInSwitch": true,
- "noImplicitOverride": true,
- "noImplicitReturns": true,
- "noUnusedLocals": true,
- "pretty": true,
- "skipLibCheck": true,
- "sourceMap": true,
- "strict": true,
- "strictNullChecks": true,
- "target": "es2017"
- },
- "include": [
- "src/**/*.ts",
- ],
- "exclude": [
- "node_modules"
- ]
-}
\ No newline at end of file
diff --git a/bundle/community/manifests/opentelemetry-operator.clusterserviceversion.yaml b/bundle/community/manifests/opentelemetry-operator.clusterserviceversion.yaml
index fec2635c30..48ef486d11 100644
--- a/bundle/community/manifests/opentelemetry-operator.clusterserviceversion.yaml
+++ b/bundle/community/manifests/opentelemetry-operator.clusterserviceversion.yaml
@@ -99,7 +99,7 @@ metadata:
categories: Logging & Tracing,Monitoring
certified: "false"
containerImage: ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator
- createdAt: "2025-07-05T13:19:47Z"
+ createdAt: "2025-07-08T15:59:44Z"
description: Provides the OpenTelemetry components, including the Collector
operators.operatorframework.io/builder: operator-sdk-v1.29.0
operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
diff --git a/bundle/community/manifests/opentelemetry.io_instrumentations.yaml b/bundle/community/manifests/opentelemetry.io_instrumentations.yaml
index 6b71ba088b..191a192cbc 100644
--- a/bundle/community/manifests/opentelemetry.io_instrumentations.yaml
+++ b/bundle/community/manifests/opentelemetry.io_instrumentations.yaml
@@ -1498,6 +1498,8 @@ spec:
x-kubernetes-int-or-string: true
type: object
type: object
+ useImport:
+ type: boolean
volumeClaimTemplate:
properties:
metadata:
diff --git a/bundle/openshift/manifests/opentelemetry-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/opentelemetry-operator.clusterserviceversion.yaml
index 5cc60031fc..96c1e9ba7d 100644
--- a/bundle/openshift/manifests/opentelemetry-operator.clusterserviceversion.yaml
+++ b/bundle/openshift/manifests/opentelemetry-operator.clusterserviceversion.yaml
@@ -99,7 +99,7 @@ metadata:
categories: Logging & Tracing,Monitoring
certified: "false"
containerImage: ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator
- createdAt: "2025-07-05T13:19:48Z"
+ createdAt: "2025-07-08T15:59:44Z"
description: Provides the OpenTelemetry components, including the Collector
operators.operatorframework.io/builder: operator-sdk-v1.29.0
operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
diff --git a/bundle/openshift/manifests/opentelemetry.io_instrumentations.yaml b/bundle/openshift/manifests/opentelemetry.io_instrumentations.yaml
index 6b71ba088b..191a192cbc 100644
--- a/bundle/openshift/manifests/opentelemetry.io_instrumentations.yaml
+++ b/bundle/openshift/manifests/opentelemetry.io_instrumentations.yaml
@@ -1498,6 +1498,8 @@ spec:
x-kubernetes-int-or-string: true
type: object
type: object
+ useImport:
+ type: boolean
volumeClaimTemplate:
properties:
metadata:
diff --git a/config/crd/bases/opentelemetry.io_instrumentations.yaml b/config/crd/bases/opentelemetry.io_instrumentations.yaml
index b06e657a27..ce6983f694 100644
--- a/config/crd/bases/opentelemetry.io_instrumentations.yaml
+++ b/config/crd/bases/opentelemetry.io_instrumentations.yaml
@@ -1496,6 +1496,8 @@ spec:
x-kubernetes-int-or-string: true
type: object
type: object
+ useImport:
+ type: boolean
volumeClaimTemplate:
properties:
metadata:
diff --git a/docs/api/instrumentations.md b/docs/api/instrumentations.md
index 87ac838c16..13891c16d0 100644
--- a/docs/api/instrumentations.md
+++ b/docs/api/instrumentations.md
@@ -5670,6 +5670,14 @@ If the former var had been defined, then the other vars would be ignored.
Resources describes the compute resource requirements.
false |
+
+ useImport |
+ boolean |
+
+ UseImport overrides the default injected --require flag with an --import flag.
+Node.js ^18.19.0 || ^20.6.0 || >=22 is required for the flag to be supported.
+ |
+ false |
volumeClaimTemplate |
object |
diff --git a/internal/instrumentation/nodejs.go b/internal/instrumentation/nodejs.go
index fc712f386e..e8c2ec354f 100644
--- a/internal/instrumentation/nodejs.go
+++ b/internal/instrumentation/nodejs.go
@@ -12,6 +12,7 @@ import (
const (
envNodeOptions = "NODE_OPTIONS"
nodeRequireArgument = " --require /otel-auto-instrumentation-nodejs/autoinstrumentation.js"
+ nodeImportArgument = " --import /otel-auto-instrumentation-nodejs/autoinstrumentation.js"
nodejsInitContainerName = initContainerName + "-nodejs"
nodejsVolumeName = volumeName + "-nodejs"
nodejsInstrMountPath = "/otel-auto-instrumentation-nodejs"
@@ -31,14 +32,20 @@ func injectNodeJSSDK(nodeJSSpec v1alpha1.NodeJS, pod corev1.Pod, index int, inst
// inject NodeJS instrumentation spec env vars.
container.Env = appendIfNotSet(container.Env, nodeJSSpec.Env...)
+ var nodeArgument string
+ if nodeJSSpec.UseImport {
+ nodeArgument = nodeImportArgument
+ } else {
+ nodeArgument = nodeRequireArgument
+ }
idx := getIndexOfEnv(container.Env, envNodeOptions)
if idx == -1 {
container.Env = append(container.Env, corev1.EnvVar{
Name: envNodeOptions,
- Value: nodeRequireArgument,
+ Value: nodeArgument,
})
} else if idx > -1 {
- container.Env[idx].Value = container.Env[idx].Value + nodeRequireArgument
+ container.Env[idx].Value = container.Env[idx].Value + nodeArgument
}
container.VolumeMounts = append(container.VolumeMounts, corev1.VolumeMount{
diff --git a/internal/instrumentation/nodejs_test.go b/internal/instrumentation/nodejs_test.go
index 9c921ad029..934c405f73 100644
--- a/internal/instrumentation/nodejs_test.go
+++ b/internal/instrumentation/nodejs_test.go
@@ -135,6 +135,120 @@ func TestInjectNodeJSSDK(t *testing.T) {
},
err: nil,
},
+ {
+ name: "NODE_OPTIONS not defined and UseImport true",
+ NodeJS: v1alpha1.NodeJS{Image: "foo/bar:1", UseImport: true},
+ pod: corev1.Pod{
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {},
+ },
+ },
+ },
+ expected: corev1.Pod{
+ Spec: corev1.PodSpec{
+ Volumes: []corev1.Volume{
+ {
+ Name: "opentelemetry-auto-instrumentation-nodejs",
+ VolumeSource: corev1.VolumeSource{
+ EmptyDir: &corev1.EmptyDirVolumeSource{
+ SizeLimit: &defaultVolumeLimitSize,
+ },
+ },
+ },
+ },
+ InitContainers: []corev1.Container{
+ {
+ Name: "opentelemetry-auto-instrumentation-nodejs",
+ Image: "foo/bar:1",
+ Command: []string{"cp", "-r", "/autoinstrumentation/.", "/otel-auto-instrumentation-nodejs"},
+ VolumeMounts: []corev1.VolumeMount{{
+ Name: "opentelemetry-auto-instrumentation-nodejs",
+ MountPath: "/otel-auto-instrumentation-nodejs",
+ }},
+ },
+ },
+ Containers: []corev1.Container{
+ {
+ VolumeMounts: []corev1.VolumeMount{
+ {
+ Name: "opentelemetry-auto-instrumentation-nodejs",
+ MountPath: "/otel-auto-instrumentation-nodejs",
+ },
+ },
+ Env: []corev1.EnvVar{
+ {
+ Name: "NODE_OPTIONS",
+ Value: " --import /otel-auto-instrumentation-nodejs/autoinstrumentation.js",
+ },
+ },
+ },
+ },
+ },
+ },
+ err: nil,
+ },
+ {
+ name: "NODE_OPTIONS defined and UseImport true",
+ NodeJS: v1alpha1.NodeJS{Image: "foo/bar:1", Resources: testResourceRequirements, UseImport: true},
+ pod: corev1.Pod{
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Env: []corev1.EnvVar{
+ {
+ Name: "NODE_OPTIONS",
+ Value: "-Dbaz=bar",
+ },
+ },
+ },
+ },
+ },
+ },
+ expected: corev1.Pod{
+ Spec: corev1.PodSpec{
+ Volumes: []corev1.Volume{
+ {
+ Name: "opentelemetry-auto-instrumentation-nodejs",
+ VolumeSource: corev1.VolumeSource{
+ EmptyDir: &corev1.EmptyDirVolumeSource{
+ SizeLimit: &defaultVolumeLimitSize,
+ },
+ },
+ },
+ },
+ InitContainers: []corev1.Container{
+ {
+ Name: "opentelemetry-auto-instrumentation-nodejs",
+ Image: "foo/bar:1",
+ Command: []string{"cp", "-r", "/autoinstrumentation/.", "/otel-auto-instrumentation-nodejs"},
+ VolumeMounts: []corev1.VolumeMount{{
+ Name: "opentelemetry-auto-instrumentation-nodejs",
+ MountPath: "/otel-auto-instrumentation-nodejs",
+ }},
+ Resources: testResourceRequirements,
+ },
+ },
+ Containers: []corev1.Container{
+ {
+ VolumeMounts: []corev1.VolumeMount{
+ {
+ Name: "opentelemetry-auto-instrumentation-nodejs",
+ MountPath: "/otel-auto-instrumentation-nodejs",
+ },
+ },
+ Env: []corev1.EnvVar{
+ {
+ Name: "NODE_OPTIONS",
+ Value: "-Dbaz=bar" + " --import /otel-auto-instrumentation-nodejs/autoinstrumentation.js",
+ },
+ },
+ },
+ },
+ },
+ },
+ err: nil,
+ },
{
name: "NODE_OPTIONS defined as ValueFrom",
NodeJS: v1alpha1.NodeJS{Image: "foo/bar:1"},
diff --git a/internal/instrumentation/podmutator_test.go b/internal/instrumentation/podmutator_test.go
index e674608a2d..620d9b6376 100644
--- a/internal/instrumentation/podmutator_test.go
+++ b/internal/instrumentation/podmutator_test.go
@@ -869,6 +869,193 @@ func TestMutatePod(t *testing.T) {
EnableNodeJSAutoInstrumentation: true,
},
},
+ {
+ name: "nodejs injection use import, true",
+ ns: corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "nodejs-import",
+ },
+ },
+ inst: v1alpha1.Instrumentation{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "example-inst",
+ Namespace: "nodejs-import",
+ },
+ Spec: v1alpha1.InstrumentationSpec{
+ NodeJS: v1alpha1.NodeJS{
+ Image: "otel/nodejs:1",
+ Env: []corev1.EnvVar{
+ {
+ Name: "OTEL_NODEJS_DEBUG",
+ Value: "true",
+ },
+ },
+ UseImport: true,
+ },
+ Env: []corev1.EnvVar{
+ {
+ Name: "OTEL_TRACES_EXPORTER",
+ Value: "otlp",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_ENDPOINT",
+ Value: "http://localhost:4317",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_TIMEOUT",
+ Value: "20",
+ },
+ {
+ Name: "OTEL_TRACES_SAMPLER",
+ Value: "parentbased_traceidratio",
+ },
+ {
+ Name: "OTEL_TRACES_SAMPLER_ARG",
+ Value: "0.85",
+ },
+ {
+ Name: "SPLUNK_TRACE_RESPONSE_HEADER_ENABLED",
+ Value: "true",
+ },
+ },
+ Exporter: v1alpha1.Exporter{
+ Endpoint: "http://collector:12345",
+ },
+ },
+ },
+ pod: corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Annotations: map[string]string{
+ annotationInjectNodeJS: "true",
+ },
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "app",
+ },
+ },
+ },
+ },
+ expected: corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Annotations: map[string]string{
+ annotationInjectNodeJS: "true",
+ },
+ },
+ Spec: corev1.PodSpec{
+ Volumes: []corev1.Volume{
+ {
+ Name: nodejsVolumeName,
+ VolumeSource: corev1.VolumeSource{
+ EmptyDir: &corev1.EmptyDirVolumeSource{
+ SizeLimit: &defaultVolumeLimitSize,
+ },
+ },
+ },
+ },
+ InitContainers: []corev1.Container{
+ {
+ Name: nodejsInitContainerName,
+ Image: "otel/nodejs:1",
+ Command: []string{"cp", "-r", "/autoinstrumentation/.", nodejsInstrMountPath},
+ VolumeMounts: []corev1.VolumeMount{{
+ Name: nodejsVolumeName,
+ MountPath: nodejsInstrMountPath,
+ }},
+ },
+ },
+ Containers: []corev1.Container{
+ {
+ Name: "app",
+ Env: []corev1.EnvVar{
+ {
+ Name: "OTEL_NODE_IP",
+ ValueFrom: &corev1.EnvVarSource{
+ FieldRef: &corev1.ObjectFieldSelector{
+ FieldPath: "status.hostIP",
+ },
+ },
+ },
+ {
+ Name: "OTEL_POD_IP",
+ ValueFrom: &corev1.EnvVarSource{
+ FieldRef: &corev1.ObjectFieldSelector{
+ FieldPath: "status.podIP",
+ },
+ },
+ },
+ {
+ Name: "OTEL_NODEJS_DEBUG",
+ Value: "true",
+ },
+ {
+ Name: "NODE_OPTIONS",
+ Value: nodeImportArgument,
+ },
+ {
+ Name: "OTEL_TRACES_EXPORTER",
+ Value: "otlp",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_ENDPOINT",
+ Value: "http://localhost:4317",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_TIMEOUT",
+ Value: "20",
+ },
+ {
+ Name: "OTEL_TRACES_SAMPLER",
+ Value: "parentbased_traceidratio",
+ },
+ {
+ Name: "OTEL_TRACES_SAMPLER_ARG",
+ Value: "0.85",
+ },
+ {
+ Name: "SPLUNK_TRACE_RESPONSE_HEADER_ENABLED",
+ Value: "true",
+ },
+ {
+ Name: "OTEL_SERVICE_NAME",
+ Value: "app",
+ },
+ {
+ Name: "OTEL_RESOURCE_ATTRIBUTES_POD_NAME",
+ ValueFrom: &corev1.EnvVarSource{
+ FieldRef: &corev1.ObjectFieldSelector{
+ FieldPath: "metadata.name",
+ },
+ },
+ },
+ {
+ Name: "OTEL_RESOURCE_ATTRIBUTES_NODE_NAME",
+ ValueFrom: &corev1.EnvVarSource{
+ FieldRef: &corev1.ObjectFieldSelector{
+ FieldPath: "spec.nodeName",
+ },
+ },
+ },
+ {
+ Name: "OTEL_RESOURCE_ATTRIBUTES",
+ Value: "k8s.container.name=app,k8s.namespace.name=nodejs-import,k8s.node.name=$(OTEL_RESOURCE_ATTRIBUTES_NODE_NAME),k8s.pod.name=$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME),service.instance.id=nodejs-import.$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME).app,service.namespace=nodejs-import",
+ },
+ },
+ VolumeMounts: []corev1.VolumeMount{
+ {
+ Name: nodejsVolumeName,
+ MountPath: nodejsInstrMountPath,
+ },
+ },
+ },
+ },
+ },
+ },
+ config: config.Config{
+ EnableNodeJSAutoInstrumentation: true,
+ },
+ },
{
name: "nodejs injection multiple containers, true",
ns: corev1.Namespace{
diff --git a/tests/e2e-instrumentation/instrumentation-nodejs-import/00-install-collector.yaml b/tests/e2e-instrumentation/instrumentation-nodejs-import/00-install-collector.yaml
new file mode 100644
index 0000000000..e32ff2b422
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-nodejs-import/00-install-collector.yaml
@@ -0,0 +1,27 @@
+apiVersion: opentelemetry.io/v1beta1
+kind: OpenTelemetryCollector
+metadata:
+ name: sidecar
+spec:
+ config:
+ receivers:
+ otlp:
+ protocols:
+ grpc: {}
+ http: {}
+
+ processors: {}
+
+ exporters:
+ debug:
+ verbosity: detailed
+
+ service:
+ pipelines:
+ traces:
+ receivers: [otlp]
+ exporters: [debug]
+ metrics:
+ receivers: [otlp]
+ exporters: [debug]
+ mode: sidecar
diff --git a/tests/e2e-instrumentation/instrumentation-nodejs-import/00-install-instrumentation.yaml b/tests/e2e-instrumentation/instrumentation-nodejs-import/00-install-instrumentation.yaml
new file mode 100644
index 0000000000..daa2bc1637
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-nodejs-import/00-install-instrumentation.yaml
@@ -0,0 +1,28 @@
+apiVersion: opentelemetry.io/v1alpha1
+kind: Instrumentation
+metadata:
+ name: nodejs
+spec:
+ env:
+ - name: OTEL_TRACES_EXPORTER
+ value: otlp
+ - name: OTEL_EXPORTER_OTLP_ENDPOINT
+ value: http://localhost:4318
+ - name: OTEL_EXPORTER_OTLP_TIMEOUT
+ value: "20000"
+ - name: OTEL_TRACES_SAMPLER
+ value: always_on
+ - name: SPLUNK_TRACE_RESPONSE_HEADER_ENABLED
+ value: "true"
+ - name: OTEL_METRICS_EXPORTER
+ value: otlp
+ exporter:
+ endpoint: http://localhost:4318
+ propagators:
+ - jaeger
+ - b3
+ nodejs:
+ env:
+ - name: OTEL_NODEJS_DEBUG
+ value: "true"
+ useImport: true
diff --git a/tests/e2e-instrumentation/instrumentation-nodejs-import/01-assert.yaml b/tests/e2e-instrumentation/instrumentation-nodejs-import/01-assert.yaml
new file mode 100644
index 0000000000..0b48de1338
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-nodejs-import/01-assert.yaml
@@ -0,0 +1,78 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ annotations:
+ instrumentation.opentelemetry.io/inject-nodejs: "true"
+ sidecar.opentelemetry.io/inject: "true"
+ labels:
+ app: my-nodejs
+spec:
+ containers:
+ - env:
+ - name: OTEL_NODE_IP
+ valueFrom:
+ fieldRef:
+ fieldPath: status.hostIP
+ - name: OTEL_POD_IP
+ valueFrom:
+ fieldRef:
+ fieldPath: status.podIP
+ - name: NODE_PATH
+ value: /usr/local/lib/node_modules
+ - name: OTEL_NODEJS_DEBUG
+ value: "true"
+ - name: NODE_OPTIONS
+ value: ' --import /otel-auto-instrumentation-nodejs/autoinstrumentation.js'
+ - name: OTEL_TRACES_EXPORTER
+ value: otlp
+ - name: OTEL_EXPORTER_OTLP_ENDPOINT
+ value: http://localhost:4318
+ - name: OTEL_EXPORTER_OTLP_TIMEOUT
+ value: "20000"
+ - name: OTEL_TRACES_SAMPLER
+ value: always_on
+ - name: SPLUNK_TRACE_RESPONSE_HEADER_ENABLED
+ value: "true"
+ - name: OTEL_METRICS_EXPORTER
+ value: otlp
+ - name: OTEL_SERVICE_NAME
+ value: my-nodejs
+ - name: OTEL_RESOURCE_ATTRIBUTES_POD_NAME
+ valueFrom:
+ fieldRef:
+ apiVersion: v1
+ fieldPath: metadata.name
+ - name: OTEL_RESOURCE_ATTRIBUTES_NODE_NAME
+ valueFrom:
+ fieldRef:
+ apiVersion: v1
+ fieldPath: spec.nodeName
+ - name: OTEL_PROPAGATORS
+ value: jaeger,b3
+ - name: OTEL_RESOURCE_ATTRIBUTES
+ name: myapp
+ ports:
+ - containerPort: 3000
+ protocol: TCP
+ volumeMounts:
+ - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
+ readOnly: true
+ - mountPath: /otel-auto-instrumentation-nodejs
+ name: opentelemetry-auto-instrumentation-nodejs
+ - args:
+ - --config=env:OTEL_CONFIG
+ name: otc-container
+ initContainers:
+ - name: opentelemetry-auto-instrumentation-nodejs
+status:
+ containerStatuses:
+ - name: myapp
+ ready: true
+ started: true
+ - name: otc-container
+ ready: true
+ started: true
+ initContainerStatuses:
+ - name: opentelemetry-auto-instrumentation-nodejs
+ ready: true
+ phase: Running
diff --git a/tests/e2e-instrumentation/instrumentation-nodejs-import/01-install-app.yaml b/tests/e2e-instrumentation/instrumentation-nodejs-import/01-install-app.yaml
new file mode 100644
index 0000000000..7efff21d2b
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-nodejs-import/01-install-app.yaml
@@ -0,0 +1,42 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: my-nodejs
+spec:
+ selector:
+ matchLabels:
+ app: my-nodejs
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: my-nodejs
+ annotations:
+ sidecar.opentelemetry.io/inject: "true"
+ instrumentation.opentelemetry.io/inject-nodejs: "true"
+ spec:
+ securityContext:
+ runAsUser: 1000
+ runAsGroup: 3000
+ fsGroup: 3000
+ containers:
+ - name: myapp
+ ports:
+ - containerPort: 3000
+ image: ghcr.io/open-telemetry/opentelemetry-operator/e2e-test-app-nodejs:main
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop: ["ALL"]
+ env:
+ - name: NODE_PATH
+ value: /usr/local/lib/node_modules
+ readinessProbe:
+ httpGet:
+ path: /rolldice
+ port: 3000
+ scheme: HTTP
+ initialDelaySeconds: 5
+ periodSeconds: 15
+ timeoutSeconds: 2
+ failureThreshold: 3
\ No newline at end of file
diff --git a/tests/e2e-instrumentation/instrumentation-nodejs-import/chainsaw-test.yaml b/tests/e2e-instrumentation/instrumentation-nodejs-import/chainsaw-test.yaml
new file mode 100755
index 0000000000..f6c57b64b2
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-nodejs-import/chainsaw-test.yaml
@@ -0,0 +1,120 @@
+# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json
+apiVersion: chainsaw.kyverno.io/v1alpha1
+kind: Test
+metadata:
+ creationTimestamp: null
+ name: instrumentation-nodejs-import
+spec:
+ steps:
+ - name: step-00
+ try:
+ # In OpenShift, when a namespace is created, all necessary SCC annotations are automatically added. However, if a namespace is created using a resource file with only selected SCCs, the other auto-added SCCs are not included. Therefore, the UID-range and supplemental groups SCC annotations must be set after the namespace is created.
+ - command:
+ entrypoint: kubectl
+ args:
+ - annotate
+ - namespace
+ - ${NAMESPACE}
+ - openshift.io/sa.scc.uid-range=1000/1000
+ - --overwrite
+ - command:
+ entrypoint: kubectl
+ args:
+ - annotate
+ - namespace
+ - ${NAMESPACE}
+ - openshift.io/sa.scc.supplemental-groups=3000/3000
+ - --overwrite
+ - apply:
+ file: 00-install-collector.yaml
+ - apply:
+ file: 00-install-instrumentation.yaml
+ - name: step-01
+ try:
+ - apply:
+ file: 01-install-app.yaml
+ - assert:
+ file: 01-assert.yaml
+ catch:
+ - podLogs:
+ selector: app=my-nodejs
+ - name: Make a request to the app
+ try:
+ - command:
+ entrypoint: kubectl
+ args:
+ - get
+ - pod
+ - -n
+ - ${NAMESPACE}
+ - -l
+ - app=my-nodejs
+ - -o
+ - jsonpath={.items[0].metadata.name}
+ outputs:
+ - name: podName
+ value: ($stdout)
+ - proxy:
+ apiVersion: v1
+ kind: Pod
+ name: ($podName)
+ namespace: ${NAMESPACE}
+ port: "3000"
+ path: /rolldice
+ - name: Wait for telemetry data
+ try:
+ - script:
+ env:
+ - name: LABEL_SELECTOR
+ value: "app=my-nodejs"
+ - name: CONTAINER_NAME
+ value: "otc-container"
+ - name: RETRY_TIMEOUT
+ value: "120"
+ - name: RETRY_SLEEP
+ value: "5"
+ - name: SEARCH_STRINGS_ENV
+ value: |
+ Name: http.server.duration
+ Description: Measures the duration of inbound HTTP requests
+ timeout: 2m
+ content: ../../test-e2e-apps/scripts/check_pod_logs.sh
+ - name: Check the instrumented app has sent the telemetry data successfully
+ try:
+ - command:
+ entrypoint: kubectl
+ args:
+ - get
+ - pod
+ - -n
+ - ${NAMESPACE}
+ - -l
+ - app=my-nodejs
+ - -o
+ - jsonpath={.items[0].metadata.name}
+ outputs:
+ - name: podName
+ value: ($stdout)
+ - script:
+ env:
+ - name: podName
+ value: ($podName)
+ content: |
+ #!/bin/bash
+ # set -ex
+ kubectl get --raw /api/v1/namespaces/$NAMESPACE/pods/${podName}:8888/proxy/metrics
+ outputs:
+ - name: metrics
+ value: (x_metrics_decode($stdout))
+ check:
+ ($error == null): true
+ - assert:
+ resource:
+ ($metrics[?as_string(metric."__name__") == 'otelcol_exporter_sent_spans_total'].value | [0] > `1`): true
+ ($metrics[?as_string(metric."__name__") == 'otelcol_receiver_accepted_spans_total'].value | [0] > `1`): true
+ ($metrics[?as_string(metric."__name__") == 'otelcol_exporter_sent_metric_points_total'].value | [0] > `1`): true
+ ($metrics[?as_string(metric."__name__") == 'otelcol_receiver_accepted_metric_points_total'].value | [0] > `1`): true
+ catch:
+ - podLogs:
+ selector: app=my-nodejs
+ container: otc-container
\ No newline at end of file