Skip to content

Commit 1ee2476

Browse files
maryliagpichlermarc
authored andcommitted
feat(sdk-node): add serviceInstanceIdDetector to NodeSDK (open-telemetry#4626)
* feat(sdk-node): add serviceInstanceIDDetector to NodeSDK Follow up from open-telemetry#4608 Adds the resource detector ServiceInstanceIDDetector on the NodeSDK constructor. It only gets added by default on any of those conditions: - the value `serviceinstance` is part of the list `OTEL_NODE_RESOURCE_DETECTORS` - `OTEL_NODE_EXPERIMENTAL_DEFAULT_SERVICE_INSTANCE_ID` is set to `true` * remove OTEL_NODE_EXPERIMENTAL_DEFAULT_SERVICE_INSTANCE_ID Signed-off-by: maryliag <[email protected]> * update readme on how to use `OTEL_NODE_RESOURCE_DETECTORS` * feedback from review * Update experimental/packages/opentelemetry-sdk-node/README.md Co-authored-by: Marc Pichler <[email protected]> * feedback from review --------- Signed-off-by: maryliag <[email protected]> Co-authored-by: Marc Pichler <[email protected]>
1 parent b3bce45 commit 1ee2476

File tree

10 files changed

+121
-24
lines changed

10 files changed

+121
-24
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/
1313

1414
* feat(sdk-trace-base): log resource attributes in ConsoleSpanExporter [#4605](https://github.com/open-telemetry/opentelemetry-js/pull/4605) @pichlermarc
1515
* feat(propagator-aws-xray): moved AWS Xray propagator from contrib [4603](https://github.com/open-telemetry/opentelemetry-js/pull/4603) @martinkuba
16-
* feat(resources): new experimental detector ServiceInstanceIdDetectorSync that sets the value for `service.instance.id` as random UUID.
16+
* feat(resources): new experimental detector ServiceInstanceIdDetectorSync that sets the value for `service.instance.id` as random UUID. [#4608](https://github.com/open-telemetry/opentelemetry-js/pull/4608) @maryliag
1717

1818
### :bug: (Bug Fix)
1919

experimental/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ All notable changes to experimental packages in this project will be documented
1818
* refactor(instrumentation-grpc): move to use SEMATTRS [#4633](https://github.com/open-telemetry/opentelemetry-js/pull/4633)
1919
* feat(otlp-transformer): consolidate scope/resource creation in transformer [#4600](https://github.com/open-telemetry/opentelemetry-js/pull/4600)
2020
* feat(sdk-logs): print message when attributes are dropped due to attribute count limit [#4614](https://github.com/open-telemetry/opentelemetry-js/pull/4614) @HyunnoH
21+
* feat(sdk-node): add usage for the detector ServiceInstanceIdDetectorSync. [#4626](https://github.com/open-telemetry/opentelemetry-js/pull/4626) @maryliag
22+
* The resource detector can be added to default resource detector list by adding the value `serviceinstance` to the list of resource detectors on the environment variable `OTEL_NODE_RESOURCE_DETECTORS`, e.g `OTEL_NODE_RESOURCE_DETECTORS=env,host,os,serviceinstance`
23+
* The value can be overwritten by
24+
* merging a resource containing the `service.instance.id` attribute
25+
* using another resource detector which writes `service.instance.id`
2126

2227
### :bug: (Bug Fix)
2328

experimental/packages/opentelemetry-sdk-node/README.md

+18-1
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,26 @@ Configure a resource. Resources may also be detected by using the `autoDetectRes
115115

116116
### resourceDetectors
117117

118-
Configure resource detectors. By default, the resource detectors are [envDetector, processDetector].
118+
Configure resource detectors. By default, the resource detectors are [envDetector, processDetector, hostDetector].
119119
NOTE: In order to enable the detection, the parameter `autoDetectResources` has to be `true`.
120120

121+
If `resourceDetectors` was not set, you can also use the environment variable `OTEL_NODE_RESOURCE_DETECTORS` to enable only certain detectors, or completely disable them:
122+
123+
- `env`
124+
- `host`
125+
- `os`
126+
- `process`
127+
- `serviceinstance` (experimental)
128+
- `all` - enable all resource detectors above
129+
- **NOTE:** future versions of `@opentelemetry/sdk-node` may include additional detectors that will be covered by this scope.
130+
- `none` - disable resource detection
131+
132+
For example, to enable only the `env`, `host` detectors:
133+
134+
```shell
135+
export OTEL_NODE_RESOURCE_DETECTORS="env,host"
136+
```
137+
121138
### sampler
122139

123140
Configure a custom sampler. By default, all traces will be sampled.

experimental/packages/opentelemetry-sdk-node/src/sdk.ts

+14-6
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
5151
import { NodeSDKConfiguration } from './types';
5252
import { TracerProviderWithEnvExporters } from './TracerProviderWithEnvExporter';
5353
import { getEnv, getEnvWithoutDefaults } from '@opentelemetry/core';
54-
import { parseInstrumentationOptions } from './utils';
54+
import {
55+
getResourceDetectorsFromEnv,
56+
parseInstrumentationOptions,
57+
} from './utils';
5558

5659
/** This class represents everything needed to register a fully configured OpenTelemetry Node.js SDK */
5760

@@ -121,11 +124,15 @@ export class NodeSDK {
121124
this._configuration = configuration;
122125

123126
this._resource = configuration.resource ?? new Resource({});
124-
this._resourceDetectors = configuration.resourceDetectors ?? [
125-
envDetector,
126-
processDetector,
127-
hostDetector,
128-
];
127+
let defaultDetectors: (Detector | DetectorSync)[] = [];
128+
if (process.env.OTEL_NODE_RESOURCE_DETECTORS != null) {
129+
defaultDetectors = getResourceDetectorsFromEnv();
130+
} else {
131+
defaultDetectors = [envDetector, processDetector, hostDetector];
132+
}
133+
134+
this._resourceDetectors =
135+
configuration.resourceDetectors ?? defaultDetectors;
129136

130137
this._serviceName = configuration.serviceName;
131138

@@ -157,6 +164,7 @@ export class NodeSDK {
157164

158165
const spanProcessor =
159166
configuration.spanProcessor ??
167+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
160168
new BatchSpanProcessor(configuration.traceExporter!);
161169

162170
const spanProcessors = configuration.spanProcessors ?? [spanProcessor];

experimental/packages/opentelemetry-sdk-node/src/utils.ts

+47
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,19 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { diag } from '@opentelemetry/api';
1718
import {
1819
Instrumentation,
1920
InstrumentationOption,
2021
} from '@opentelemetry/instrumentation';
22+
import {
23+
DetectorSync,
24+
envDetectorSync,
25+
hostDetectorSync,
26+
osDetectorSync,
27+
processDetectorSync,
28+
serviceInstanceIdDetectorSync,
29+
} from '@opentelemetry/resources';
2130

2231
// TODO: This part of a workaround to fix https://github.com/open-telemetry/opentelemetry-js/issues/3609
2332
// If the MeterProvider is not yet registered when instrumentations are registered, all metrics are dropped.
@@ -41,3 +50,41 @@ export function parseInstrumentationOptions(
4150

4251
return instrumentations;
4352
}
53+
54+
const RESOURCE_DETECTOR_ENVIRONMENT = 'env';
55+
const RESOURCE_DETECTOR_HOST = 'host';
56+
const RESOURCE_DETECTOR_OS = 'os';
57+
const RESOURCE_DETECTOR_PROCESS = 'process';
58+
const RESOURCE_DETECTOR_SERVICE_INSTANCE_ID = 'serviceinstance';
59+
60+
export function getResourceDetectorsFromEnv(): Array<DetectorSync> {
61+
// When updating this list, make sure to also update the section `resourceDetectors` on README.
62+
const resourceDetectors = new Map<string, DetectorSync>([
63+
[RESOURCE_DETECTOR_ENVIRONMENT, envDetectorSync],
64+
[RESOURCE_DETECTOR_HOST, hostDetectorSync],
65+
[RESOURCE_DETECTOR_OS, osDetectorSync],
66+
[RESOURCE_DETECTOR_SERVICE_INSTANCE_ID, serviceInstanceIdDetectorSync],
67+
[RESOURCE_DETECTOR_PROCESS, processDetectorSync],
68+
]);
69+
70+
const resourceDetectorsFromEnv =
71+
process.env.OTEL_NODE_RESOURCE_DETECTORS?.split(',') ?? ['all'];
72+
73+
if (resourceDetectorsFromEnv.includes('all')) {
74+
return [...resourceDetectors.values()].flat();
75+
}
76+
77+
if (resourceDetectorsFromEnv.includes('none')) {
78+
return [];
79+
}
80+
81+
return resourceDetectorsFromEnv.flatMap(detector => {
82+
const resourceDetector = resourceDetectors.get(detector);
83+
if (!resourceDetector) {
84+
diag.error(
85+
`Invalid resource detector "${detector}" specified in the environment variable OTEL_NODE_RESOURCE_DETECTORS`
86+
);
87+
}
88+
return resourceDetector || [];
89+
});
90+
}

experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts

+20-12
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ import {
3939
View,
4040
} from '@opentelemetry/sdk-metrics';
4141
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
42-
import { assertServiceResource } from './util/resource-assertions';
42+
import {
43+
assertServiceInstanceIdIsUUID,
44+
assertServiceResource,
45+
} from './util/resource-assertions';
4346
import {
4447
ConsoleSpanExporter,
4548
SimpleSpanProcessor,
@@ -71,7 +74,6 @@ import {
7174
import {
7275
SEMRESATTRS_HOST_NAME,
7376
SEMRESATTRS_PROCESS_PID,
74-
SEMRESATTRS_SERVICE_INSTANCE_ID,
7577
} from '@opentelemetry/semantic-conventions';
7678

7779
const DefaultContextManager = semver.gte(process.version, '14.8.0')
@@ -682,7 +684,7 @@ describe('Node SDK', () => {
682684
describe('configureServiceInstanceId', async () => {
683685
it('should configure service instance id via OTEL_RESOURCE_ATTRIBUTES env var', async () => {
684686
process.env.OTEL_RESOURCE_ATTRIBUTES =
685-
'service.instance.id=627cc493,service.name=my-service';
687+
'service.instance.id=627cc493,service.name=my-service,service.namespace';
686688
const sdk = new NodeSDK();
687689

688690
sdk.start();
@@ -694,7 +696,20 @@ describe('Node SDK', () => {
694696
instanceId: '627cc493',
695697
});
696698
delete process.env.OTEL_RESOURCE_ATTRIBUTES;
697-
sdk.shutdown();
699+
await sdk.shutdown();
700+
});
701+
702+
it('should configure service instance id via OTEL_NODE_RESOURCE_DETECTORS env var', async () => {
703+
process.env.OTEL_NODE_RESOURCE_DETECTORS = 'env,host,os,serviceinstance';
704+
const sdk = new NodeSDK();
705+
706+
sdk.start();
707+
const resource = sdk['_resource'];
708+
await resource.waitForAsyncAttributes?.();
709+
710+
assertServiceInstanceIdIsUUID(resource);
711+
delete process.env.OTEL_NODE_RESOURCE_DETECTORS;
712+
await sdk.shutdown();
698713
});
699714

700715
it('should configure service instance id with random UUID', async () => {
@@ -712,14 +727,7 @@ describe('Node SDK', () => {
712727
const resource = sdk['_resource'];
713728
await resource.waitForAsyncAttributes?.();
714729

715-
const UUID_REGEX =
716-
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
717-
assert.equal(
718-
UUID_REGEX.test(
719-
resource.attributes[SEMRESATTRS_SERVICE_INSTANCE_ID]?.toString() || ''
720-
),
721-
true
722-
);
730+
assertServiceInstanceIdIsUUID(resource);
723731
await sdk.shutdown();
724732
});
725733
});

experimental/packages/opentelemetry-sdk-node/test/util/resource-assertions.ts

+12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { SDK_INFO } from '@opentelemetry/core';
1818
import * as assert from 'assert';
1919
import { IResource, Resource } from '@opentelemetry/resources';
2020
import {
21+
SEMRESATTRS_SERVICE_INSTANCE_ID,
2122
SEMRESATTRS_TELEMETRY_SDK_LANGUAGE,
2223
SEMRESATTRS_TELEMETRY_SDK_NAME,
2324
SEMRESATTRS_TELEMETRY_SDK_VERSION,
@@ -336,3 +337,14 @@ const assertHasOneLabel = (prefix: string, resource: Resource): void => {
336337
JSON.stringify(Object.keys(SemanticResourceAttributes))
337338
);
338339
};
340+
341+
export const assertServiceInstanceIdIsUUID = (resource: Resource): void => {
342+
const UUID_REGEX =
343+
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
344+
assert.equal(
345+
UUID_REGEX.test(
346+
resource.attributes[SEMRESATTRS_SERVICE_INSTANCE_ID]?.toString() || ''
347+
),
348+
true
349+
);
350+
};

packages/opentelemetry-resources/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ npm install --save @opentelemetry/resources
1616
## Usage
1717

1818
```typescript
19-
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
19+
import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
2020
import { Resource } from '@opentelemetry/resources';
2121

2222
const resource = new Resource({
23-
[SemanticResourceAttributes.SERVICE_NAME]: 'api-service',
23+
[SEMRESATTRS_SERVICE_NAME]: 'api-service',
2424
});
2525

2626
const anotherResource = new Resource({

packages/opentelemetry-resources/src/platform/browser/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
export * from './default-service-name';
1818
export * from './HostDetector';
19-
export * from './OSDetector';
2019
export * from './HostDetectorSync';
20+
export * from './OSDetector';
2121
export * from './OSDetectorSync';
2222
export * from './ProcessDetector';
2323
export * from './ProcessDetectorSync';

packages/opentelemetry-resources/src/platform/node/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
export * from './default-service-name';
1818
export * from './HostDetector';
19-
export * from './OSDetector';
2019
export * from './HostDetectorSync';
20+
export * from './OSDetector';
2121
export * from './OSDetectorSync';
2222
export * from './ProcessDetector';
2323
export * from './ProcessDetectorSync';

0 commit comments

Comments
 (0)