Skip to content

Commit 2d8e2b8

Browse files
authored
feat(auto-instrumentations-node): Add "@opentelemetry/auto-instrumentations-node/register" for an agent-like experience (open-telemetry#1400)
* feat(auto-instrumentation-agent): added intrumentation-agent package * feat(auto-instrumentation-agent): added api peer dependency * feat(auto-instrumentation-agent): updated test * feat(auto-instrumentation-agent): updated release please config * feat(auto-instrumentation-agent): updated .release-please-manifest * feat(auto-instrumentation-agent): updated test timeout * feat(auto-instrumentation-agent): removed timeout, added pretest script * feat(auto-instrumentation-agent): moved agent to auto-instrumentations-node * feat(auto-instrumentation-agent): reverted release please config * feat(auto-instrumentation-agent): updated README.md * feat(auto-instrumentation-agent): added env variable for resource detector configuration * feat(auto-instrumentation-agent): removed no-process-exit * feat(auto-instrumentation-agent): removed pretest script * feat(auto-instrumentation-agent): fixed lint issues * feat(auto-instrumentation-agent): updated register test * feat(auto-instrumentation-agent): fixed typo in test * feat(auto-instrumentation-agent): using env instead of export * feat(auto-instrumentation-agent): updated eslint.config.js * feat(auto-instrumentation-agent): updated test * feat(auto-instrumentation-agent): using language specific env var name * feat(auto-instrumentation-agent): updated README.md * feat(auto-instrumentation-agent): updated dependencies * feat(auto-instrumentation-agent): fixed detector test * feat(auto-instrumentation-agent): added comment to test app * feat(auto-instrumentation-agent): small refactor * feat(auto-instrumentation-agent): updated log messages * feat(auto-instrumentation-agent): added missing aws detectors * feat(auto-instrumentation-agent): updated tests * feat(auto-instrumentation-agent): updated getResourceDetectorsFromEnv() * feat(auto-instrumentation-agent): revert unnecessary changes * feat(auto-instrumentation-agent): added reference to supported instrumentations * feat(auto-instrumentation-agent): added reference to env var spec * feat(auto-instrumentation-agent): added reference node documentation * feat(auto-instrumentation-agent): added note for unsupported config * feat(auto-instrumentation-agent): added note to the debug section * feat(auto-instrumentation-agent): moved opentelemetry/api to regular dependency * feat(auto-instrumentation-agent): fixed lint issue * feat(auto-instrumentation-agent): re-added peer dep * feat(auto-instrumentation-agent): re-added api dev dep * feat(auto-instrumentation-agent): fixed lint issue * feat(auto-instrumentation-agent): fixed lint issue * feat(auto-instrumentation-agent): updated README.md * feat(auto-instrumentation-agent): added exporters reference in README.md * feat(auto-instrumentation-agent): updated debug notes * feat(auto-instrumentation-agent): updated installation section to include the api dependency * feat(auto-instrumentation-agent): reordered aws resource detectors * feat(auto-instrumentation-agent): removed process.exit(0) * feat(auto-instrumentation-agent): reordered aws resource detectors * feat(auto-instrumentation-agent): replaced type any with actual types * feat(auto-instrumentation-agent): updated utils test * feat(auto-instrumentation-agent): updated register test * feat(auto-instrumentation-agent): updated README.md * feat(auto-instrumentation-agent): updated shutdown logs * feat(auto-instrumentation-agent): fixed sinon issue
1 parent b5b951e commit 2d8e2b8

File tree

7 files changed

+343
-5
lines changed

7 files changed

+343
-5
lines changed

metapackages/auto-instrumentations-node/README.md

+85-2
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,97 @@
33
[![NPM Published Version][npm-img]][npm-url]
44
[![Apache License][license-image]][license-url]
55

6-
This module provides a simple way to initialize multiple Node instrumentations.
6+
## About
7+
8+
This module provides a way to auto instrument any Node application to capture telemetry from a number of popular libraries and frameworks.
9+
You can export the telemetry data in a variety of formats. Exporters, samplers, and more can be configured via [environment variables][env-var-url].
10+
The net result is the ability to gather telemetry data from a Node application without any code changes.
11+
12+
This module also provides a simple way to manually initialize multiple Node instrumentations for use with the OpenTelemetry SDK.
713

814
Compatible with OpenTelemetry JS API and SDK `1.0+`.
915

1016
## Installation
1117

1218
```bash
19+
npm install --save @opentelemetry/api
1320
npm install --save @opentelemetry/auto-instrumentations-node
1421
```
1522

16-
## Usage
23+
## Usage: Auto Instrumentation
24+
25+
This module includes auto instrumentation for all supported instrumentations and [all available data exporters][exporter-url].
26+
It provides a completely automatic, out-of-the-box experience.
27+
Please see the [Supported Instrumentations](#supported-instrumentations) section for more information.
28+
29+
Enable auto instrumentation by requiring this module using the [--require flag][require-url]:
30+
31+
```shell
32+
node --require '@opentelemetry/auto-instrumentations-node/register' app.js
33+
```
34+
35+
If your Node application is encapsulated in a complex run script, you can also set it via an environment variable before running Node.
36+
37+
```shell
38+
env NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register"
39+
```
40+
41+
The module is highly configurable using environment variables.
42+
Many aspects of the auto instrumentation's behavior can be configured for your needs, such as resource detectors, exporter choice, exporter configuration, trace context propagation headers, and much more.
43+
Instrumentation configuration is not yet supported through environment variables. Users that require instrumentation configuration must initialize OpenTelemetry programmatically.
44+
45+
```shell
46+
export OTEL_TRACES_EXPORTER="otlp"
47+
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
48+
export OTEL_EXPORTER_OTLP_COMPRESSION="gzip"
49+
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://your-endpoint"
50+
export OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your-api-key"
51+
export OTEL_EXPORTER_OTLP_TRACES_HEADERS="x-api-key=your-api-key"
52+
export OTEL_RESOURCE_ATTRIBUTES="service.namespace=my-namespace"
53+
export OTEL_NODE_RESOURCE_DETECTORS="env,host,os"
54+
export OTEL_SERVICE_NAME="client"
55+
export NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register"
56+
node app.js
57+
```
58+
59+
By default, all SDK resource detectors are used, but you can use the environment variable OTEL_NODE_RESOURCE_DETECTORS to enable only certain detectors, or completely disable them:
60+
61+
- `env`
62+
- `host`
63+
- `os`
64+
- `process`
65+
- `container`
66+
- `alibaba`
67+
- `aws`
68+
- `gcp`
69+
- `all` - enable all resource detectors
70+
- `none` - disable resource detection
71+
72+
For example, to enable only the `env`, `host` detectors:
73+
74+
```shell
75+
export OTEL_NODE_RESOURCE_DETECTORS="env,host"
76+
```
77+
78+
To enable logging for troubleshooting, set the log level by setting the `OTEL_LOG_LEVEL` environment variable to one of the following:
79+
80+
- `none`
81+
- `error`
82+
- `warn`
83+
- `info`
84+
- `debug`
85+
- `verbose`
86+
- `all`
87+
88+
The default level is `info`.
89+
90+
Notes:
91+
92+
- In a production environment, it is recommended to set `OTEL_LOG_LEVEL`to `info`.
93+
- Logs are always sent to console, no matter the environment, or debug level.
94+
- Debug logs are extremely verbose. Enable debug logging only when needed. Debug logging negatively impacts the performance of your application.
95+
96+
## Usage: Instrumentation Initialization
1797

1898
OpenTelemetry Meta Packages for Node automatically loads instrumentations for Node builtin modules and common packages.
1999

@@ -100,3 +180,6 @@ APACHE 2.0 - See [LICENSE][license-url] for more information.
100180
[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
101181
[npm-url]: https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node
102182
[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fauto-instrumentations-node.svg
183+
[env-var-url]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#general-sdk-configuration
184+
[exporter-url]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#otlp-exporter
185+
[require-url]: https://nodejs.org/api/cli.html#-r---require-module

metapackages/auto-instrumentations-node/package.json

+13-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
},
1414
"main": "build/src/index.js",
1515
"types": "build/src/index.d.ts",
16+
"exports": {
17+
".": "./build/src/index.js",
18+
"./register": "./build/src/register.js"
19+
},
1620
"repository": "open-telemetry/opentelemetry-js-contrib",
1721
"scripts": {
1822
"clean": "rimraf build/*",
@@ -30,10 +34,10 @@
3034
"url": "https://github.com/open-telemetry/opentelemetry-js-contrib/issues"
3135
},
3236
"peerDependencies": {
33-
"@opentelemetry/api": "^1.3.0"
37+
"@opentelemetry/api": "^1.4.1"
3438
},
3539
"devDependencies": {
36-
"@opentelemetry/api": "^1.3.0",
40+
"@opentelemetry/api": "^1.4.1",
3741
"@types/mocha": "7.0.2",
3842
"@types/node": "18.11.7",
3943
"@types/sinon": "10.0.2",
@@ -82,6 +86,12 @@
8286
"@opentelemetry/instrumentation-router": "^0.32.2",
8387
"@opentelemetry/instrumentation-socket.io": "^0.33.2",
8488
"@opentelemetry/instrumentation-tedious": "^0.5.2",
85-
"@opentelemetry/instrumentation-winston": "^0.31.2"
89+
"@opentelemetry/instrumentation-winston": "^0.31.2",
90+
"@opentelemetry/resource-detector-alibaba-cloud": "^0.27.4",
91+
"@opentelemetry/resource-detector-aws": "^1.2.2",
92+
"@opentelemetry/resource-detector-container": "^0.2.2",
93+
"@opentelemetry/resource-detector-gcp": "^0.28.0",
94+
"@opentelemetry/resources": "^1.12.0",
95+
"@opentelemetry/sdk-node": "^0.38.0"
8696
}
8797
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import * as opentelemetry from '@opentelemetry/sdk-node';
17+
import { diag, DiagConsoleLogger } from '@opentelemetry/api';
18+
import {
19+
getNodeAutoInstrumentations,
20+
getResourceDetectorsFromEnv,
21+
} from './utils';
22+
23+
diag.setLogger(
24+
new DiagConsoleLogger(),
25+
opentelemetry.core.getEnv().OTEL_LOG_LEVEL
26+
);
27+
28+
const sdk = new opentelemetry.NodeSDK({
29+
instrumentations: getNodeAutoInstrumentations(),
30+
resourceDetectors: getResourceDetectorsFromEnv(),
31+
});
32+
33+
try {
34+
sdk.start();
35+
diag.info('OpenTelemetry automatic instrumentation started successfully');
36+
} catch (error) {
37+
diag.error(
38+
'Error initializing OpenTelemetry SDK. Your application is not instrumented and will not produce telemetry',
39+
error
40+
);
41+
}
42+
43+
process.on('SIGTERM', () => {
44+
sdk
45+
.shutdown()
46+
.then(() => diag.debug('OpenTelemetry SDK terminated'))
47+
.catch(error => diag.error('Error terminating OpenTelemetry SDK', error));
48+
});

metapackages/auto-instrumentations-node/src/utils.ts

+74
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,34 @@ import { SocketIoInstrumentation } from '@opentelemetry/instrumentation-socket.i
5454
import { TediousInstrumentation } from '@opentelemetry/instrumentation-tedious';
5555
import { WinstonInstrumentation } from '@opentelemetry/instrumentation-winston';
5656

57+
import { alibabaCloudEcsDetector } from '@opentelemetry/resource-detector-alibaba-cloud';
58+
import {
59+
awsBeanstalkDetector,
60+
awsEc2Detector,
61+
awsEcsDetector,
62+
awsEksDetector,
63+
awsLambdaDetector,
64+
} from '@opentelemetry/resource-detector-aws';
65+
import { containerDetector } from '@opentelemetry/resource-detector-container';
66+
import { gcpDetector } from '@opentelemetry/resource-detector-gcp';
67+
import {
68+
Detector,
69+
DetectorSync,
70+
envDetectorSync,
71+
hostDetectorSync,
72+
osDetectorSync,
73+
processDetectorSync,
74+
} from '@opentelemetry/resources';
75+
76+
const RESOURCE_DETECTOR_CONTAINER = 'container';
77+
const RESOURCE_DETECTOR_ENVIRONMENT = 'env';
78+
const RESOURCE_DETECTOR_HOST = 'host';
79+
const RESOURCE_DETECTOR_OS = 'os';
80+
const RESOURCE_DETECTOR_PROCESS = 'process';
81+
const RESOURCE_DETECTOR_ALIBABA = 'alibaba';
82+
const RESOURCE_DETECTOR_AWS = 'aws';
83+
const RESOURCE_DETECTOR_GCP = 'gcp';
84+
5785
const InstrumentationMap = {
5886
'@opentelemetry/instrumentation-amqplib': AmqplibInstrumentation,
5987
'@opentelemetry/instrumentation-aws-lambda': AwsLambdaInstrumentation,
@@ -136,3 +164,49 @@ export function getNodeAutoInstrumentations(
136164

137165
return instrumentations;
138166
}
167+
168+
export function getResourceDetectorsFromEnv(): Array<Detector | DetectorSync> {
169+
const resourceDetectors = new Map<
170+
string,
171+
Detector | DetectorSync | Detector[]
172+
>([
173+
[RESOURCE_DETECTOR_CONTAINER, containerDetector],
174+
[RESOURCE_DETECTOR_ENVIRONMENT, envDetectorSync],
175+
[RESOURCE_DETECTOR_HOST, hostDetectorSync],
176+
[RESOURCE_DETECTOR_OS, osDetectorSync],
177+
[RESOURCE_DETECTOR_PROCESS, processDetectorSync],
178+
[RESOURCE_DETECTOR_ALIBABA, alibabaCloudEcsDetector],
179+
[RESOURCE_DETECTOR_GCP, gcpDetector],
180+
[
181+
RESOURCE_DETECTOR_AWS,
182+
[
183+
awsEc2Detector,
184+
awsEcsDetector,
185+
awsEksDetector,
186+
awsBeanstalkDetector,
187+
awsLambdaDetector,
188+
],
189+
],
190+
]);
191+
192+
const resourceDetectorsFromEnv =
193+
process.env.OTEL_NODE_RESOURCE_DETECTORS?.split(',') ?? ['all'];
194+
195+
if (resourceDetectorsFromEnv.includes('all')) {
196+
return [...resourceDetectors.values()].flat();
197+
}
198+
199+
if (resourceDetectorsFromEnv.includes('none')) {
200+
return [];
201+
}
202+
203+
return resourceDetectorsFromEnv.flatMap(detector => {
204+
const resourceDetector = resourceDetectors.get(detector);
205+
if (!resourceDetector) {
206+
diag.error(
207+
`Invalid resource detector "${detector}" specified in the environment variable OTEL_NODE_RESOURCE_DETECTORS`
208+
);
209+
}
210+
return resourceDetector || [];
211+
});
212+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import { promisify } from 'util';
17+
import * as childProcess from 'child_process';
18+
import * as assert from 'assert';
19+
20+
const exec = promisify(childProcess.exec);
21+
22+
describe('Register', function () {
23+
this.timeout(5000);
24+
it('can load auto instrumentation from command line', async () => {
25+
process.env.OTEL_NODE_RESOURCE_DETECTORS = 'none';
26+
process.env.OTEL_TRACES_EXPORTER = 'console';
27+
28+
const { stdout } = await exec(
29+
'node --require ./build/src/register.js ./test/test-app/app.js'
30+
);
31+
32+
assert.ok(
33+
stdout.includes(
34+
'OpenTelemetry automatic instrumentation started successfully'
35+
)
36+
);
37+
38+
//Check a span has been generated for the GET request done in app.js
39+
assert.ok(stdout.includes("name: 'GET'"));
40+
41+
delete process.env.OTEL_NODE_RESOURCE_DETECTORS;
42+
delete process.env.OTEL_TRACES_EXPORTER;
43+
});
44+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
//Used in register.test.ts to mimic a JS app.
18+
const http = require('http');
19+
20+
const options = {
21+
hostname: 'example.com',
22+
port: 80,
23+
path: '/',
24+
method: 'GET'
25+
};
26+
27+
const req = http.request(options);
28+
29+
req.end();

0 commit comments

Comments
 (0)